From ebcc9a069b54090f1f1879fc9aa741258d1a52e8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 25 Jun 2020 13:14:26 -0400 Subject: [PATCH] add server-side support for the new format of public signing keys --- lib/commands/quota.js | 18 +++++++--- lib/keys.js | 81 +++++++++++++++++++++++++++++++++++++++++++ server.js | 9 +++-- 3 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 lib/keys.js diff --git a/lib/commands/quota.js b/lib/commands/quota.js index 5c39a8d93..97213e02b 100644 --- a/lib/commands/quota.js +++ b/lib/commands/quota.js @@ -3,6 +3,7 @@ const Quota = module.exports; const Util = require("../common-util"); +const Keys = require("../keys"); const Package = require('../../package.json'); const Https = require("https"); @@ -19,11 +20,18 @@ Quota.applyCustomLimits = function (Env) { var customLimits = (function (custom) { var limits = {}; Object.keys(custom).forEach(function (k) { - k.replace(/\/([^\/]+)$/, function (all, safeKey) { - var id = Util.unescapeKeyCharacters(safeKey || ''); - limits[id] = custom[k]; - return ''; - }); + var user; + try { + user = Keys.parseUser(k); + } catch (err) { + return void Env.Log.error("PARSE_CUSTOM_LIMIT_BLOCK", { + user: k, + error: err.message, + }); + } + + var unsafeKey = user.pubkey; + limits[unsafeKey] = custom[k]; }); return limits; }(Env.customLimits || {})); diff --git a/lib/keys.js b/lib/keys.js new file mode 100644 index 000000000..c4be44c85 --- /dev/null +++ b/lib/keys.js @@ -0,0 +1,81 @@ +(function () { +var factory = function () { + var Keys = {}; + +/* Parse the new format of "Signing Public Keys". + If anything about the input is found to be invalid, return; + this will fall back to the old parsing method + + +*/ + var parseNewUser = function (userString) { + if (!/^\[.*?@.*\]$/.test(userString)) { return; } + var temp = userString.slice(1, -1); + var domain, username, pubkey; + + temp = temp + .replace(/\/([a-zA-Z0-9+-]{43}=)$/, function (all, k) { + pubkey = k.replace(/-/g, '/'); + return ''; + }); + if (!pubkey) { return; } + + var index = temp.lastIndexOf('@'); + if (index < 1) { return; } + + domain = temp.slice(index + 1); + username = temp.slice(0, index); + + return { + domain: domain, + user: username, + pubkey: pubkey + }; + }; + + var isValidUser = function (parsed) { + if (!parsed) { return; } + if (!(parsed.domain && parsed.user && parsed.pubkey)) { return; } + return true; + }; + + Keys.parseUser = function (user) { + var parsed = parseNewUser(user); + if (isValidUser(parsed)) { return parsed; } + + var domain, username, pubkey; + user.replace(/^https*:\/\/([^\/]+)\/user\/#\/1\/([^\/]+)\/([a-zA-Z0-9+-]{43}=)$/, + function (a, d, u, k) { + domain = d; + username = u; + pubkey = k.replace(/-/g, '/'); + return ''; + }); + if (!domain) { throw new Error("Could not parse user id [" + user + "]"); } + return { + domain: domain, + user: username, + pubkey: pubkey + }; + }; + + Keys.serialize = function (origin, username, pubkey) { + return '[' + + username + + '@' + + origin.replace(/https*:\/\//, '') + + '/' + + pubkey.replace(/\//g, '-') + + ']'; + // return origin + '/user/#/1/' + username + '/' + pubkey.replace(/\//g, '-'); + }; + + return Keys; +}; + + if (typeof(module) !== 'undefined' && module.exports) { + module.exports = factory(); + } else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) { + define([], factory); + } +}()); diff --git a/server.js b/server.js index 8508eba83..b721afa86 100644 --- a/server.js +++ b/server.js @@ -9,6 +9,7 @@ var Path = require("path"); var nThen = require("nthen"); var Util = require("./lib/common-util"); var Default = require("./lib/defaults"); +var Keys = require("./lib/keys"); var config = require("./lib/load-config"); @@ -201,9 +202,11 @@ app.use(/^\/[^\/]*$/, Express.static('customize.dist')); var admins = []; try { admins = (config.adminKeys || []).map(function (k) { - k = k.replace(/\/+$/, ''); - var s = k.split('/'); - return s[s.length-1].replace(/-/g, '/'); + // return each admin's "unsafeKey" + // this might throw and invalidate all the other admin's keys + // but we want to get the admin's attention anyway. + // breaking everything is a good way to accomplish that. + return Keys.parseUser(k).pubkey; }); } catch (e) { console.error("Can't parse admin keys"); }