config: use stricter arg and config file parsing.
This commit is contained in:
parent
b892aeab2f
commit
78dfe005c7
@ -135,7 +135,8 @@ Config.prototype.set = function set(key, value) {
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
key = key.toLowerCase().replace(/-/g, '');
|
key = key.replace(/-/g, '');
|
||||||
|
key = key.toLowerCase();
|
||||||
|
|
||||||
this.options[key] = value;
|
this.options[key] = value;
|
||||||
};
|
};
|
||||||
@ -156,7 +157,8 @@ Config.prototype.has = function has(key) {
|
|||||||
|
|
||||||
assert(typeof key === 'string', 'Key must be a string.');
|
assert(typeof key === 'string', 'Key must be a string.');
|
||||||
|
|
||||||
key = key.toLowerCase().replace(/-/g, '');
|
key = key.replace(/-/g, '');
|
||||||
|
key = key.toLowerCase();
|
||||||
|
|
||||||
if (this.hash[key] != null)
|
if (this.hash[key] != null)
|
||||||
return true;
|
return true;
|
||||||
@ -214,7 +216,8 @@ Config.prototype.get = function get(key, fallback) {
|
|||||||
|
|
||||||
assert(typeof key === 'string', 'Key must be a string.');
|
assert(typeof key === 'string', 'Key must be a string.');
|
||||||
|
|
||||||
key = key.toLowerCase().replace(/-/g, '');
|
key = key.replace(/-/g, '');
|
||||||
|
key = key.toLowerCase();
|
||||||
|
|
||||||
if (this.hash[key] != null)
|
if (this.hash[key] != null)
|
||||||
return this.hash[key];
|
return this.hash[key];
|
||||||
@ -735,47 +738,69 @@ Config.prototype.location = function location(file) {
|
|||||||
Config.prototype.parseConfig = function parseConfig(text) {
|
Config.prototype.parseConfig = function parseConfig(text) {
|
||||||
assert(typeof text === 'string', 'Config must be text.');
|
assert(typeof text === 'string', 'Config must be text.');
|
||||||
|
|
||||||
text = text.trim();
|
if (text.charCodeAt(0) === 0xfeff)
|
||||||
|
text = text.substring(1);
|
||||||
|
|
||||||
const parts = text.split(/\n+/);
|
text = text.replace(/\r\n/g, '\n');
|
||||||
|
text = text.replace(/\r/g, '\n');
|
||||||
|
text = text.replace(/\\\n/g, '');
|
||||||
|
|
||||||
for (let line of parts) {
|
let colons = true;
|
||||||
line = line.trim();
|
let seen = false;
|
||||||
|
let num = 0;
|
||||||
|
|
||||||
|
for (const chunk of text.split('\n')) {
|
||||||
|
const line = chunk.trim();
|
||||||
|
|
||||||
|
num += 1;
|
||||||
|
|
||||||
if (line.length === 0)
|
if (line.length === 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (/^\s*#/.test(line))
|
if (line[0] === '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let eq = line.indexOf('=');
|
const equal = line.indexOf('=');
|
||||||
const col = line.indexOf(':');
|
const colon = line.indexOf(':');
|
||||||
|
|
||||||
if (col !== -1 && (col < eq || eq === -1))
|
let index = -1;
|
||||||
eq = col;
|
|
||||||
|
|
||||||
let key, value;
|
if (colon !== -1 && (colon < equal || equal === -1)) {
|
||||||
if (eq === -1) {
|
if (seen && !colons)
|
||||||
key = line.trim();
|
throw new Error(`Expected \`=\` on line ${num}: "${line}".`);
|
||||||
value = '';
|
|
||||||
|
index = colon;
|
||||||
|
seen = true;
|
||||||
|
colons = true;
|
||||||
|
} else if (equal !== -1) {
|
||||||
|
if (seen && colons)
|
||||||
|
throw new Error(`Expected \`:\` on line ${num}: "${line}".`);
|
||||||
|
|
||||||
|
index = equal;
|
||||||
|
seen = true;
|
||||||
|
colons = false;
|
||||||
} else {
|
} else {
|
||||||
key = line.substring(0, eq).trim();
|
const symbol = colons ? ':' : '=';
|
||||||
value = line.substring(eq + 1).trim();
|
throw new Error(`Expected \`${symbol}\` on line ${num}: "${line}".`);
|
||||||
}
|
}
|
||||||
|
|
||||||
key = key.replace(/\-/g, '').toLowerCase();
|
let key = line.substring(0, index).trim();
|
||||||
|
|
||||||
|
key = key.replace(/\-/g, '')
|
||||||
|
|
||||||
|
if (!isLowerKey(key))
|
||||||
|
throw new Error(`Invalid option on line ${num}: ${key}.`);
|
||||||
|
|
||||||
|
const value = line.substring(index + 1).trim();
|
||||||
|
|
||||||
|
if (value.length === 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
const alias = Config.alias[key];
|
const alias = Config.alias[key];
|
||||||
|
|
||||||
if (alias)
|
if (alias)
|
||||||
key = alias;
|
key = alias;
|
||||||
|
|
||||||
if (key.length === 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (value.length === 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.data[key] = value;
|
this.data[key] = value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -816,19 +841,21 @@ Config.prototype.parseArg = function parseArg(argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (arg.indexOf('--') === 0) {
|
if (arg.indexOf('--') === 0) {
|
||||||
// e.g. --opt
|
const index = arg.indexOf('=');
|
||||||
const parts = arg.split('=');
|
|
||||||
|
|
||||||
let key = parts[0];
|
let key = null;
|
||||||
let value = null;
|
let value = null;
|
||||||
let empty = false;
|
let empty = false;
|
||||||
|
|
||||||
if (parts.length > 1) {
|
if (index !== -1) {
|
||||||
// e.g. --opt=val
|
// e.g. --opt=val
|
||||||
value = parts.slice(1).join('=').trim();
|
key = arg.substring(2, index);
|
||||||
|
value = arg.substring(index + 1);
|
||||||
last = null;
|
last = null;
|
||||||
empty = false;
|
empty = false;
|
||||||
} else {
|
} else {
|
||||||
|
// e.g. --opt
|
||||||
|
key = arg.substring(2);
|
||||||
value = 'true';
|
value = 'true';
|
||||||
last = null;
|
last = null;
|
||||||
empty = true;
|
empty = true;
|
||||||
@ -836,8 +863,8 @@ Config.prototype.parseArg = function parseArg(argv) {
|
|||||||
|
|
||||||
key = key.replace(/\-/g, '');
|
key = key.replace(/\-/g, '');
|
||||||
|
|
||||||
if (key.length === 0)
|
if (!isLowerKey(key))
|
||||||
continue;
|
throw new Error(`Invalid argument: --${key}.`);
|
||||||
|
|
||||||
if (value.length === 0)
|
if (value.length === 0)
|
||||||
continue;
|
continue;
|
||||||
@ -860,19 +887,32 @@ Config.prototype.parseArg = function parseArg(argv) {
|
|||||||
if (arg[0] === '-') {
|
if (arg[0] === '-') {
|
||||||
// e.g. -abc
|
// e.g. -abc
|
||||||
last = null;
|
last = null;
|
||||||
|
|
||||||
for (let j = 1; j < arg.length; j++) {
|
for (let j = 1; j < arg.length; j++) {
|
||||||
let key = arg[j];
|
let key = arg[j];
|
||||||
|
|
||||||
|
if ((key < 'a' || key > 'z')
|
||||||
|
&& (key < 'A' || key > 'Z')
|
||||||
|
&& (key < '0' || key > '9')
|
||||||
|
&& key !== '?') {
|
||||||
|
throw new Error(`Invalid argument: -${key}.`);
|
||||||
|
}
|
||||||
|
|
||||||
const alias = Config.alias[key];
|
const alias = Config.alias[key];
|
||||||
|
|
||||||
if (alias)
|
if (alias)
|
||||||
key = alias;
|
key = alias;
|
||||||
|
|
||||||
this.args[key] = 'true';
|
this.args[key] = 'true';
|
||||||
|
|
||||||
last = key;
|
last = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// e.g. foo
|
// e.g. foo
|
||||||
const value = arg.trim();
|
const value = arg;
|
||||||
|
|
||||||
if (value.length === 0) {
|
if (value.length === 0) {
|
||||||
last = null;
|
last = null;
|
||||||
@ -908,24 +948,24 @@ Config.prototype.parseEnv = function parseEnv(env) {
|
|||||||
assert(env && typeof env === 'object');
|
assert(env && typeof env === 'object');
|
||||||
|
|
||||||
for (let key of Object.keys(env)) {
|
for (let key of Object.keys(env)) {
|
||||||
let value = env[key];
|
const value = env[key];
|
||||||
|
|
||||||
assert(typeof value === 'string');
|
assert(typeof value === 'string');
|
||||||
|
|
||||||
if (key.indexOf(prefix) !== 0)
|
if (!util.startsWith(key, prefix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
key = key.substring(prefix.length);
|
key = key.substring(prefix.length);
|
||||||
key = key.replace(/_/g, '').toLowerCase();
|
key = key.replace(/_/g, '');
|
||||||
|
|
||||||
if (key.length === 0)
|
if (!isUpperKey(key))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
value = value.trim();
|
|
||||||
|
|
||||||
if (value.length === 0)
|
if (value.length === 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
key = key.toLowerCase();
|
||||||
|
|
||||||
// Do not allow one-letter aliases.
|
// Do not allow one-letter aliases.
|
||||||
if (key.length > 1) {
|
if (key.length > 1) {
|
||||||
const alias = Config.alias[key];
|
const alias = Config.alias[key];
|
||||||
@ -989,27 +1029,30 @@ Config.prototype.parseForm = function parseForm(query, map) {
|
|||||||
if (query.length === 0)
|
if (query.length === 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (query[0] === '?' || query[0] === '#')
|
let ch = '?';
|
||||||
|
|
||||||
|
if (map === this.hash)
|
||||||
|
ch = '#';
|
||||||
|
|
||||||
|
if (query[0] === ch)
|
||||||
query = query.substring(1);
|
query = query.substring(1);
|
||||||
|
|
||||||
const parts = query.split('&');
|
for (const pair of query.split('&')) {
|
||||||
|
|
||||||
for (const pair of parts) {
|
|
||||||
const index = pair.indexOf('=');
|
const index = pair.indexOf('=');
|
||||||
|
|
||||||
let key, value;
|
let key, value;
|
||||||
if (index === -1) {
|
if (index !== -1) {
|
||||||
key = pair;
|
|
||||||
value = '';
|
|
||||||
} else {
|
|
||||||
key = pair.substring(0, index);
|
key = pair.substring(0, index);
|
||||||
value = pair.substring(index + 1);
|
value = pair.substring(index + 1);
|
||||||
|
} else {
|
||||||
|
key = pair;
|
||||||
|
value = 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
key = unescape(key);
|
key = unescape(key);
|
||||||
key = key.replace(/\-/g, '').toLowerCase();
|
key = key.replace(/\-/g, '');
|
||||||
|
|
||||||
if (key.length === 0)
|
if (!isLowerKey(key))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
value = unescape(value);
|
value = unescape(value);
|
||||||
@ -1055,6 +1098,24 @@ function isAlpha(str) {
|
|||||||
return /^[a-z0-9]+$/.test(str);
|
return /^[a-z0-9]+$/.test(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isKey(key) {
|
||||||
|
return /^[a-zA-Z0-9]+$/.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLowerKey(key) {
|
||||||
|
if (!isKey(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !/[A-Z]/.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUpperKey(key) {
|
||||||
|
if (!isKey(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !/[a-z]/.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user