From 7dde31546ef96a4b3ade47c6806e295bbfff2831 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Wed, 26 Apr 2017 23:48:55 +0200 Subject: [PATCH 1/8] Add jsdoc search.js --- lib/search.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/search.js b/lib/search.js index eda8fcfb8..49c1a09f3 100644 --- a/lib/search.js +++ b/lib/search.js @@ -2,7 +2,14 @@ const lunr = require('lunr'); +/** + * Handle the search Indexer. + */ class Search { + + /** + * Constructor. + */ constructor() { this.index = lunr(function() { this.field('name', {boost: 10}); @@ -12,6 +19,12 @@ class Search { }); } + /** + * Performs a query to the indexer. + * If the keyword is a * it returns all local elements + * otherwise performs a search + * @param {*} q the keyword + */ query(q) { return q === '*' ? this.storage.config.localList.get().map( function( pkg ) { @@ -19,6 +32,10 @@ class Search { }) : this.index.search(q); } + /** + * Add a new element to index + * @param {*} pkg the package + */ add(pkg) { this.index.add({ id: pkg.name, @@ -28,10 +45,17 @@ class Search { }); } + /** + * Remove an element from the index. + * @param {*} name the id element + */ remove(name) { this.index.remove({id: name}); } + /** + * Force a reindex. + */ reindex() { let self = this; this.storage.get_local(function(err, packages) { @@ -43,6 +67,10 @@ class Search { }); } + /** + * Set up the {Storage} + * @param {*} storage An storage reference. + */ configureStorage(storage) { this.storage = storage; this.reindex(); From 5a17a040902b413ba45ae61a09fe5f39d3d89221 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 00:35:25 +0200 Subject: [PATCH 2/8] Add jsdoc and fix lint warnings for utils.js --- lib/utils.js | 410 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 241 insertions(+), 169 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 483287269..a39befd5b 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -5,193 +5,265 @@ let Semver = require('semver'); let URL = require('url'); let Logger = require('./logger'); -module.exports.validate_package = function(name) { - name = name.split('/', 2); - if (name.length === 1) { - // normal package - return module.exports.validate_name(name[0]); - } else { - // scoped package - return name[0][0] === '@' - && module.exports.validate_name(name[0].slice(1)) - && module.exports.validate_name(name[1]); - } -}; +/** + * Validate a package. + * @param {*} name + * @return {Boolean} whether the package is valid or not + */ +function validate_package(name) { + name = name.split('/', 2); + if (name.length === 1) { + // normal package + return module.exports.validate_name(name[0]); + } else { + // scoped package + return name[0][0] === '@' + && module.exports.validate_name(name[0].slice(1)) + && module.exports.validate_name(name[1]); + } +} -// from normalize-package-data/lib/fixer.js -module.exports.validate_name = function(name) { - if (typeof(name) !== 'string') return false; - name = name.toLowerCase(); +/** + * From normalize-package-data/lib/fixer.js + * @param {*} name the package name + * @return {Boolean} whether is valid or not + */ +function validate_name(name) { + if (typeof(name) !== 'string') { + return false; + } + name = name.toLowerCase(); - // all URL-safe characters and "@" for issue #75 - if (!name.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) - || name.charAt(0) === '.' // ".bin", etc. - || name.charAt(0) === '-' // "-" is reserved by couchdb - || name === 'node_modules' - || name === '__proto__' - || name === 'package.json' - || name === 'favicon.ico' - ) { - return false; - } else { - return true; - } -}; + // all URL-safe characters and "@" for issue #75 + if (!name.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) + || name.charAt(0) === '.' // ".bin", etc. + || name.charAt(0) === '-' // "-" is reserved by couchdb + || name === 'node_modules' + || name === '__proto__' + || name === 'package.json' + || name === 'favicon.ico' + ) { + return false; + } else { + return true; + } +} -module.exports.is_object = function(obj) { - return typeof(obj) === 'object' && obj !== null && !Array.isArray(obj); -}; +/** + * Check whether an element is an Object + * @param {*} obj the element + * @return {Boolean} + */ +function is_object(obj) { + return typeof(obj) === 'object' && obj !== null && !Array.isArray(obj); +} -module.exports.validate_metadata = function(object, name) { - assert(module.exports.is_object(object), 'not a json object'); - assert.equal(object.name, name); +/** + * Validate the package metadata, add additional properties whether are missing within + * the metadata properties. + * @param {*} object + * @param {*} name + * @return {Object} the object with additional properties as dist-tags ad versions + */ +function validate_metadata(object, name) { + assert(module.exports.is_object(object), 'not a json object'); + assert.equal(object.name, name); - if (!module.exports.is_object(object['dist-tags'])) { - object['dist-tags'] = {}; - } + if (!module.exports.is_object(object['dist-tags'])) { + object['dist-tags'] = {}; + } - if (!module.exports.is_object(object['versions'])) { - object['versions'] = {}; - } + if (!module.exports.is_object(object['versions'])) { + object['versions'] = {}; + } - return object; -}; + return object; +} -module.exports.filter_tarball_urls = function(pkg, req, config) { - function filter(_url) { - if (!req.headers.host) return _url; +/** + * Iterate a packages's versions and filter each original tarbal url. + * @param {*} pkg + * @param {*} req + * @param {*} config + * @return {String} a filtered package + */ +function filter_tarball_urls(pkg, req, config) { + /** + * Filter a tarball url. + * @param {*} _url + * @return {String} a parsed url + */ + const filter = function(_url) { + if (!req.headers.host) { + return _url; + } + let filename = URL.parse(_url).pathname.replace(/^.*\//, ''); + let result; + if (config.url_prefix != null) { + result = config.url_prefix.replace(/\/$/, ''); + } else { + result = req.protocol + '://' + req.headers.host; + } + return `${result}/${pkg.name.replace(/\//g, '%2f')}/-/${filename}`; + }; - let filename = URL.parse(_url).pathname.replace(/^.*\//, ''); + for (let ver in pkg.versions) { + let dist = pkg.versions[ver].dist; + if (dist != null && dist.tarball != null) { + // dist.__verdaccio_orig_tarball = dist.tarball + dist.tarball = filter(dist.tarball); + } + } + return pkg; +} - if (config.url_prefix != null) { - var result = config.url_prefix.replace(/\/$/, ''); - } else { - var result = req.protocol + '://' + req.headers.host; - } +/** + * Create a tag for a package + * @param {*} data + * @param {*} version + * @param {*} tag + * @return {Boolean} whether a package has been tagged + */ +function tag_version(data, version, tag) { + if (tag) { + if (data['dist-tags'][tag] !== version) { + if (Semver.parse(version, true)) { + // valid version - store + data['dist-tags'][tag] = version; + return true; + } + } + Logger.logger.warn({ver: version, tag: tag}, 'ignoring bad version @{ver} in @{tag}'); + if (tag && data['dist-tags'][tag]) { + delete data['dist-tags'][tag]; + } + } + return false; +} - return `${result}/${pkg.name.replace(/\//g, '%2f')}/-/${filename}`; - } +/** + * Gets version from a package object taking into account semver weirdness. + * @param {*} object + * @param {*} version + * @return {String} return the semantic version of a package + */ +function get_version(object, version) { + // this condition must allow cast + if (object.versions[version] != null) { + return object.versions[version]; + } + try { + version = Semver.parse(version, true); + for (let k in object.versions) { + if (version.compare(Semver.parse(k, true)) === 0) { + return object.versions[k]; + } + } + } catch (err) { + return undefined; + } +} - for (let ver in pkg.versions) { - let dist = pkg.versions[ver].dist; - if (dist != null && dist.tarball != null) { - // dist.__verdaccio_orig_tarball = dist.tarball - dist.tarball = filter(dist.tarball); - } - } - return pkg; -}; +/** + * Parse an internet address + * Allow: + - https:localhost:1234 - protocol + host + port + - localhost:1234 - host + port + - 1234 - port + - http::1234 - protocol + port + - https://localhost:443/ - full url + https + - http://[::1]:443/ - ipv6 + - unix:/tmp/http.sock - unix sockets + - https://unix:/tmp/http.sock - unix sockets (https) + * @param {*} addr the internet address definition + * @return {Object|Null} literal object that represent the address parsed + */ +function parse_address(addr) { + // + // TODO: refactor it to something more reasonable? + // + // protocol : // ( host )|( ipv6 ): port / + let m = /^((https?):(\/\/)?)?((([^\/:]*)|\[([^\[\]]+)\]):)?(\d+)\/?$/.exec(addr); -module.exports.tag_version = function(data, version, tag) { - if (tag) { - if (data['dist-tags'][tag] !== version) { - if (Semver.parse(version, true)) { - // valid version - store - data['dist-tags'][tag] = version; - return true; - } - } - Logger.logger.warn({ver: version, tag: tag}, 'ignoring bad version @{ver} in @{tag}'); - if (tag && data['dist-tags'][tag]) { - delete data['dist-tags'][tag]; - } - } - return false; -}; + if (m) return { + proto: m[2] || 'http', + host: m[6] || m[7] || 'localhost', + port: m[8] || '4873', + }; -// gets version from a package object taking into account semver weirdness -module.exports.get_version = function(object, version) { - if (object.versions[version] != null) return object.versions[version]; + m = /^((https?):(\/\/)?)?unix:(.*)$/.exec(addr); - try { - version = Semver.parse(version, true); - for (let k in object.versions) { - if (version.compare(Semver.parse(k, true)) === 0) { - return object.versions[k]; - } - } - } catch (err) { - return undefined; - } -}; + if (m) { + return { + proto: m[2] || 'http', + path: m[4], + }; + } -module.exports.parse_address = function parse_address(addr) { - // - // Allow: - // - // - https:localhost:1234 - protocol + host + port - // - localhost:1234 - host + port - // - 1234 - port - // - http::1234 - protocol + port - // - https://localhost:443/ - full url + https - // - http://[::1]:443/ - ipv6 - // - unix:/tmp/http.sock - unix sockets - // - https://unix:/tmp/http.sock - unix sockets (https) - // - // TODO: refactor it to something more reasonable? - // - // protocol : // ( host )|( ipv6 ): port / - var m = /^((https?):(\/\/)?)?((([^\/:]*)|\[([^\[\]]+)\]):)?(\d+)\/?$/.exec(addr); + return null; +} - if (m) return { - proto: m[2] || 'http', - host: m[6] || m[7] || 'localhost', - port: m[8] || '4873', - }; +/** + * Function filters out bad semver versions and sorts the array. + * @param {*} array + * @return {Array} sorted Array + */ +function semver_sort(array) { + return array + .filter(function(x) { + if (!Semver.parse(x, true)) { + Logger.logger.warn( {ver: x}, 'ignoring bad version @{ver}' ); + return false; + } + return true; + }) + .sort(Semver.compareLoose) + .map(String); +} - var m = /^((https?):(\/\/)?)?unix:(.*)$/.exec(addr); +/** + * Flatten arrays of tags. + * @param {*} data + */ +function normalize_dist_tags(data) { + let sorted; - if (m) return { - proto: m[2] || 'http', - path: m[4], - }; + if (!data['dist-tags'].latest) { + // overwrite latest with highest known version based on semver sort + sorted = module.exports.semver_sort(Object.keys(data.versions)); + if (sorted && sorted.length) { + data['dist-tags'].latest = sorted.pop(); + } + } - return null; -}; + for (let tag in data['dist-tags']) { + if (Array.isArray(data['dist-tags'][tag])) { + if (data['dist-tags'][tag].length) { + // sort array + sorted = module.exports.semver_sort(data['dist-tags'][tag]); + if (sorted.length) { + // use highest version based on semver sort + data['dist-tags'][tag] = sorted.pop(); + } + } else { + delete data['dist-tags'][tag]; + } + } else if (typeof data['dist-tags'][tag] === 'string') { + if (!Semver.parse(data['dist-tags'][tag], true)) { + // if the version is invalid, delete the dist-tag entry + delete data['dist-tags'][tag]; + } + } + } +} -// function filters out bad semver versions and sorts the array -module.exports.semver_sort = function semver_sort(array) { - return array - .filter(function(x) { - if (!Semver.parse(x, true)) { - Logger.logger.warn( {ver: x}, 'ignoring bad version @{ver}' ); - return false; - } - return true; - }) - .sort(Semver.compareLoose) - .map(String); -}; - -// flatten arrays of tags -module.exports.normalize_dist_tags = function(data) { - let sorted; - - if (!data['dist-tags'].latest) { - // overwrite latest with highest known version based on semver sort - sorted = module.exports.semver_sort(Object.keys(data.versions)); - if (sorted && sorted.length) { - data['dist-tags'].latest = sorted.pop(); - } - } - - for (let tag in data['dist-tags']) { - if (Array.isArray(data['dist-tags'][tag])) { - if (data['dist-tags'][tag].length) { - // sort array - sorted = module.exports.semver_sort(data['dist-tags'][tag]); - if (sorted.length) { - // use highest version based on semver sort - data['dist-tags'][tag] = sorted.pop(); - } - } else { - delete data['dist-tags'][tag]; - } - } else if (typeof data['dist-tags'][tag] === 'string') { - if (!Semver.parse(data['dist-tags'][tag], true)) { - // if the version is invalid, delete the dist-tag entry - delete data['dist-tags'][tag]; - } - } - } -}; +module.exports.semver_sort = semver_sort; +module.exports.parse_address = parse_address; +module.exports.get_version = get_version; +module.exports.normalize_dist_tags = normalize_dist_tags; +module.exports.tag_version = tag_version; +module.exports.filter_tarball_urls = filter_tarball_urls; +module.exports.validate_metadata = validate_metadata; +module.exports.is_object = is_object; +module.exports.validate_name = validate_name; +module.exports.validate_package = validate_package; From 105a34f91231168eba02f262d2959ae7f3c880d9 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 00:36:19 +0200 Subject: [PATCH 3/8] Apply es6 feature utils.js --- lib/utils.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index a39befd5b..7f6294232 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,9 +1,9 @@ 'use strict'; -let assert = require('assert'); -let Semver = require('semver'); -let URL = require('url'); -let Logger = require('./logger'); +const assert = require('assert'); +const Semver = require('semver'); +const URL = require('url'); +const Logger = require('./logger'); /** * Validate a package. From 318634f0729daada90a66fa83f85f5f28da4cf2a Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 03:50:04 +0200 Subject: [PATCH 4/8] Add jsdoc to stream.js --- lib/streams.js | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/streams.js b/lib/streams.js index 9a105aa17..9fd0f560f 100644 --- a/lib/streams.js +++ b/lib/streams.js @@ -1,16 +1,15 @@ 'use strict'; -let Stream = require('stream'); -let Util = require('util'); +const Stream = require('stream'); +const Util = require('util'); -module.exports.ReadTarballStream = ReadTarball; -module.exports.UploadTarballStream = UploadTarball; - -// -// This stream is used to read tarballs from repository -// +/** + * This stream is used to read tarballs from repository. + * @param {*} options + * @return {Object} + */ function ReadTarball(options) { - let self = new Stream.PassThrough(options); + const self = new Stream.PassThrough(options); Object.setPrototypeOf(self, ReadTarball.prototype); // called when data is not needed anymore @@ -21,11 +20,13 @@ function ReadTarball(options) { Util.inherits(ReadTarball, Stream.PassThrough); -// -// This stream is used to upload tarballs to a repository -// +/** + * This stream is used to upload tarballs to a repository. + * @param {*} options + * @return {Object} + */ function UploadTarball(options) { - let self = new Stream.PassThrough(options); + const self = new Stream.PassThrough(options); Object.setPrototypeOf(self, UploadTarball.prototype); // called when user closes connection before upload finishes @@ -39,10 +40,12 @@ function UploadTarball(options) { Util.inherits(UploadTarball, Stream.PassThrough); -// -// This function intercepts abstract calls and replays them allowing -// us to attach those functions after we are ready to do so -// +/** + * This function intercepts abstract calls and replays them allowing. + * us to attach those functions after we are ready to do so + * @param {*} self + * @param {*} name + */ function add_abstract_method(self, name) { self._called_methods = self._called_methods || {}; self.__defineGetter__(name, function() { @@ -60,3 +63,5 @@ function add_abstract_method(self, name) { }); } +module.exports.ReadTarballStream = ReadTarball; +module.exports.UploadTarballStream = UploadTarball; From 09c60e68e0518f25c0b2f5c173152fefa5a8159f Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 03:59:11 +0200 Subject: [PATCH 5/8] Add missing @return on search.js --- lib/search.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/search.js b/lib/search.js index 49c1a09f3..20fd21a83 100644 --- a/lib/search.js +++ b/lib/search.js @@ -24,6 +24,7 @@ class Search { * If the keyword is a * it returns all local elements * otherwise performs a search * @param {*} q the keyword + * @return {Array} list of results. */ query(q) { return q === '*' From acfd865bb069bcb35035d76384345599166a3b36 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 05:52:46 +0200 Subject: [PATCH 6/8] Fix eslint issues, add jsdoc --- lib/plugin-loader.js | 18 +++++++++++++++++- lib/search.js | 2 ++ lib/status-cats.js | 2 ++ lib/utils.js | 15 ++++++++------- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/plugin-loader.js b/lib/plugin-loader.js index 6ff4739e2..bf01985fb 100644 --- a/lib/plugin-loader.js +++ b/lib/plugin-loader.js @@ -1,7 +1,12 @@ 'use strict'; -let Path = require('path'); +const Path = require('path'); +/** + * Requires a module. + * @param {*} path the module's path + * @return {Object} + */ function try_load(path) { try { return require(path); @@ -13,6 +18,17 @@ function try_load(path) { } } +/** + * Load a plugin following the rules + * - First try to load from the internal directory plugins (which will disappear soon or later). + * - A seccond attempt from node_modules, in case to have multiple match as for instance verdaccio-ldap + * and sinopia-ldap. All verdaccio prefix will have preferences. + * @param {*} config a reference of the configuration settings + * @param {*} plugin_configs + * @param {*} params a set of params to initialise the plugin + * @param {*} sanity_check callback that check the shape that should fulfill the plugin + * @return {Array} list of plugins + */ function load_plugins(config, plugin_configs, params, sanity_check) { let plugins = Object.keys(plugin_configs || {}).map(function(p) { let plugin; diff --git a/lib/search.js b/lib/search.js index 20fd21a83..51cba12b1 100644 --- a/lib/search.js +++ b/lib/search.js @@ -1,3 +1,5 @@ +/* eslint no-invalid-this: "off" */ + 'use strict'; const lunr = require('lunr'); diff --git a/lib/status-cats.js b/lib/status-cats.js index f1cb4dd7d..a3561d3f5 100644 --- a/lib/status-cats.js +++ b/lib/status-cats.js @@ -1,3 +1,5 @@ +/* eslint prefer-rest-params: "off" */ + 'use strict'; // see https://secure.flickr.com/photos/girliemac/sets/72157628409467125 diff --git a/lib/utils.js b/lib/utils.js index 7f6294232..74f4a82dc 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -97,21 +97,23 @@ function filter_tarball_urls(pkg, req, config) { if (!req.headers.host) { return _url; } - let filename = URL.parse(_url).pathname.replace(/^.*\//, ''); + const filename = URL.parse(_url).pathname.replace(/^.*\//, ''); let result; if (config.url_prefix != null) { result = config.url_prefix.replace(/\/$/, ''); } else { - result = req.protocol + '://' + req.headers.host; + result = `${req.protocol}://${req.headers.host}`; } return `${result}/${pkg.name.replace(/\//g, '%2f')}/-/${filename}`; }; for (let ver in pkg.versions) { - let dist = pkg.versions[ver].dist; - if (dist != null && dist.tarball != null) { - // dist.__verdaccio_orig_tarball = dist.tarball - dist.tarball = filter(dist.tarball); + if (Object.prototype.hasOwnProperty.call(pkg.versions, ver)) { + const dist = pkg.versions[ver].dist; + if (dist != null && dist.tarball != null) { + // dist.__verdaccio_orig_tarball = dist.tarball + dist.tarball = filter(dist.tarball); + } } } return pkg; @@ -227,7 +229,6 @@ function semver_sort(array) { */ function normalize_dist_tags(data) { let sorted; - if (!data['dist-tags'].latest) { // overwrite latest with highest known version based on semver sort sorted = module.exports.semver_sort(Object.keys(data.versions)); From 1d062075c4359ca49a3215c1ec3f3ac752cc4e56 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 06:54:15 +0200 Subject: [PATCH 7/8] Refactor config.js to es6, add jsdoc --- lib/config.js | 445 ++++++++++++++++++++++++++++---------------------- 1 file changed, 248 insertions(+), 197 deletions(-) diff --git a/lib/config.js b/lib/config.js index 96b2affe2..19b863f7f 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,209 +1,260 @@ +/* eslint prefer-rest-params: "off" */ +/* eslint prefer-spread: "off" */ + 'use strict'; -let assert = require('assert'); -let Crypto = require('crypto'); -let Error = require('http-errors'); -let minimatch = require('minimatch'); -let Path = require('path'); -let LocalData = require('./local-data'); -var Utils = require('./utils'); -var Utils = require('./utils'); -let pkginfo = require('pkginfo')(module); // eslint-disable-line no-unused-vars -let pkgVersion = module.exports.version; -let pkgName = module.exports.name; +const assert = require('assert'); +const Crypto = require('crypto'); +const Error = require('http-errors'); +const minimatch = require('minimatch'); +const Path = require('path'); +const LocalData = require('./local-data'); +const Utils = require('./utils'); +const pkginfo = require('pkginfo')(module); // eslint-disable-line no-unused-vars +const pkgVersion = module.exports.version; +const pkgName = module.exports.name; -// [[a, [b, c]], d] -> [a, b, c, d] +/** + * [[a, [b, c]], d] -> [a, b, c, d] + * @param {*} array + * @return {Array} + */ function flatten(array) { - let result = []; - for (let i=0; i= last_suffix + || (m[4] === '' && last_suffix !== Infinity)) { + throw Error('invalid interval: ' + interval); + } + last_suffix = parse_interval_table[m[4]]; + result += Number(m[1]) * parse_interval_table[m[4]]; + }); + return result; } -Config.prototype.can_proxy_to = function(pkg, uplink) { - return (this.get_package_spec(pkg).proxy || []).reduce(function(prev, curr) { - if (uplink === curr) return true; - return prev; - }, false); -}; +/** + * Coordinates the application configuration + */ +class Config { -Config.prototype.get_package_spec = function(pkg) { - for (let i in this.packages) { - if (minimatch.makeRe(i).exec(pkg)) { - return this.packages[i]; - } - } - return {}; -}; + /** + * Constructor + * @param {*} config config the content + */ + constructor(config) { + const self = this; + for (let i in config) { + if (self[i] == null) { + self[i] = config[i]; + } + } + + if (!self.user_agent) { + self.user_agent = `${pkgName}/${pkgVersion}`; + } + + // some weird shell scripts are valid yaml files parsed as string + assert.equal(typeof(config), 'object', 'CONFIG: it doesn\'t look like a valid config file'); + + assert(self.storage, 'CONFIG: storage path not defined'); + // local data handler is linked with the configuration handler + self.localList = new LocalData( + Path.join( + Path.resolve(Path.dirname(self.self_path || ''), self.storage), + // FUTURE: the database might be parameterizable from config.yaml + '.sinopia-db.json' + ) + ); + // it generates a secret key + // FUTURE: this might be an external secret key, perhaps whitin config file? + if (!self.secret) { + self.secret = self.localList.data.secret; + if (!self.secret) { + self.secret = Crypto.pseudoRandomBytes(32).toString('hex'); + self.localList.data.secret = self.secret; + self.localList.sync(); + } + } + + const users = { + 'all': true, + 'anonymous': true, + 'undefined': true, + 'owner': true, + 'none': true, + }; + + const check_user_or_uplink = function(arg) { + assert(arg !== 'all' && arg !== 'owner' + && arg !== 'anonymous' && arg !== 'undefined' && arg !== 'none', 'CONFIG: reserved user/uplink name: ' + arg); + assert(!arg.match(/\s/), 'CONFIG: invalid user name: ' + arg); + assert(users[arg] == null, 'CONFIG: duplicate user/uplink name: ' + arg); + users[arg] = true; + } + // sanity check for strategic config properties + ;['users', 'uplinks', 'packages'].forEach(function(x) { + if (self[x] == null) self[x] = {}; + assert(Utils.is_object(self[x]), `CONFIG: bad "${x}" value (object expected)`); + }); + // sanity check for users + for (let i in self.users) { + if (Object.prototype.hasOwnProperty.call(self.users, i)) { + check_user_or_uplink(i); + } + } + // sanity check for uplinks + for (let i in self.uplinks) { + if (Object.prototype.hasOwnProperty.call(self.uplinks, i)) { + check_user_or_uplink(i); + } + } + for (let i in self.users) { + if (Object.prototype.hasOwnProperty.call(self.users, i)) { + assert(self.users[i].password, 'CONFIG: no password for user: ' + i); + assert(typeof(self.users[i].password) === 'string' && + self.users[i].password.match(/^[a-f0-9]{40}$/) + , 'CONFIG: wrong password format for user: ' + i + ', sha1 expected'); + } + } + for (let i in self.uplinks) { + if (Object.prototype.hasOwnProperty.call(self.uplinks, i)) { + assert(self.uplinks[i].url, 'CONFIG: no url for uplink: ' + i); + assert( typeof(self.uplinks[i].url) === 'string' + , 'CONFIG: wrong url format for uplink: ' + i); + self.uplinks[i].url = self.uplinks[i].url.replace(/\/$/, ''); + } + } + + /** + * Normalise user list. + * @return {Array} + */ + function normalize_userlist() { + let result = []; + + for (let i=0; i= last_suffix - || (m[4] === '' && last_suffix !== Infinity)) { - throw Error('invalid interval: ' + interval); - } - last_suffix = parse_interval_table[m[4]]; - result += Number(m[1]) * parse_interval_table[m[4]]; - }); - return result; -}; +module.exports.parse_interval = parse_interval; From 90328d5fafb986d0d07f84329a1d69f2fc5af2c6 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Thu, 27 Apr 2017 06:54:53 +0200 Subject: [PATCH 8/8] Fix config.js new shape --- lib/index.js | 2 +- test/unit/search.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index f244a1653..5be203e43 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,7 +13,7 @@ let Storage = require('./storage'); module.exports = function(config_hash) { Logger.setup(config_hash.logs); - let config = Config(config_hash); + let config = new Config(config_hash); let storage = new Storage(config); let auth = Auth(config); let app = express(); diff --git a/test/unit/search.js b/test/unit/search.js index 837bc8f69..5b74e43b0 100644 --- a/test/unit/search.js +++ b/test/unit/search.js @@ -34,7 +34,7 @@ let packages = [ describe('search', function() { before(function() { - let config = Config(config_hash); + let config = new Config(config_hash); this.storage = new Storage(config); Search.configureStorage(this.storage); packages.map(function(item) {