diff --git a/bower.json b/bower.json index 0fb80b9f9..6e94e14d6 100644 --- a/bower.json +++ b/bower.json @@ -19,12 +19,12 @@ ], "dependencies": { "jquery": "~2.1.3", - "tweetnacl": "~0.12.2", + "tweetnacl": "0.12.2", "components-font-awesome": "^4.6.3", "ckeditor": "~4.7", "codemirror": "^5.19.0", - "requirejs": "~2.1.15", - "marked": "~0.3.5", + "requirejs": "2.1.15", + "marked": "0.3.5", "rangy": "rangy-release#~1.3.0", "json.sortify": "~2.1.0", "secure-fabric.js": "secure-v1.7.9", @@ -33,11 +33,11 @@ "chainpad-json-validator": "^0.2.0", "chainpad-crypto": "^0.1.3", "chainpad-listmap": "^0.3.0", - "file-saver": "^1.3.1", - "diff-dom": "^2.1.1", - "alertifyjs": "^1.0.11", - "scrypt-async": "^1.2.0", - "require-css": "^0.1.10", + "file-saver": "1.3.1", + "diff-dom": "~2.1.1", + "alertifyjs": "1.0.11", + "scrypt-async": "1.2.0", + "require-css": "0.1.10", "less": "^2.7.2", "bootstrap": "#v4.0.0-alpha.6" } diff --git a/customize.dist/main.js b/customize.dist/main.js index f2580bbe1..633f4c573 100644 --- a/customize.dist/main.js +++ b/customize.dist/main.js @@ -171,6 +171,10 @@ define([ $('button.gotodrive').click(function () { document.location.href = '/drive/'; }); + + $('button#loggedInLogout').click(function () { + $('#user-menu .logout').click(); + }); }; displayCreateButtons(); 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/code/main.js b/www/code/main.js index 1e7210ce3..1108486eb 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -428,8 +428,6 @@ define([ Cryptpad.onLogout(function () { setEditable(false); }); }; - var interval = 100; - var first = function () { Cryptpad.ready(function () { andThen(); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 5b1a2fc06..e1743b89c 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'); + } }); }; @@ -1328,7 +1350,7 @@ define([ setActive($val); $innerblock.scrollTop($val.position().top + $innerblock.scrollTop()); } - if (config.feedback) { common.feedback(config.feedback); } + if (config.feedback && store) { common.feedback(config.feedback); } }; $container.click(function (e) { @@ -1707,6 +1729,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 }; }); diff --git a/www/file/main.js b/www/file/main.js index f58636ed1..ef43bb83d 100644 --- a/www/file/main.js +++ b/www/file/main.js @@ -185,9 +185,6 @@ define([ }; Cryptpad.getFileSize(window.location.href, function (e, data) { if (e) { - // TODO when GET_FILE_SIZE is made unauthenticated - // you won't need to handle this error (there won't be one) - if (e === 'RPC_NOT_READY') { return todoBigFile(); } return void Cryptpad.errorLoadingScreen(e); } var size = Cryptpad.bytesToMegabytes(data); diff --git a/www/slide/main.js b/www/slide/main.js index e7fea2ca0..0b03f292c 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -695,8 +695,6 @@ define([ Cryptpad.onLogout(function () { setEditable(false); }); }; - var interval = 100; - var first = function () { Cryptpad.ready(function () { andThen();