added JSON Schema to validate the config
This commit is contained in:
parent
8f4a733391
commit
5761ab9d62
|
@ -202,9 +202,9 @@ var tcpProm;
|
||||||
function fillConfig(config, args) {
|
function fillConfig(config, args) {
|
||||||
config.debug = config.debug || args.debug;
|
config.debug = config.debug || args.debug;
|
||||||
|
|
||||||
if (!config.ddns) {
|
config.socks5 = config.socks5 || { enabled: false };
|
||||||
config.ddns = { enabled: false };
|
config.ddns = config.ddns || { enabled: false };
|
||||||
}
|
|
||||||
// Use Object.assign to copy any real config values over the default values so we can
|
// Use Object.assign to copy any real config values over the default values so we can
|
||||||
// easily make sure all the fields we need exist .
|
// easily make sure all the fields we need exist .
|
||||||
var mdnsDefaults = { disabled: false, port: 5353, broadcast: '224.0.0.251', ttl: 300 };
|
var mdnsDefaults = { disabled: false, port: 5353, broadcast: '224.0.0.251', ttl: 300 };
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var validator = new (require('jsonschema').Validator)();
|
||||||
|
var recase = require('recase').create({});
|
||||||
|
|
||||||
|
function deepCopy(obj) {
|
||||||
|
if (!obj || typeof obj !== 'object') {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result;
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
result = [];
|
||||||
|
} else {
|
||||||
|
result = {};
|
||||||
|
}
|
||||||
|
Object.keys(obj).forEach(function (key) {
|
||||||
|
result[key] = deepCopy(obj[key]);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var portSchema = { type: 'number', minimum: 1, maximum: 65535 };
|
||||||
|
|
||||||
|
var moduleSchemas = {
|
||||||
|
// the proxy module is common to basically all categories.
|
||||||
|
proxy: {
|
||||||
|
type: 'object'
|
||||||
|
, oneOf: [
|
||||||
|
{ required: [ 'address' ] }
|
||||||
|
, { required: [ 'port' ] }
|
||||||
|
]
|
||||||
|
, properties: {
|
||||||
|
address: { type: 'string' }
|
||||||
|
, host: { type: 'string' }
|
||||||
|
, port: portSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirect and static modules are for HTTP
|
||||||
|
, redirect: {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'to', 'from' ]
|
||||||
|
, properties: {
|
||||||
|
to: { type: 'string'}
|
||||||
|
, from: { type: 'string'}
|
||||||
|
, status: { type: 'integer', minimum: 1, maximum: 999 }
|
||||||
|
, }
|
||||||
|
}
|
||||||
|
, static: {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'root' ]
|
||||||
|
, properties: {
|
||||||
|
root: { type: 'string' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the acme module is for TLS
|
||||||
|
, acme: {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'email' ]
|
||||||
|
, properties: {
|
||||||
|
email: { type: 'string' }
|
||||||
|
, server: { type: 'string' }
|
||||||
|
, challengeType: { type: 'string' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// forward is basically the name for the TCP proxy
|
||||||
|
moduleSchemas.forward = deepCopy(moduleSchemas.proxy);
|
||||||
|
moduleSchemas.forward.required = [ 'ports' ];
|
||||||
|
moduleSchemas.forward.properties.ports = { type: 'array', items: portSchema };
|
||||||
|
|
||||||
|
Object.keys(moduleSchemas).forEach(function (name) {
|
||||||
|
var schema = moduleSchemas[name];
|
||||||
|
schema.id = '/modules/'+name;
|
||||||
|
schema.required = ['id', 'type'].concat(schema.required || []);
|
||||||
|
schema.properties.id = { type: 'string' };
|
||||||
|
schema.properties.type = { type: 'string', const: name };
|
||||||
|
validator.addSchema(schema, schema.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
function addDomainsSchema(base, modList) {
|
||||||
|
var modSchemas = modList.map(function (name) {
|
||||||
|
return { '$ref': '/modules/'+name };
|
||||||
|
});
|
||||||
|
|
||||||
|
base.required = [ 'modules', 'domains' ].concat(base.required || []);
|
||||||
|
base.properties.modules = {
|
||||||
|
type: 'array'
|
||||||
|
, items: {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'domains' ]
|
||||||
|
, properties: {
|
||||||
|
domains: { type: 'array', items: { type: 'string' }, minLength: 1}
|
||||||
|
}
|
||||||
|
, oneOf: modSchemas
|
||||||
|
}
|
||||||
|
};
|
||||||
|
base.properties.domains = {
|
||||||
|
type: 'array'
|
||||||
|
, items: {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'id', 'names', ]
|
||||||
|
, properties: {
|
||||||
|
id: { type: 'string' }
|
||||||
|
, names: { type: 'array', items: { type: 'string' }, minLength: 1}
|
||||||
|
, modules: { type: 'array', items: { oneOf: modSchemas }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, properties: {
|
||||||
|
// These properties should be snake_case to match the API and config format
|
||||||
|
primary_domain: { type: 'string' }
|
||||||
|
, allow_insecure: { type: 'boolean' }
|
||||||
|
, trust_proxy: { type: 'boolean' }
|
||||||
|
, }
|
||||||
|
};
|
||||||
|
addDomainsSchema(httpSchema, ['proxy', 'static', 'redirect']);
|
||||||
|
|
||||||
|
var tlsSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, properties: {
|
||||||
|
acme: {
|
||||||
|
type: 'object'
|
||||||
|
// These properties should be snake_case to match the API and config format
|
||||||
|
, required: [ 'email', 'approved_domains' ]
|
||||||
|
, properties: {
|
||||||
|
email: { type: 'string' }
|
||||||
|
, server: { type: 'string' }
|
||||||
|
, challenge_type: { type: 'string' }
|
||||||
|
, approved_domains: { type: 'array', items: { type: 'string' }, minLength: 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addDomainsSchema(tlsSchema, ['proxy', 'acme']);
|
||||||
|
|
||||||
|
var tcpSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'bind' ]
|
||||||
|
, properties: {
|
||||||
|
bind: { type: 'array', items: portSchema, minLength: 1 }
|
||||||
|
, modules: { type: 'array', items: { '$ref': '/modules/forward' }}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dnsSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, properties: {
|
||||||
|
bind: { type: 'array', items: portSchema }
|
||||||
|
, modules: { type: 'array', items: { '$ref': '/modules/proxy' }}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var mdnsSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'port', 'broadcast', 'ttl' ]
|
||||||
|
, properties: {
|
||||||
|
port: portSchema
|
||||||
|
, broadcast: { type: 'string' }
|
||||||
|
, ttl: { type: 'integer', minimum: 0, maximum: 2147483647 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var ddnsSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, properties: {
|
||||||
|
enabled: { type: 'boolean' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var socks5Schema = {
|
||||||
|
type: 'object'
|
||||||
|
, properties: {
|
||||||
|
enabled: { type: 'boolean' }
|
||||||
|
, port: portSchema
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var mainSchema = {
|
||||||
|
type: 'object'
|
||||||
|
, required: [ 'http', 'tls', 'tcp', 'dns', 'mdns', 'ddns' ]
|
||||||
|
, properties: {
|
||||||
|
http: httpSchema
|
||||||
|
, tls: tlsSchema
|
||||||
|
, tcp: tcpSchema
|
||||||
|
, dns: dnsSchema
|
||||||
|
, mdns: mdnsSchema
|
||||||
|
, ddns: ddnsSchema
|
||||||
|
, socks5: socks5Schema
|
||||||
|
}
|
||||||
|
, additionalProperties: false
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.validate = function (config) {
|
||||||
|
return validator.validate(recase.snakeCopy(config), mainSchema).errors;
|
||||||
|
};
|
|
@ -1029,6 +1029,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
|
||||||
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
|
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
|
||||||
},
|
},
|
||||||
|
"jsonschema": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-XDJApzBauMg0TinJNP4iVcJl99PQ4JbWKK7nwzpOIkAOVveDKgh/2xm41T3x7Spu4PWMhnnQpNJmUSIUgl6sKg=="
|
||||||
|
},
|
||||||
"jsonwebtoken": {
|
"jsonwebtoken": {
|
||||||
"version": "7.4.1",
|
"version": "7.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz",
|
||||||
|
@ -1967,14 +1972,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
|
||||||
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
|
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
|
||||||
},
|
},
|
||||||
"stream-pair": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/stream-pair/-/stream-pair-1.0.3.tgz",
|
|
||||||
"integrity": "sha1-vIdY/jnTgQuva3VMj5BI8PuRNn0=",
|
|
||||||
"requires": {
|
|
||||||
"readable-stream": "2.2.11"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz",
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
"human-readable-ids": "git+https://git.daplie.com/Daplie/human-readable-ids-js#master",
|
"human-readable-ids": "git+https://git.daplie.com/Daplie/human-readable-ids-js#master",
|
||||||
"ipaddr.js": "git+https://github.com/whitequark/ipaddr.js.git#v1.3.0",
|
"ipaddr.js": "git+https://github.com/whitequark/ipaddr.js.git#v1.3.0",
|
||||||
"js-yaml": "^3.8.3",
|
"js-yaml": "^3.8.3",
|
||||||
|
"jsonschema": "^1.2.0",
|
||||||
"jsonwebtoken": "^7.4.0",
|
"jsonwebtoken": "^7.4.0",
|
||||||
"le-challenge-ddns": "git+https://git.daplie.com/Daplie/le-challenge-ddns.git#master",
|
"le-challenge-ddns": "git+https://git.daplie.com/Daplie/le-challenge-ddns.git#master",
|
||||||
"le-challenge-fs": "git+https://git.daplie.com/Daplie/le-challenge-webroot.git#master",
|
"le-challenge-fs": "git+https://git.daplie.com/Daplie/le-challenge-webroot.git#master",
|
||||||
|
|
Loading…
Reference in New Issue