From b60658ee818eaeacb90044e5a3a542213bc36d01 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 10 Aug 2018 09:06:16 +0000 Subject: [PATCH] move account db to own file --- lib/extensions/db.js | 235 ++++++++++++++++++++++++++++++++++++++++ lib/extensions/index.js | 224 +------------------------------------- 2 files changed, 236 insertions(+), 223 deletions(-) create mode 100644 lib/extensions/db.js diff --git a/lib/extensions/db.js b/lib/extensions/db.js new file mode 100644 index 0000000..de72d8f --- /dev/null +++ b/lib/extensions/db.js @@ -0,0 +1,235 @@ +'use strict'; + +var PromiseA; +try { + PromiseA = require('bluebird'); +} catch(e) { + PromiseA = global.Promise; +} + +var path = require('path'); +var sfs = require('safe-replace'); + +var DB = module.exports = {}; +DB._savefile = path.join(__dirname, 'permissions.json'); +DB._load = function () { + try { + DB._perms = require(DB._savefile); + } catch(e) { + try { + DB._perms = require(DB._savefile + '.bak'); + } catch(e) { + DB._perms = []; + } + } + DB._byDomain = {}; + DB._byPort = {}; + DB._byEmail = {}; + DB._byPpid = {}; + DB._byId = {}; + DB._grants = {}; + DB._grantsMap = {}; + DB._perms.forEach(function (acc) { + if (acc.id) { + // if account has an id + DB._byId[acc.id] = acc; + if (!DB._grants[acc.id]) { + DB._grantsMap[acc.id] = {}; + DB._grants[acc.id] = []; + } + acc.domains.forEach(function (d) { + DB._grants[d.name + '|id|' + acc.id] = true; + if (!DB._grantsMap[acc.id][d.name]) { + DB._grantsMap[acc.id][d.name] = d; + DB._grants[acc.id].push(d); + } + }); + acc.ports.forEach(function (p) { + DB._grants[p.number + '|id|' + acc.id] = true; + if (!DB._grantsMap[acc.id][p.number]) { + DB._grantsMap[acc.id][p.number] = p; + DB._grants[acc.id].push(p); + } + }); + } else if (acc.nodes[0] && 'email' === acc.nodes[0].type) { + // if primary (first) node is email + //console.log("XXXX email", acc.nodes[0].name); + if (!DB._byEmail[acc.nodes[0].name]) { + DB._byEmail[acc.nodes[0].name] = { + account: acc + , node: acc.nodes[0] + }; + } + } + // map domains to all nodes that have permission + // (which permission could be granted by more than one account) + acc.nodes.forEach(function (node) { + if ('mailto' === node.scheme || 'email' === node.type) { + if (!DB._grants[node.name]) { + DB._grantsMap[node.name] = {}; + DB._grants[node.name] = []; + } + acc.domains.forEach(function (d) { + DB._grants[d.name + '|' + (node.scheme||node.type) + '|' + node.name] = true; + if (!DB._grantsMap[node.name][d.name]) { + DB._grantsMap[node.name][d.name] = d; + DB._grants[node.name].push(d); + } + }); + acc.ports.forEach(function (p) { + DB._grants[p.number + '|' + (node.scheme||node.type) + '|' + node.name] = true; + if (!DB._grantsMap[node.name][p.number]) { + DB._grantsMap[node.name][p.number] = p; + DB._grants[node.name].push(p); + } + }); + } + }); + // TODO this also should be maps/arrays (... or just normal database) + acc.domains.forEach(function (domain) { + if (DB._byDomain[domain.name]) { + console.warn("duplicate domain '" + domain.name + "'"); + console.warn("::existing account '" + acc.nodes.map(function (node) { return node.name; }) + "'"); + console.warn("::new account '" + DB._byDomain[domain.name].account.nodes.map(function (node) { return node.name; }) + "'"); + } + DB._byDomain[domain.name] = { + account: acc + , domain: domain + }; + }); + acc.ports.forEach(function (port) { + if (DB._byPort[port.number]) { + console.warn("duplicate port '" + port.number + "'"); + console.warn("::existing account '" + acc.nodes.map(function (node) { return node.name; }) + "'"); + console.warn("::new account '" + DB._byPort[port.number].account.nodes.map(function (node) { return node.name; }) + "'"); + } + DB._byPort[port.number] = { + account: acc + , port: port + }; + }); + }); +}; +DB._load(); +DB.accounts = {}; +DB.accounts.get = function (obj) { + return PromiseA.resolve().then(function () { + //console.log('XXXX obj.name', DB._byEmail[obj.name]); + return DB._byId[obj.name] || (DB._byEmail[obj.name] || {}).account || null; + }); +}; +DB.accounts.add = function (obj) { + return PromiseA.resolve().then(function () { + if (obj.id) { + // TODO more checks + DB._perms.push(obj); + } else if ('email' === obj.nodes[0].type || obj.email) { + obj.email = undefined; + DB._perms.push(obj); + } + }); +}; +DB.domains = {}; +DB.domains.available = function (name) { + return PromiseA.resolve().then(function () { + return !DB._byDomain[name]; + }); +}; +DB.domains._add = function (acc, opts) { + // TODO verifications to change ownership of a domain + return PromiseA.resolve().then(function () { + var err; + //var acc = DB._byId[aid]; + var domain = { + name: (opts.domain || opts.name) + , hostname: opts.hostname + , os: opts.os + , createdAt: new Date().toISOString() + , wildcard: opts.wildcard + }; + var pdomain; + var parts = (opts.domain || domain.name).split('.').map(function (el, i, arr) { + return arr.slice(i).join('.'); + }).reverse(); + parts.shift(); + parts.pop(); + if (parts.some(function (part) { + if (DB._byDomain[part]) { + pdomain = part; + return true; + } + })) { + err = new Error("'" + domain.name + "' exists as '" + pdomain + "' and therefore requires an admin to review and approve"); + err.code = "E_REQ_ADMIN"; + throw err; + } + if (DB._byDomain[domain.name]) { + if (acc !== DB._byDomain[domain.name].account) { + throw new Error("domain '" + domain.name + "' exists"); + } + // happily ignore non-change + return; + } + DB._byDomain[domain.name] = { + account: acc + , domain: domain + }; + acc.domains.push(domain); + }); +}; +DB.ports = {}; +DB.ports.available = function (number) { + return PromiseA.resolve().then(function () { + return !DB._byPort[number]; + }); +}; +DB.ports._add = function (acc, opts) { + return PromiseA.resolve().then(function () { + //var acc = DB._byId[aid]; + var port = { + number: opts.port || opts.number + , hostname: opts.hostname + , os: opts.os + , createdAt: new Date().toISOString() + }; + if (DB._byPort[port.number]) { + // TODO verifications + throw new Error("port '" + port.number + "' exists"); + } + DB._byPort[port.number] = { + account: acc + , port: port + }; + acc.ports.push(port); + }); +}; +DB._save = function () { + return sfs.writeFileAsync(DB._savefile, JSON.stringify(DB._perms)); +}; +DB._saveToken = null; +DB._savePromises = []; +DB._savePromise = PromiseA.resolve(); +DB.save = function () { + clearTimeout(DB._saveToken); + return new PromiseA(function (resolve, reject) { + function doSave() { + DB._savePromise = DB._savePromise.then(function () { + return DB._save().then(function (yep) { + DB._savePromises.forEach(function (p) { + p.resolve(yep); + }); + DB._savePromises.length = 1; + }, function (err) { + DB._savePromises.forEach(function (p) { + p.reject(err); + }); + DB._savePromises.length = 1; + }); + }); + return DB._savePromise; + } + + DB._saveToken = setTimeout(doSave, 2500); + DB._savePromises.push({ resolve: resolve, reject: reject }); + }); +}; diff --git a/lib/extensions/index.js b/lib/extensions/index.js index 9638c80..604f144 100644 --- a/lib/extensions/index.js +++ b/lib/extensions/index.js @@ -18,229 +18,7 @@ var requestAsync = util.promisify(require('@coolaj86/urequest')); //var readFileAsync = util.promisify(fs.readFile); var mkdirpAsync = util.promisify(require('mkdirp')); var TRUSTED_ISSUERS = [ 'oauth3.org' ]; -var DB = {}; -DB._savefile = path.join(__dirname, 'permissions.json'); -DB._load = function () { - try { - DB._perms = require(DB._savefile); - } catch(e) { - try { - DB._perms = require(DB._savefile + '.bak'); - } catch(e) { - DB._perms = []; - } - } - DB._byDomain = {}; - DB._byPort = {}; - DB._byEmail = {}; - DB._byPpid = {}; - DB._byId = {}; - DB._grants = {}; - DB._grantsMap = {}; - DB._perms.forEach(function (acc) { - if (acc.id) { - // if account has an id - DB._byId[acc.id] = acc; - if (!DB._grants[acc.id]) { - DB._grantsMap[acc.id] = {}; - DB._grants[acc.id] = []; - } - acc.domains.forEach(function (d) { - DB._grants[d.name + '|id|' + acc.id] = true; - if (!DB._grantsMap[acc.id][d.name]) { - DB._grantsMap[acc.id][d.name] = d; - DB._grants[acc.id].push(d); - } - }); - acc.ports.forEach(function (p) { - DB._grants[p.number + '|id|' + acc.id] = true; - if (!DB._grantsMap[acc.id][p.number]) { - DB._grantsMap[acc.id][p.number] = p; - DB._grants[acc.id].push(p); - } - }); - } else if (acc.nodes[0] && 'email' === acc.nodes[0].type) { - // if primary (first) node is email - //console.log("XXXX email", acc.nodes[0].name); - if (!DB._byEmail[acc.nodes[0].name]) { - DB._byEmail[acc.nodes[0].name] = { - account: acc - , node: acc.nodes[0] - }; - } - } - // map domains to all nodes that have permission - // (which permission could be granted by more than one account) - acc.nodes.forEach(function (node) { - if ('mailto' === node.scheme || 'email' === node.type) { - if (!DB._grants[node.name]) { - DB._grantsMap[node.name] = {}; - DB._grants[node.name] = []; - } - acc.domains.forEach(function (d) { - DB._grants[d.name + '|' + (node.scheme||node.type) + '|' + node.name] = true; - if (!DB._grantsMap[node.name][d.name]) { - DB._grantsMap[node.name][d.name] = d; - DB._grants[node.name].push(d); - } - }); - acc.ports.forEach(function (p) { - DB._grants[p.number + '|' + (node.scheme||node.type) + '|' + node.name] = true; - if (!DB._grantsMap[node.name][p.number]) { - DB._grantsMap[node.name][p.number] = p; - DB._grants[node.name].push(p); - } - }); - } - }); - // TODO this also should be maps/arrays (... or just normal database) - acc.domains.forEach(function (domain) { - if (DB._byDomain[domain.name]) { - console.warn("duplicate domain '" + domain.name + "'"); - console.warn("::existing account '" + acc.nodes.map(function (node) { return node.name; }) + "'"); - console.warn("::new account '" + DB._byDomain[domain.name].account.nodes.map(function (node) { return node.name; }) + "'"); - } - DB._byDomain[domain.name] = { - account: acc - , domain: domain - }; - }); - acc.ports.forEach(function (port) { - if (DB._byPort[port.number]) { - console.warn("duplicate port '" + port.number + "'"); - console.warn("::existing account '" + acc.nodes.map(function (node) { return node.name; }) + "'"); - console.warn("::new account '" + DB._byPort[port.number].account.nodes.map(function (node) { return node.name; }) + "'"); - } - DB._byPort[port.number] = { - account: acc - , port: port - }; - }); - }); -}; -DB._load(); -DB.accounts = {}; -DB.accounts.get = function (obj) { - return PromiseA.resolve().then(function () { - //console.log('XXXX obj.name', DB._byEmail[obj.name]); - return DB._byId[obj.name] || (DB._byEmail[obj.name] || {}).account || null; - }); -}; -DB.accounts.add = function (obj) { - return PromiseA.resolve().then(function () { - if (obj.id) { - // TODO more checks - DB._perms.push(obj); - } else if ('email' === obj.nodes[0].type || obj.email) { - obj.email = undefined; - DB._perms.push(obj); - } - }); -}; -DB.domains = {}; -DB.domains.available = function (name) { - return PromiseA.resolve().then(function () { - return !DB._byDomain[name]; - }); -}; -DB.domains._add = function (acc, opts) { - // TODO verifications to change ownership of a domain - return PromiseA.resolve().then(function () { - var err; - //var acc = DB._byId[aid]; - var domain = { - name: (opts.domain || opts.name) - , hostname: opts.hostname - , os: opts.os - , createdAt: new Date().toISOString() - , wildcard: opts.wildcard - }; - var pdomain; - var parts = (opts.domain || domain.name).split('.').map(function (el, i, arr) { - return arr.slice(i).join('.'); - }).reverse(); - parts.shift(); - parts.pop(); - if (parts.some(function (part) { - if (DB._byDomain[part]) { - pdomain = part; - return true; - } - })) { - err = new Error("'" + domain.name + "' exists as '" + pdomain + "' and therefore requires an admin to review and approve"); - err.code = "E_REQ_ADMIN"; - throw err; - } - if (DB._byDomain[domain.name]) { - if (acc !== DB._byDomain[domain.name].account) { - throw new Error("domain '" + domain.name + "' exists"); - } - // happily ignore non-change - return; - } - DB._byDomain[domain.name] = { - account: acc - , domain: domain - }; - acc.domains.push(domain); - }); -}; -DB.ports = {}; -DB.ports.available = function (number) { - return PromiseA.resolve().then(function () { - return !DB._byPort[number]; - }); -}; -DB.ports._add = function (acc, opts) { - return PromiseA.resolve().then(function () { - //var acc = DB._byId[aid]; - var port = { - number: opts.port || opts.number - , hostname: opts.hostname - , os: opts.os - , createdAt: new Date().toISOString() - }; - if (DB._byPort[port.number]) { - // TODO verifications - throw new Error("port '" + port.number + "' exists"); - } - DB._byPort[port.number] = { - account: acc - , port: port - }; - acc.ports.push(port); - }); -}; -DB._save = function () { - return sfs.writeFileAsync(DB._savefile, JSON.stringify(DB._perms)); -}; -DB._saveToken = null; -DB._savePromises = []; -DB._savePromise = PromiseA.resolve(); -DB.save = function () { - clearTimeout(DB._saveToken); - return new PromiseA(function (resolve, reject) { - function doSave() { - DB._savePromise = DB._savePromise.then(function () { - return DB._save().then(function (yep) { - DB._savePromises.forEach(function (p) { - p.resolve(yep); - }); - DB._savePromises.length = 1; - }, function (err) { - DB._savePromises.forEach(function (p) { - p.reject(err); - }); - DB._savePromises.length = 1; - }); - }); - return DB._savePromise; - } - - DB._saveToken = setTimeout(doSave, 2500); - DB._savePromises.push({ resolve: resolve, reject: reject }); - }); -}; +var DB = require('./db.js'); var _auths = module.exports._auths = {}; var Auths = {};