diff --git a/lib/commands/core.js b/lib/commands/core.js index 7e34232cb..0bf7ff542 100644 --- a/lib/commands/core.js +++ b/lib/commands/core.js @@ -1,8 +1,13 @@ /*jshint esversion: 6 */ +/* globals process */ const Core = module.exports; const Util = require("../common-util"); const escapeKeyCharacters = Util.escapeKeyCharacters; +/* Use Nacl for checking signatures of messages */ +const Nacl = require("tweetnacl/nacl-fast"); + + Core.DEFAULT_LIMIT = 50 * 1024 * 1024; Core.SESSION_EXPIRATION_TIME = 60 * 1000; @@ -16,6 +21,30 @@ var makeToken = Core.makeToken = function () { .toString(16); }; +Core.makeCookie = function (token) { + var time = (+new Date()); + time -= time % 5000; + + return [ + time, + process.pid, + token + ]; +}; + +var parseCookie = function (cookie) { + if (!(cookie && cookie.split)) { return null; } + + var parts = cookie.split('|'); + if (parts.length !== 3) { return null; } + + var c = {}; + c.time = new Date(parts[0]); + c.pid = Number(parts[1]); + c.seq = parts[2]; + return c; +}; + Core.getSession = function (Sessions, key) { var safeKey = escapeKeyCharacters(key); if (Sessions[safeKey]) { @@ -30,13 +59,123 @@ Core.getSession = function (Sessions, key) { return user; }; +Core.expireSession = function (Sessions, key) { + var session = Sessions[key]; + if (!session) { return; } + if (session.blobstage) { + session.blobstage.close(); + } + delete Sessions[key]; +}; + +var isTooOld = function (time, now) { + return (now - time) > 300000; +}; + +Core.expireSessions = function (Sessions) { + var now = +new Date(); + Object.keys(Sessions).forEach(function (key) { + var session = Sessions[key]; + if (session && isTooOld(session.atime, now)) { + Core.expireSession(Sessions, key); + } + }); +}; + +var addTokenForKey = function (Sessions, publicKey, token) { + if (!Sessions[publicKey]) { throw new Error('undefined user'); } + + var user = Core.getSession(Sessions, publicKey); + user.tokens.push(token); + user.atime = +new Date(); + if (user.tokens.length > 2) { user.tokens.shift(); } +}; + +Core.isValidCookie = function (Sessions, publicKey, cookie) { + var parsed = parseCookie(cookie); + if (!parsed) { return false; } + + var now = +new Date(); + + if (!parsed.time) { return false; } + if (isTooOld(parsed.time, now)) { + return false; + } + + // different process. try harder + if (process.pid !== parsed.pid) { + return false; + } + + var user = Core.getSession(Sessions, publicKey); + if (!user) { return false; } + + var idx = user.tokens.indexOf(parsed.seq); + if (idx === -1) { return false; } + + if (idx > 0) { + // make a new token + addTokenForKey(Sessions, publicKey, Core.makeToken()); + } + + return true; +}; + +Core.checkSignature = function (Env, signedMsg, signature, publicKey) { + if (!(signedMsg && publicKey)) { return false; } + + var signedBuffer; + var pubBuffer; + var signatureBuffer; + + try { + signedBuffer = Nacl.util.decodeUTF8(signedMsg); + } catch (e) { + Env.Log.error('INVALID_SIGNED_BUFFER', signedMsg); + return null; + } + + try { + pubBuffer = Nacl.util.decodeBase64(publicKey); + } catch (e) { + return false; + } + + try { + signatureBuffer = Nacl.util.decodeBase64(signature); + } catch (e) { + return false; + } + + if (pubBuffer.length !== 32) { + Env.Log.error('PUBLIC_KEY_LENGTH', publicKey); + return false; + } + + if (signatureBuffer.length !== 64) { + return false; + } + + return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); +}; + +// E_NO_OWNERS +Core.hasOwners = function (metadata) { + return Boolean(metadata && Array.isArray(metadata.owners)); +}; + +Core.hasPendingOwners = function (metadata) { + return Boolean(metadata && Array.isArray(metadata.pending_owners)); +}; + +// INSUFFICIENT_PERMISSIONS +Core.isOwner = function (metadata, unsafeKey) { + return metadata.owners.indexOf(unsafeKey) !== -1; +}; + +Core.isPendingOwner = function (metadata, unsafeKey) { + return metadata.pending_owners.indexOf(unsafeKey) !== -1; +}; -// getChannelList -// getSession -// getHash -// getMultipleFileSize -// sumChannelSizes -// getFreeSpace -// getLimit diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index 3412f329e..16998b8b5 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -8,6 +8,8 @@ const Pinning = module.exports; const Nacl = require("tweetnacl/nacl-fast"); const Util = require("../common-util"); const nThen = require("nthen"); +const Saferphore = require("saferphore"); +const Pinned = require('../../scripts/pinned'); //const escapeKeyCharacters = Util.escapeKeyCharacters; const unescapeKeyCharacters = Util.unescapeKeyCharacters; @@ -397,3 +399,66 @@ Pinning.getFileSize = function (Env, channel, _cb) { }); }; +/* accepts a list, and returns a sublist of channel or file ids which seem + to have been deleted from the server (file size 0) + + we might consider that we should only say a file is gone if fs.stat returns + ENOENT, but for now it's simplest to just rely on getFileSize... +*/ +Pinning.getDeletedPads = function (Env, channels, cb) { + if (!Array.isArray(channels)) { return cb('INVALID_LIST'); } + var L = channels.length; + + var sem = Saferphore.create(10); + var absentees = []; + + var job = function (channel, wait) { + return function (give) { + Pinning.getFileSize(Env, channel, wait(give(function (e, size) { + if (e) { return; } + if (size === 0) { absentees.push(channel); } + }))); + }; + }; + + nThen(function (w) { + for (var i = 0; i < L; i++) { + sem.take(job(channels[i], w)); + } + }).nThen(function () { + cb(void 0, absentees); + }); +}; + +// inform that the +Pinning.loadChannelPins = function (Env) { + Pinned.load(function (err, data) { + if (err) { + Env.Log.error("LOAD_CHANNEL_PINS", err); + + // FIXME not sure what should be done here instead + Env.pinnedPads = {}; + Env.evPinnedPadsReady.fire(); + return; + } + + + Env.pinnedPads = data; + Env.evPinnedPadsReady.fire(); + }, { + pinPath: Env.paths.pin, + }); +}; + +Pinning.isChannelPinned = function (Env, channel, cb) { + Env.evPinnedPadsReady.reg(() => { + if (Env.pinnedPads[channel] && Object.keys(Env.pinnedPads[channel]).length) { + cb(true); + } else { + delete Env.pinnedPads[channel]; + cb(false); + } + }); +}; + + diff --git a/lib/commands/quota.js b/lib/commands/quota.js new file mode 100644 index 000000000..e7df14364 --- /dev/null +++ b/lib/commands/quota.js @@ -0,0 +1,111 @@ +/*jshint esversion: 6 */ +/* globals Buffer*/ +const Quota = module.exports; + +const Core = require("./commands/core"); +const Util = require("../common-util"); +const Package = require('../../package.json'); +const Https = require("https"); + +Quota.applyCustomLimits = function (Env, config) { + var isLimit = function (o) { + var valid = o && typeof(o) === 'object' && + typeof(o.limit) === 'number' && + typeof(o.plan) === 'string' && + typeof(o.note) === 'string'; + return valid; + }; + + // read custom limits from the config + 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 ''; + }); + }); + return limits; + }(config.customLimits || {})); + + Object.keys(customLimits).forEach(function (k) { + if (!isLimit(customLimits[k])) { return; } + Env.limits[k] = customLimits[k]; + }); +}; + +// The limits object contains storage limits for all the publicKey that have paid +// To each key is associated an object containing the 'limit' value and a 'note' explaining that limit +Quota.updateLimits = function (Env, config, publicKey, cb) { // FIXME BATCH?S + + if (config.adminEmail === false) { + Quota.applyCustomLimits(Env, config); + if (config.allowSubscriptions === false) { return; } + throw new Error("allowSubscriptions must be false if adminEmail is false"); + } + if (typeof cb !== "function") { cb = function () {}; } + + var defaultLimit = typeof(config.defaultStorageLimit) === 'number'? + config.defaultStorageLimit: Core.DEFAULT_LIMIT; + + var userId; + if (publicKey) { + userId = Util.unescapeKeyCharacters(publicKey); + } + + var body = JSON.stringify({ + domain: config.myDomain, + subdomain: config.mySubdomain || null, + adminEmail: config.adminEmail, + version: Package.version + }); + var options = { + host: 'accounts.cryptpad.fr', + path: '/api/getauthorized', + method: 'POST', + headers: { + "Content-Type": "application/json", + "Content-Length": Buffer.byteLength(body) + } + }; + + var req = Https.request(options, function (response) { + if (!('' + response.statusCode).match(/^2\d\d$/)) { + return void cb('SERVER ERROR ' + response.statusCode); + } + var str = ''; + + response.on('data', function (chunk) { + str += chunk; + }); + + response.on('end', function () { + try { + var json = JSON.parse(str); + Env.limits = json; + Quota.applyCustomLimits(Env, config); + + var l; + if (userId) { + var limit = Env.limits[userId]; + l = limit && typeof limit.limit === "number" ? + [limit.limit, limit.plan, limit.note] : [defaultLimit, '', '']; + } + cb(void 0, l); + } catch (e) { + cb(e); + } + }); + }); + + req.on('error', function (e) { + Quota.applyCustomLimits(Env, config); + if (!config.domain) { return cb(); } + cb(e); + }); + + req.end(body); +}; + + diff --git a/lib/rpc.js b/lib/rpc.js index a064ebe64..cbaad1ee2 100644 --- a/lib/rpc.js +++ b/lib/rpc.js @@ -1,32 +1,26 @@ -/*@flow*/ /*jshint esversion: 6 */ /* Use Nacl for checking signatures of messages */ var Nacl = require("tweetnacl/nacl-fast"); /* globals Buffer*/ -/* globals process */ var Fs = require("fs"); var Fse = require("fs-extra"); var Path = require("path"); -var Https = require("https"); -const Package = require('../package.json'); -const Pinned = require('../scripts/pinned'); -const Saferphore = require("saferphore"); const nThen = require("nthen"); const Meta = require("./metadata"); const WriteQueue = require("./write-queue"); const BatchRead = require("./batch-read"); -const Core = require("./commands/core"); const Util = require("./common-util"); const escapeKeyCharacters = Util.escapeKeyCharacters; -const unescapeKeyCharacters = Util.unescapeKeyCharacters; const mkEvent = Util.mkEvent; +const Core = require("./commands/core"); const Admin = require("./commands/admin-rpc"); const Pinning = require("./commands/pin-rpc"); +const Quota = require("./commands/quota"); var RPC = module.exports; @@ -45,130 +39,6 @@ var WARN = function (e, output) { } }; -var makeCookie = function (token) { - var time = (+new Date()); - time -= time % 5000; - - return [ - time, - process.pid, - token - ]; -}; - -var parseCookie = function (cookie) { - if (!(cookie && cookie.split)) { return null; } - - var parts = cookie.split('|'); - if (parts.length !== 3) { return null; } - - var c = {}; - c.time = new Date(parts[0]); - c.pid = Number(parts[1]); - c.seq = parts[2]; - return c; -}; - -var isTooOld = function (time, now) { - return (now - time) > 300000; -}; - -var expireSession = function (Sessions, key) { - var session = Sessions[key]; - if (!session) { return; } - if (session.blobstage) { - session.blobstage.close(); - } - delete Sessions[key]; -}; - -var expireSessions = function (Sessions) { - var now = +new Date(); - Object.keys(Sessions).forEach(function (key) { - var session = Sessions[key]; - if (session && isTooOld(session.atime, now)) { - expireSession(Sessions, key); - } - }); -}; - -var addTokenForKey = function (Sessions, publicKey, token) { - if (!Sessions[publicKey]) { throw new Error('undefined user'); } - - var user = Core.getSession(Sessions, publicKey); - user.tokens.push(token); - user.atime = +new Date(); - if (user.tokens.length > 2) { user.tokens.shift(); } -}; - -var isValidCookie = function (Sessions, publicKey, cookie) { - var parsed = parseCookie(cookie); - if (!parsed) { return false; } - - var now = +new Date(); - - if (!parsed.time) { return false; } - if (isTooOld(parsed.time, now)) { - return false; - } - - // different process. try harder - if (process.pid !== parsed.pid) { - return false; - } - - var user = Core.getSession(Sessions, publicKey); - if (!user) { return false; } - - var idx = user.tokens.indexOf(parsed.seq); - if (idx === -1) { return false; } - - if (idx > 0) { - // make a new token - addTokenForKey(Sessions, publicKey, Core.makeToken()); - } - - return true; -}; - -var checkSignature = function (signedMsg, signature, publicKey) { - if (!(signedMsg && publicKey)) { return false; } - - var signedBuffer; - var pubBuffer; - var signatureBuffer; - - try { - signedBuffer = Nacl.util.decodeUTF8(signedMsg); - } catch (e) { - Log.error('INVALID_SIGNED_BUFFER', signedMsg); - return null; - } - - try { - pubBuffer = Nacl.util.decodeBase64(publicKey); - } catch (e) { - return false; - } - - try { - signatureBuffer = Nacl.util.decodeBase64(signature); - } catch (e) { - return false; - } - - if (pubBuffer.length !== 32) { - Log.error('PUBLIC_KEY_LENGTH', publicKey); - return false; - } - - if (signatureBuffer.length !== 64) { - return false; - } - - return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); -}; - const batchMetadata = BatchRead("GET_METADATA"); var getMetadata = function (Env, channel, cb) { if (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); } @@ -188,24 +58,6 @@ var getMetadata = function (Env, channel, cb) { }); }; -// E_NO_OWNERS -var hasOwners = function (metadata) { - return Boolean(metadata && Array.isArray(metadata.owners)); -}; - -var hasPendingOwners = function (metadata) { - return Boolean(metadata && Array.isArray(metadata.pending_owners)); -}; - -// INSUFFICIENT_PERMISSIONS -var isOwner = function (metadata, unsafeKey) { - return metadata.owners.indexOf(unsafeKey) !== -1; -}; - -var isPendingOwner = function (metadata, unsafeKey) { - return metadata.pending_owners.indexOf(unsafeKey) !== -1; -}; - /* setMetadata - write a new line to the metadata log if a valid command is provided - data is an object: { @@ -228,7 +80,7 @@ var setMetadata = function (Env, data, unsafeKey, cb) { cb(err); return void next(); } - if (!hasOwners(metadata)) { + if (!Core.hasOwners(metadata)) { cb('E_NO_OWNERS'); return void next(); } @@ -243,9 +95,9 @@ var setMetadata = function (Env, data, unsafeKey, cb) { // Confirm that the channel is owned by the user in question // or the user is accepting a pending ownership offer - if (hasPendingOwners(metadata) && - isPendingOwner(metadata, unsafeKey) && - !isOwner(metadata, unsafeKey)) { + if (Core.hasPendingOwners(metadata) && + Core.isPendingOwner(metadata, unsafeKey) && + !Core.isOwner(metadata, unsafeKey)) { // If you are a pending owner, make sure you can only add yourelf as an owner if ((command !== 'ADD_OWNERS' && command !== 'RM_PENDING_OWNERS') @@ -258,7 +110,7 @@ var setMetadata = function (Env, data, unsafeKey, cb) { // FIXME wacky fallthrough is hard to read // we could pass this off to a writeMetadataCommand function // and make the flow easier to follow - } else if (!isOwner(metadata, unsafeKey)) { + } else if (!Core.isOwner(metadata, unsafeKey)) { cb('INSUFFICIENT_PERMISSIONS'); return void next(); } @@ -291,169 +143,6 @@ var setMetadata = function (Env, data, unsafeKey, cb) { }); }; -/* accepts a list, and returns a sublist of channel or file ids which seem - to have been deleted from the server (file size 0) - - we might consider that we should only say a file is gone if fs.stat returns - ENOENT, but for now it's simplest to just rely on getFileSize... -*/ -var getDeletedPads = function (Env, channels, cb) { - if (!Array.isArray(channels)) { return cb('INVALID_LIST'); } - var L = channels.length; - - var sem = Saferphore.create(10); - var absentees = []; - - var job = function (channel, wait) { - return function (give) { - Pinning.getFileSize(Env, channel, wait(give(function (e, size) { - if (e) { return; } - if (size === 0) { absentees.push(channel); } - }))); - }; - }; - - nThen(function (w) { - for (var i = 0; i < L; i++) { - sem.take(job(channels[i], w)); - } - }).nThen(function () { - cb(void 0, absentees); - }); -}; - -var applyCustomLimits = function (Env, config) { - var isLimit = function (o) { - var valid = o && typeof(o) === 'object' && - typeof(o.limit) === 'number' && - typeof(o.plan) === 'string' && - typeof(o.note) === 'string'; - return valid; - }; - - // read custom limits from the config - var customLimits = (function (custom) { - var limits = {}; - Object.keys(custom).forEach(function (k) { - k.replace(/\/([^\/]+)$/, function (all, safeKey) { - var id = unescapeKeyCharacters(safeKey || ''); - limits[id] = custom[k]; - return ''; - }); - }); - return limits; - }(config.customLimits || {})); - - Object.keys(customLimits).forEach(function (k) { - if (!isLimit(customLimits[k])) { return; } - Env.limits[k] = customLimits[k]; - }); -}; - -// The limits object contains storage limits for all the publicKey that have paid -// To each key is associated an object containing the 'limit' value and a 'note' explaining that limit -var updateLimits = function (Env, config, publicKey, cb /*:(?string, ?any[])=>void*/) { // FIXME BATCH? - - if (config.adminEmail === false) { - applyCustomLimits(Env, config); - if (config.allowSubscriptions === false) { return; } - throw new Error("allowSubscriptions must be false if adminEmail is false"); - } - if (typeof cb !== "function") { cb = function () {}; } - - var defaultLimit = typeof(config.defaultStorageLimit) === 'number'? - config.defaultStorageLimit: Core.DEFAULT_LIMIT; - - var userId; - if (publicKey) { - userId = unescapeKeyCharacters(publicKey); - } - - var body = JSON.stringify({ - domain: config.myDomain, - subdomain: config.mySubdomain || null, - adminEmail: config.adminEmail, - version: Package.version - }); - var options = { - host: 'accounts.cryptpad.fr', - path: '/api/getauthorized', - method: 'POST', - headers: { - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(body) - } - }; - - var req = Https.request(options, function (response) { - if (!('' + response.statusCode).match(/^2\d\d$/)) { - return void cb('SERVER ERROR ' + response.statusCode); - } - var str = ''; - - response.on('data', function (chunk) { - str += chunk; - }); - - response.on('end', function () { - try { - var json = JSON.parse(str); - Env.limits = json; - applyCustomLimits(Env, config); - - var l; - if (userId) { - var limit = Env.limits[userId]; - l = limit && typeof limit.limit === "number" ? - [limit.limit, limit.plan, limit.note] : [defaultLimit, '', '']; - } - cb(void 0, l); - } catch (e) { - cb(e); - } - }); - }); - - req.on('error', function (e) { - applyCustomLimits(Env, config); - if (!config.domain) { return cb(); } - cb(e); - }); - - req.end(body); -}; - -// inform that the -var loadChannelPins = function (Env) { - Pinned.load(function (err, data) { - if (err) { - Log.error("LOAD_CHANNEL_PINS", err); - - // FIXME not sure what should be done here instead - Env.pinnedPads = {}; - Env.evPinnedPadsReady.fire(); - return; - } - - - Env.pinnedPads = data; - Env.evPinnedPadsReady.fire(); - }, { - pinPath: Env.paths.pin, - }); -}; - -var isChannelPinned = function (Env, channel, cb) { - Env.evPinnedPadsReady.reg(() => { - if (Env.pinnedPads[channel] && Object.keys(Env.pinnedPads[channel]).length) { - cb(true); - } else { - delete Env.pinnedPads[channel]; - cb(false); - } - }); -}; - var clearOwnedChannel = function (Env, channelId, unsafeKey, cb) { if (typeof(channelId) !== 'string' || channelId.length !== 32) { return cb('INVALID_ARGUMENTS'); @@ -461,9 +150,9 @@ var clearOwnedChannel = function (Env, channelId, unsafeKey, cb) { getMetadata(Env, channelId, function (err, metadata) { if (err) { return void cb(err); } - if (!hasOwners(metadata)) { return void cb('E_NO_OWNERS'); } + if (!Core.hasOwners(metadata)) { return void cb('E_NO_OWNERS'); } // Confirm that the channel is owned by the user in question - if (!isOwner(metadata, unsafeKey)) { + if (!Core.isOwner(metadata, unsafeKey)) { return void cb('INSUFFICIENT_PERMISSIONS'); } return void Env.msgStore.clearChannel(channelId, function (e) { @@ -520,8 +209,8 @@ var removeOwnedChannel = function (Env, channelId, unsafeKey, cb) { getMetadata(Env, channelId, function (err, metadata) { if (err) { return void cb(err); } - if (!hasOwners(metadata)) { return void cb('E_NO_OWNERS'); } - if (!isOwner(metadata, unsafeKey)) { + if (!Core.hasOwners(metadata)) { return void cb('E_NO_OWNERS'); } + if (!Core.isOwner(metadata, unsafeKey)) { return void cb('INSUFFICIENT_PERMISSIONS'); } // temporarily archive the file @@ -540,11 +229,11 @@ var removeOwnedChannelHistory = function (Env, channelId, unsafeKey, hash, cb) { nThen(function (w) { getMetadata(Env, channelId, w(function (err, metadata) { if (err) { return void cb(err); } - if (!hasOwners(metadata)) { + if (!Core.hasOwners(metadata)) { w.abort(); return void cb('E_NO_OWNERS'); } - if (!isOwner(metadata, unsafeKey)) { + if (!Core.isOwner(metadata, unsafeKey)) { w.abort(); return void cb("INSUFFICIENT_PERMISSIONS"); } @@ -956,7 +645,7 @@ RPC.create = function (config, cb) { respond(e, [null, dict, null]); }); case 'GET_DELETED_PADS': - return void getDeletedPads(Env, msg[1], function (e, list) { + return void Pinning.getDeletedPads(Env, msg[1], function (e, list) { if (e) { WARN(e, msg[1]); return respond(e); @@ -964,7 +653,7 @@ RPC.create = function (config, cb) { respond(e, [null, list, null]); }); case 'IS_CHANNEL_PINNED': - return void isChannelPinned(Env, msg[1], function (isPinned) { + return void Pinning.isChannelPinned(Env, msg[1], function (isPinned) { respond(null, [null, isPinned, null]); }); case 'IS_NEW_CHANNEL': @@ -1014,7 +703,7 @@ RPC.create = function (config, cb) { } var cookie = msg[0]; - if (!isValidCookie(Sessions, publicKey, cookie)) { + if (!Core.isValidCookie(Sessions, publicKey, cookie)) { // no cookie is fine if the RPC is to get a cookie if (msg[1] !== 'COOKIE') { return void respond('NO_COOKIE'); @@ -1028,7 +717,7 @@ RPC.create = function (config, cb) { } if (isAuthenticatedCall(msg[1])) { - if (checkSignature(serialized, signature, publicKey) !== true) { + if (Core.checkSignature(Env, serialized, signature, publicKey) !== true) { return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY"); } } else if (msg[1] !== 'UPLOAD') { @@ -1052,7 +741,7 @@ RPC.create = function (config, cb) { var Respond = function (e, msg) { var session = Sessions[safeKey]; var token = session? session.tokens.slice(-1)[0]: ''; - var cookie = makeCookie(token).join('|'); + var cookie = Core.makeCookie(token).join('|'); respond(e ? String(e): e, [cookie].concat(typeof(msg) !== 'undefined' ?msg: [])); }; @@ -1093,7 +782,7 @@ RPC.create = function (config, cb) { Respond(e, size); }); case 'UPDATE_LIMITS': - return void updateLimits(Env, config, safeKey, function (e, limit) { + return void Quota.updateLimits(Env, config, safeKey, function (e, limit) { if (e) { WARN(e, limit); return void Respond(e); @@ -1110,7 +799,7 @@ RPC.create = function (config, cb) { }); case 'EXPIRE_SESSION': return void setTimeout(function () { - expireSession(Sessions, safeKey); + Core.expireSession(Sessions, safeKey); Respond(void 0, "OK"); }); case 'CLEAR_OWNED_CHANNEL': @@ -1223,17 +912,17 @@ RPC.create = function (config, cb) { }; var updateLimitDaily = function () { - updateLimits(Env, config, undefined, function (e) { + Quota.updateLimits(Env, config, undefined, function (e) { if (e) { WARN('limitUpdate', e); } }); }; - applyCustomLimits(Env, config); + Quota.applyCustomLimits(Env, config); updateLimitDaily(); setInterval(updateLimitDaily, 24*3600*1000); - loadChannelPins(Env); + Pinning.loadChannelPins(Env); nThen(function (w) { Store.create({ @@ -1257,7 +946,7 @@ RPC.create = function (config, cb) { // expire old sessions once per minute // XXX allow for graceful shutdown Env.sessionExpirationInterval = setInterval(function () { - expireSessions(Sessions); + Core.expireSessions(Sessions); }, Core.SESSION_EXPIRATION_TIME); }); };