move account db to own file
This commit is contained in:
		
							parent
							
								
									f54c4dde7a
								
							
						
					
					
						commit
						b60658ee81
					
				
							
								
								
									
										235
									
								
								lib/extensions/db.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								lib/extensions/db.js
									
									
									
									
									
										Normal file
									
								
							| @ -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 }); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| @ -18,229 +18,7 @@ var requestAsync = util.promisify(require('@coolaj86/urequest')); | |||||||
| //var readFileAsync = util.promisify(fs.readFile);
 | //var readFileAsync = util.promisify(fs.readFile);
 | ||||||
| var mkdirpAsync = util.promisify(require('mkdirp')); | var mkdirpAsync = util.promisify(require('mkdirp')); | ||||||
| var TRUSTED_ISSUERS = [ 'oauth3.org' ]; | var TRUSTED_ISSUERS = [ 'oauth3.org' ]; | ||||||
| var DB = {}; | var DB = require('./db.js'); | ||||||
| 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 _auths = module.exports._auths = {}; | var _auths = module.exports._auths = {}; | ||||||
| var Auths = {}; | var Auths = {}; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user