check if folder/file name is valid
This commit is contained in:
parent
fccebb0594
commit
e9b9cd97ac
@ -28,6 +28,7 @@ import {
|
||||
} from "../../src/metadataOnRemote";
|
||||
import {
|
||||
atWhichLevel,
|
||||
checkValidName,
|
||||
getParentFolder,
|
||||
isHiddenPath,
|
||||
isSpecialFolderNameToSkip,
|
||||
@ -211,6 +212,13 @@ const ensembleMixedEnties = async (
|
||||
continue;
|
||||
}
|
||||
|
||||
const checkValidNameResult = checkValidName(key);
|
||||
if (!checkValidNameResult.result) {
|
||||
throw Error(
|
||||
`your remote folder/file name is invalid: ${checkValidNameResult.reason}`
|
||||
);
|
||||
}
|
||||
|
||||
finalMappings[key] = {
|
||||
key: key,
|
||||
remote: remoteCopied,
|
||||
@ -280,6 +288,13 @@ const ensembleMixedEnties = async (
|
||||
continue;
|
||||
}
|
||||
|
||||
const checkValidNameResult = checkValidName(key);
|
||||
if (!checkValidNameResult.result) {
|
||||
throw Error(
|
||||
`your local folder/file name is invalid: ${checkValidNameResult.reason}`
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: abstraction leaking?
|
||||
const localCopied = await fsEncrypt.encryptEntity(
|
||||
copyEntityAndFixTimeFormat(local, serviceType)
|
||||
@ -920,6 +935,8 @@ const getSyncPlanInplace = async (
|
||||
keptFolder.delete("/");
|
||||
keptFolder.delete("");
|
||||
if (keptFolder.size > 0) {
|
||||
console.error(sortedKeys);
|
||||
console.error(mixedEntityMappings);
|
||||
throw Error(`unexpectedly keptFolder no decisions: ${[...keptFolder]}`);
|
||||
}
|
||||
|
||||
|
||||
107
src/misc.ts
107
src/misc.ts
@ -742,3 +742,110 @@ export const getSha1 = async (x: ArrayBuffer, stringify: "base64" | "hex") => {
|
||||
}
|
||||
throw Error(`not supported stringify option = ${stringify}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
|
||||
* https://support.microsoft.com/en-us/office/restrictions-and-limitations-in-onedrive-and-sharepoint-64883a5d-228e-48f5-b3d2-eb39e07630fa#invalidcharacters
|
||||
*/
|
||||
export const checkValidName = (x: string) => {
|
||||
if (x === undefined || x === "") {
|
||||
// what??
|
||||
return {
|
||||
reason: "empty",
|
||||
result: false,
|
||||
};
|
||||
}
|
||||
|
||||
// The following reserved characters:
|
||||
const invalidChars = '*"<>:|?'.split("");
|
||||
for (const c of invalidChars) {
|
||||
if (x.includes(c)) {
|
||||
return {
|
||||
reason: `reserved character: ${c}`,
|
||||
result: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// directory component
|
||||
for (const c of [".", ".."]) {
|
||||
if (
|
||||
x === c ||
|
||||
x.endsWith(`/${c}`) ||
|
||||
x.startsWith(`${c}/`) ||
|
||||
x.includes(`/${c}/`)
|
||||
) {
|
||||
return {
|
||||
reason: `directory being ${c}`,
|
||||
result: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// reserved file names
|
||||
const reservedNames = [
|
||||
"CON",
|
||||
"PRN",
|
||||
"AUX",
|
||||
"NUL",
|
||||
"COM0",
|
||||
"COM1",
|
||||
"COM2",
|
||||
"COM3",
|
||||
"COM4",
|
||||
"COM5",
|
||||
"COM6",
|
||||
"COM7",
|
||||
"COM8",
|
||||
"COM9",
|
||||
"COM¹",
|
||||
"COM²",
|
||||
"COM³",
|
||||
"LPT0",
|
||||
"LPT1",
|
||||
"LPT2",
|
||||
"LPT3",
|
||||
"LPT4",
|
||||
"LPT5",
|
||||
"LPT6",
|
||||
"LPT7",
|
||||
"LPT8",
|
||||
"LPT9",
|
||||
"LPT¹",
|
||||
"LPT²",
|
||||
"LPT³",
|
||||
];
|
||||
for (const f of reservedNames) {
|
||||
if (
|
||||
x === f ||
|
||||
x.startsWith(`${f}.`) ||
|
||||
x.startsWith(`${f}/`) ||
|
||||
x.includes(`/${f}/`) ||
|
||||
x.endsWith(`/${f}`) ||
|
||||
x.includes(`/${f}.`)
|
||||
) {
|
||||
return {
|
||||
reason: `reserved folder/file name: ${f}`,
|
||||
result: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Do not end a file or directory name with a space or a period.
|
||||
if (
|
||||
x.endsWith(" ") ||
|
||||
x.endsWith(".") ||
|
||||
x.includes(" /") ||
|
||||
x.includes("./")
|
||||
) {
|
||||
return {
|
||||
reason: `folder/file name ending with a space or a period`,
|
||||
result: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
reason: "ok",
|
||||
result: true,
|
||||
};
|
||||
};
|
||||
|
||||
@ -363,6 +363,82 @@ describe("Misc: split chunk ranges", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Misc: check valid file names", () => {
|
||||
it("should be ok for normal file nmes", () => {
|
||||
let item = "what/.hidden/what/what/what";
|
||||
assert.ok(misc.checkValidName(item).result);
|
||||
|
||||
item = "ssss/%%%^^^$xxxx.md";
|
||||
assert.ok(misc.checkValidName(item).result);
|
||||
});
|
||||
|
||||
it("should be not ok for reserved characters", () => {
|
||||
let item = "a**";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "a?*";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "<>:";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "<>:/ssss";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
});
|
||||
|
||||
it("should be not ok for reserved names", () => {
|
||||
let item = "CON";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "CON.txt";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "CON.md";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "con"; // lower case is ok
|
||||
assert.ok(misc.checkValidName(item).result);
|
||||
|
||||
item = "CON/";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "CON.dir/";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "CON.dir.folder/";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx/CON";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx/CON.txt";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx/CON.txt.md";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
});
|
||||
|
||||
it("should be not ok for invalid endings", () => {
|
||||
let item = "xxx ";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "/xxx ";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx.yyy.";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx.yyy.";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx /";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
|
||||
item = "xxx.yyy./";
|
||||
assert.ok(!misc.checkValidName(item).result);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Misc: Dropbox: should fix the folder name cases", () => {
|
||||
it("should do nothing on empty folders", () => {
|
||||
const input: any[] = [];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user