mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 22:28:15 +00:00
fix: yaml secret file parsing (#3837)
This commit is contained in:
@@ -77,3 +77,91 @@ export const parseJson = (src: ArrayBuffer | string) => {
|
|||||||
});
|
});
|
||||||
return env;
|
return env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses simple flat YAML with support for multiline strings using |, |-, and >.
|
||||||
|
* @param {ArrayBuffer | string} src
|
||||||
|
* @returns {Record<string, { value: string, comments: string[] }>}
|
||||||
|
*/
|
||||||
|
export function parseYaml(src: ArrayBuffer | string) {
|
||||||
|
const result: Record<string, { value: string; comments: string[] }> = {};
|
||||||
|
|
||||||
|
const content = src.toString().replace(/\r\n?/g, "\n");
|
||||||
|
const lines = content.split("\n");
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
let comments: string[] = [];
|
||||||
|
|
||||||
|
while (i < lines.length) {
|
||||||
|
const line = lines[i].trim();
|
||||||
|
|
||||||
|
// Collect comment
|
||||||
|
if (line.startsWith("#")) {
|
||||||
|
comments.push(line.slice(1).trim());
|
||||||
|
i += 1; // move to next line
|
||||||
|
} else {
|
||||||
|
// Match key: value or key: |, key: >, etc.
|
||||||
|
const keyMatch = lines[i].match(/^([\w.-]+)\s*:\s*(.*)$/);
|
||||||
|
if (keyMatch) {
|
||||||
|
const [, key, rawValue] = keyMatch;
|
||||||
|
let value = rawValue.trim();
|
||||||
|
|
||||||
|
// Multiline string handling
|
||||||
|
if (value === "|-" || value === "|" || value === ">") {
|
||||||
|
const isFolded = value === ">";
|
||||||
|
|
||||||
|
const baseIndent = lines[i + 1]?.match(/^(\s*)/)?.[1]?.length ?? 0;
|
||||||
|
const collectedLines: string[] = [];
|
||||||
|
|
||||||
|
i += 1; // move to first content line
|
||||||
|
|
||||||
|
while (i < lines.length) {
|
||||||
|
const current = lines[i];
|
||||||
|
const currentIndent = current.match(/^(\s*)/)?.[1]?.length ?? 0;
|
||||||
|
|
||||||
|
if (current.trim() === "" || currentIndent >= baseIndent) {
|
||||||
|
collectedLines.push(current.slice(baseIndent));
|
||||||
|
i += 1; // move to next line
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFolded) {
|
||||||
|
// Join lines with space for `>` folded style
|
||||||
|
value = collectedLines.map((l) => l.trim()).join(" ");
|
||||||
|
} else {
|
||||||
|
// Keep lines with newlines for `|` and `|-`
|
||||||
|
value = collectedLines.join("\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Inline value — strip quotes and inline comment
|
||||||
|
const commentIndex = value.indexOf(" #");
|
||||||
|
if (commentIndex !== -1) {
|
||||||
|
value = value.slice(0, commentIndex).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove surrounding quotes
|
||||||
|
if (
|
||||||
|
(value.startsWith('"') && value.endsWith('"')) ||
|
||||||
|
(value.startsWith("'") && value.endsWith("'"))
|
||||||
|
) {
|
||||||
|
value = value.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1; // advance to next line
|
||||||
|
}
|
||||||
|
|
||||||
|
result[key] = {
|
||||||
|
value,
|
||||||
|
comments: [...comments]
|
||||||
|
};
|
||||||
|
comments = []; // reset
|
||||||
|
} else {
|
||||||
|
i += 1; // skip unknown line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
+23
-8
@@ -9,7 +9,7 @@ import { twMerge } from "tailwind-merge";
|
|||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
// TODO:(akhilmhdh) convert all the util functions like this into a lib folder grouped by functionality
|
// TODO:(akhilmhdh) convert all the util functions like this into a lib folder grouped by functionality
|
||||||
import { parseDotEnv, parseJson } from "@app/components/utilities/parseSecrets";
|
import { parseDotEnv, parseJson, parseYaml } from "@app/components/utilities/parseSecrets";
|
||||||
import { Button, Lottie, Modal, ModalContent } from "@app/components/v2";
|
import { Button, Lottie, Modal, ModalContent } from "@app/components/v2";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||||
import { usePopUp, useToggle } from "@app/hooks";
|
import { usePopUp, useToggle } from "@app/hooks";
|
||||||
@@ -127,7 +127,7 @@ export const SecretDropzone = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseFile = (file?: File, isJson?: boolean) => {
|
const parseFile = (file?: File) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
if (!file) {
|
if (!file) {
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -140,10 +140,25 @@ export const SecretDropzone = ({
|
|||||||
setIsLoading.on();
|
setIsLoading.on();
|
||||||
reader.onload = (event) => {
|
reader.onload = (event) => {
|
||||||
if (!event?.target?.result) return;
|
if (!event?.target?.result) return;
|
||||||
// parse function's argument looks like to be ArrayBuffer
|
|
||||||
const env = isJson
|
let env: TParsedEnv;
|
||||||
? parseJson(event.target.result as ArrayBuffer)
|
|
||||||
: parseDotEnv(event.target.result as ArrayBuffer);
|
const src = event.target.result as ArrayBuffer;
|
||||||
|
|
||||||
|
switch (file.type) {
|
||||||
|
case "application/json":
|
||||||
|
env = parseJson(src);
|
||||||
|
break;
|
||||||
|
case "text/yaml":
|
||||||
|
case "application/x-yaml":
|
||||||
|
case "application/yaml":
|
||||||
|
env = parseYaml(src);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
env = parseDotEnv(src);
|
||||||
|
break;
|
||||||
|
}
|
||||||
setIsLoading.off();
|
setIsLoading.off();
|
||||||
handleParsedEnv(env);
|
handleParsedEnv(env);
|
||||||
};
|
};
|
||||||
@@ -165,12 +180,12 @@ export const SecretDropzone = ({
|
|||||||
|
|
||||||
e.dataTransfer.dropEffect = "copy";
|
e.dataTransfer.dropEffect = "copy";
|
||||||
setDragActive.off();
|
setDragActive.off();
|
||||||
parseFile(e.dataTransfer.files[0], e.dataTransfer.files[0].type === "application/json");
|
parseFile(e.dataTransfer.files[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileUpload = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleFileUpload = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
parseFile(e.target?.files?.[0], e.target?.files?.[0]?.type === "application/json");
|
parseFile(e.target?.files?.[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveSecrets = async () => {
|
const handleSaveSecrets = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user