Ensure instance name is a valid Windows file name

Add check for instance name that ensures it being a valid Windows file.
See the microsoft article about naming files for more details:
https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
This commit is contained in:
Hornwitser committed 2019-09-16 16:04:02 +02:00
1 parent 1ba9e68603
commit 53a5ce062b
3 files changed
+98

No files matched your search

+1
View File
@@ -19,6 +19,7 @@ Version 2.0.0
- The masterIP and masterPort config entries has been merged into masterURL.
Breaks discordChat, playerManager, serverSelect, trainTeleports and
clusterioModel.
- Instance names can no longer be invalid Windows file names.
Version 1.2.1
+45
View File
@@ -63,11 +63,55 @@ class Instance {
}
}
function checkFilename(name) {
// All of these are bad in Windows only, except for /, . and ..
// See: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
const badChars = /[<>:"\/\\|?*\x00-\x1f]/g;
const badEnd = /[. ]$/;
const oneToNine = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const badNames = [
// Relative path components
'.', '..',
// Reserved filenames in Windows
'CON', 'PRN', 'AUX', 'NUL',
...oneToNine.map(n => `COM${n}`),
...oneToNine.map(n => `LPT${n}`),
];
if (typeof name !== "string") {
throw new Error("must be a string");
}
if (name === "") {
throw new Error("cannot be empty");
}
if (badChars.test(name)) {
throw new Error('cannot contain <>:"\\/|=* or control characters');
}
if (badNames.includes(name.toUpperCase())) {
throw new Error(
"cannot be named any of . .. CON PRN AUX NUL COM1-9 and LPT1-9"
);
}
if (badEnd.test(name)) {
throw new Error("cannot end with . or space");
}
}
let instance;
if (process.argv[3] !== undefined) {
let name = process.argv[3];
try {
checkFilename(name);
} catch (err) {
throw new Error(`Instance name ${err.message}`);
}
let dir = path.join(config.instanceDirectory, name);
instance = new Instance(dir, name);
}
@@ -892,6 +936,7 @@ function hashMods(instance, callback) {
module.exports = {
// For testing only
_Instance: Instance,
_checkFilename: checkFilename,
_randomDynamicPort: randomDynamicPort,
_generatePassword: generatePassword,
};
+52
View File
@@ -19,6 +19,58 @@ describe("Client testing", function() {
})
});
describe("checkFilename()", function() {
it("should allow a basic name", function() {
client._checkFilename("file");
});
function check(item, msg) {
assert.throws(() => client._checkFilename(item), new Error(msg));
}
it("should throw on non-string", function() {
check(undefined, "must be a string");
check(null, "must be a string");
check({}, "must be a string");
check([], "must be a string");
check(0, "must be a string");
check(false, "must be a string");
});
it("should throw on empty name", function() {
check("", "cannot be empty");
});
it("should throw on <>:\"\\/|?* \\x00\\r\\n\\t", function() {
for (let char of '<>:"\\/|?*\x00\r\n\t') {
check(char, 'cannot contain <>:"\\/|=* or control characters');
}
});
it("should throw on CON, PRN, AUX, NUL, COM1, LPT1", function() {
for (let bad of ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'LPT1']) {
check(
bad, 'cannot be named any of . ..'
+' CON PRN AUX NUL COM1-9 and LPT1-9'
);
}
});
it("should throw on . and ..", function() {
for (let bad of ['.', '..']) {
check(
bad, 'cannot be named any of . ..'
+' CON PRN AUX NUL COM1-9 and LPT1-9'
);
}
});
it("should throw on names ending with . or space", function() {
check("a ", "cannot end with . or space");
check("a.", "cannot end with . or space");
});
});
describe("randomDynamicPort()", function() {
it("should return a port number", function() {
let port = client._randomDynamicPort()