From 6ac056e314907725e79550f7d2066bbe15e8df25 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 3 Jul 2017 11:38:39 +0200 Subject: [PATCH] make explicit file size RPCs unauthenticated --- rpc.js | 64 +++++++++++++++++++-- www/common/cryptpad-common.js | 43 +++++++++++++- www/common/pinpad.js | 15 ----- www/common/rpc.js | 105 +++++++++++++++++++++++++++++++++- 4 files changed, 201 insertions(+), 26 deletions(-) diff --git a/rpc.js b/rpc.js index d00ee93b7..2260c2c53 100644 --- a/rpc.js +++ b/rpc.js @@ -281,7 +281,7 @@ var getUploadSize = function (Env, channel, cb) { var paths = Env.paths; var path = makeFilePath(paths.blob, channel); if (!path) { - return cb('INVALID_UPLOAD_ID'); + return cb('INVALID_UPLOAD_ID', path); } Fs.stat(path, function (err, stats) { @@ -826,6 +826,13 @@ var upload_status = function (Env, publicKey, filesize, cb) { }); }; +var isUnauthenticatedCall = function (call) { + return [ + 'GET_FILE_SIZE', + 'GET_MULTIPLE_FILE_SIZE', + ].indexOf(call) !== -1; +}; + var isAuthenticatedCall = function (call) { return [ 'COOKIE', @@ -834,11 +841,8 @@ var isAuthenticatedCall = function (call) { 'UNPIN', 'GET_HASH', 'GET_TOTAL_SIZE', - 'GET_FILE_SIZE', 'UPDATE_LIMITS', 'GET_LIMIT', - 'GET_MULTIPLE_FILE_SIZE', - //'UPLOAD', 'UPLOAD_COMPLETE', 'UPLOAD_CANCEL', ].indexOf(call) !== -1; @@ -867,6 +871,45 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function) var blobPath = paths.blob = keyOrDefaultString('blobPath', './blob'); var blobStagingPath = paths.staging = keyOrDefaultString('blobStagingPath', './blobstage'); + var isUnauthenticateMessage = function (msg) { + var unAuthed = msg && msg.length === 2 && isUnauthenticatedCall(msg[0]); + + if (unAuthed) { + console.log(msg); + console.log('is unauthenticated call!'); + return unAuthed; + } else { + return false; + } + }; + + var handleUnauthenticatedMessage = function (msg, respond) { + console.log(msg); + switch (msg[0]) { + case 'GET_FILE_SIZE': + console.log("Get file size"); + return void getFileSize(Env, msg[1], function (e, size) { + if (e) { + console.error(e); + } + WARN(e, msg[1]); + console.log(size); + respond(e, [null, size, null]); + }); + case 'GET_MULTIPLE_FILE_SIZE': + return void getMultipleFileSize(Env, msg[1], function (e, dict) { + if (e) { + WARN(e, dict); + return respond(e); + } + respond(e, [null, dict, null]); + }); + default: + console.error("unsupported!"); + return respond('UNSUPPORTED_RPC_CALL', msg); + } + }; + var rpc = function ( ctx /*:{ store: Object }*/, data /*:Array>*/, @@ -888,11 +931,19 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function) return void respond('INVALID_ARG_FORMAT'); } + if (isUnauthenticateMessage(msg)) { + return handleUnauthenticatedMessage(msg, respond); + } + var signature = msg.shift(); var publicKey = msg.shift(); // make sure a user object is initialized in the cookie jar - beginSession(Sessions, publicKey); + if (publicKey) { + beginSession(Sessions, publicKey); + } else { + console.log("No public key"); + } var cookie = msg[0]; if (!isValidCookie(Sessions, publicKey, cookie)) { @@ -928,7 +979,8 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function) msg.shift(); var Respond = function (e, msg) { - var token = Sessions[safeKey].tokens.slice(-1)[0]; + var session = Sessions[safeKey]; + var token = session? session.tokens.slice(-1)[0]: ''; var cookie = makeCookie(token).join('|'); respond(e, [cookie].concat(typeof(msg) !== 'undefined' ?msg: [])); }; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 628982c29..bf0fb4117 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -49,6 +49,7 @@ define([ var store; var rpc; + var anon_rpc; // import UI elements common.findCancelButton = UI.findCancelButton; @@ -787,11 +788,32 @@ define([ }; common.getFileSize = function (href, cb) { - if (!pinsReady()) { return void cb('RPC_NOT_READY'); } + if (!anon_rpc) { return void cb('ANON_RPC_NOT_READY'); } + //if (!pinsReady()) { return void cb('RPC_NOT_READY'); } var channelId = Hash.hrefToHexChannelId(href); - rpc.getFileSize(channelId, function (e, bytes) { + anon_rpc.send("GET_FILE_SIZE", channelId, function (e, response) { if (e) { return void cb(e); } - cb(void 0, bytes); + if (response && response.length && typeof(response[0]) === 'number') { + return void cb(void 0, response[0]); + } else { + cb('INVALID_RESPONSE'); + } + }); + }; + + common.getMultipleFileSize = function (files, cb) { + if (!anon_rpc) { return void cb('ANON_RPC_NOT_READY'); } + if (!Array.isArray(files)) { + return void setTimeout(function () { cb('INVALID_FILE_LIST'); }); + } + + anon_rpc.send('GET_MULTIPLE_FILE_SIZE', files, function (e, res) { + if (e) { return cb(e); } + if (res && res.length && typeof(res[0]) === 'object') { + cb(void 0, res[0]); + } else { + cb('UNEXPECTED_RESPONSE'); + } }); }; @@ -1699,6 +1721,21 @@ define([ console.log('pinning disabled'); } + block++; + require([ + '/common/rpc.js', + ], function (Rpc) { + Rpc.createAnonymous(network, function (e, call) { + if (e) { + console.error(e); + return void cb(); + } + anon_rpc = common.anon_rpc = env.anon_rpc = call; + cb(); + }); + }); + + // Everything's ready, continue... if($('#pad-iframe').length) { block++; diff --git a/www/common/pinpad.js b/www/common/pinpad.js index ffdbb9002..64bf04b57 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -100,21 +100,6 @@ define([ }); }; - // take a list of channels and return a dictionary of their sizes - exp.getMultipleFileSize = function (files, cb) { - if (!Array.isArray(files)) { - return window.setTimeout(function () { - cb('[TypeError] pin expects an array'); - }); - } - rpc.send('GET_MULTIPLE_FILE_SIZE', files, function (e, res) { - if (e) { return void cb(e); } - if (typeof(res) !== 'object') { - return void cb('INVALID_RESPONSE'); - } - }); - }; - // get the combined size of all channels (in bytes) for all the // channels which the server has pinned for your publicKey exp.getFileListSize = function (cb) { diff --git a/www/common/rpc.js b/www/common/rpc.js index 02453a9e8..059c5e1e9 100644 --- a/www/common/rpc.js +++ b/www/common/rpc.js @@ -99,7 +99,9 @@ types of messages: delete ctx.pending[txid]; return; } - console.error("received message [%s] for txid[%s] with no callback", msg, txid); + if (parsed.length !== 2) { + console.error("received message [%s] for txid[%s] with no callback", msg, txid); + } }; var create = function (network, edPrivateKey, edPublicKey, cb) { @@ -217,5 +219,104 @@ types of messages: }); }; - return { create: create }; + var onAnonMsg = function (ctx, msg) { + var parsed = parse(msg); + + if (!parsed) { + return void console.error(new Error('could not parse message: %s', msg)); + } + + // RPC messages are always arrays. + if (!Array.isArray(parsed)) { return; } + var txid = parsed[0]; + + // txid must be a string, or this message is not meant for us + if (typeof(txid) !== 'string') { return; } + + var pending = ctx.pending[txid]; + + if (!(parsed && parsed.slice)) { + // RPC responses are arrays. this message isn't meant for us. + return; + } + if (/FULL_HISTORY/.test(parsed[0])) { return; } + var response = parsed.slice(2); + + if (typeof(pending) === 'function') { + if (parsed[1] === 'ERROR') { + pending(parsed[2]); + delete ctx.pending[txid]; + return; + } + pending(void 0, response); + + // if successful, delete the callback... + delete ctx.pending[txid]; + return; + } + // HACK: filter out ugly messages we don't care about + if (typeof(msg) !== 'string') { + console.error("received message [%s] for txid[%s] with no callback", msg, txid); + } + }; + + var createAnonymous = function (network, cb) { + var ctx = { + network: network, + timeouts: {}, // timeouts + pending: {}, // callbacks + cookie: null, + connected: true, + }; + + var send = ctx.send = function (type, msg, cb) { + if (!ctx.connected) { + return void window.setTimeout(function () { + cb('DISCONNECTED'); + }); + } + + + // construct an unsigned message... + var data = [type, msg]; + + // [sig, edPublicKey, cookie, type, msg] + return sendMsg(ctx, data, cb); + }; + + ctx.resend = function (txid) { + var pending = ctx.pending[txid]; + if (pending.called) { + console.error("[%s] called too many times", txid); + return true; + } + pending.called++; + + try { + return ctx.network.sendto(ctx.network.historyKeeper, + JSON.stringify([txid, pending.data])); + } catch (e) { + console.log("failed to resend"); + console.error(e); + } + }; + + network.on('message', function (msg) { + onAnonMsg(ctx, msg); + }); + + network.on('disconnect', function () { + ctx.connected = false; + }); + + network.on('reconnect', function () { + ctx.connected = true; + }); + + cb(void 0, { + send: send + }); + }; + + return { create: create, createAnonymous: createAnonymous }; });