From 586193d6a157ec5548915c2a98b1bb10ad002b15 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 28 May 2018 15:30:39 +0200 Subject: [PATCH] Password-protected files: upload files with hashes V2 --- rpc.js | 65 ++++++++++++++++----------------- www/common/common-hash.js | 23 ++---------- www/common/cryptpad-common.js | 8 ++-- www/common/outer/async-store.js | 6 +-- www/common/outer/upload.js | 15 +++----- www/common/pinpad.js | 8 ++-- 6 files changed, 52 insertions(+), 73 deletions(-) diff --git a/rpc.js b/rpc.js index 88228fdac..486c01e42 100644 --- a/rpc.js +++ b/rpc.js @@ -53,9 +53,15 @@ var uint8ArrayToHex = function (a) { }).join(''); }; +var testFileId = function (id) { + if (id.length !== 48 || /[^a-f0-9]/.test(id)) { + return false; + } + return true; +}; var createFileId = function () { var id = uint8ArrayToHex(Nacl.randomBytes(24)); - if (id.length !== 48 || /[^a-f0-9]/.test(id)) { + if (!testFileId(id)) { throw new Error('file ids must consist of 48 hex characters'); } return id; @@ -876,7 +882,7 @@ var upload = function (Env, publicKey, content, cb) { var session = getSession(Env.Sessions, publicKey); if (typeof(session.currentUploadSize) !== 'number' || - typeof(session.currentUploadSize) !== 'number') { + typeof(session.pendingUploadSize) !== 'number') { // improperly initialized... maybe they didn't check before uploading? // reject it, just in case return cb('NOT_READY'); @@ -902,12 +908,12 @@ var upload = function (Env, publicKey, content, cb) { } }; -var upload_cancel = function (Env, publicKey, cb) { +var upload_cancel = function (Env, publicKey, fileSize, cb) { var paths = Env.paths; var session = getSession(Env.Sessions, publicKey); - delete session.currentUploadSize; - delete session.pendingUploadSize; + session.pendingUploadSize = fileSize; + session.currentUploadSize = 0; if (session.blobstage) { session.blobstage.close(); } var path = makeFilePath(paths.staging, publicKey); @@ -933,13 +939,14 @@ var isFile = function (filePath, cb) { }); }; -var upload_complete = function (Env, publicKey, cb) { +var upload_complete = function (Env, publicKey, id, cb) { var paths = Env.paths; var session = getSession(Env.Sessions, publicKey); - if (session.blobstage && session.blobstage.close) { - session.blobstage.close(); - delete session.blobstage; + if (!testFileId(id)) { + console.log(id); + WARN('uploadComplete', "id is invalid"); + return void cb('RENAME_ERR'); } var oldPath = makeFilePath(paths.staging, publicKey); @@ -948,8 +955,7 @@ var upload_complete = function (Env, publicKey, cb) { return void cb('RENAME_ERR'); } - var tryRandomLocation = function (cb) { - var id = createFileId(); + var tryLocation = function (cb) { var prefix = id.slice(0, 2); var newPath = makeFilePath(paths.blob, id); if (typeof(newPath) !== 'string') { @@ -968,7 +974,8 @@ var upload_complete = function (Env, publicKey, cb) { return void cb(e); } if (yes) { - return void tryRandomLocation(cb); + WARN('isFile', 'FILE EXISTS!'); + return void cb('RENAME_ERR'); } cb(void 0, newPath, id); @@ -976,38 +983,27 @@ var upload_complete = function (Env, publicKey, cb) { }); }; - var retries = 3; - var handleMove = function (e, newPath, id) { if (e || !oldPath || !newPath) { - if (retries--) { - setTimeout(function () { - return tryRandomLocation(handleMove); - }, 750); - } else { - cb(e); - } - return; + return void cb(e || 'PATH_ERR'); + } + + if (session.blobstage && session.blobstage.close) { + session.blobstage.close(); + delete session.blobstage; } // lol wut handle ur errors Fs.rename(oldPath, newPath, function (e) { if (e) { WARN('rename', e); - - if (retries--) { - return void setTimeout(function () { - tryRandomLocation(handleMove); - }, 750); - } - return void cb('RENAME_ERR'); } cb(void 0, id); }); }; - tryRandomLocation(handleMove); + tryLocation(handleMove); }; var owned_upload_complete = function (Env, safeKey, cb) { @@ -1504,7 +1500,7 @@ RPC.create = function ( }); case 'UPLOAD_COMPLETE': if (!privileged) { return deny(); } - return void upload_complete(Env, safeKey, function (e, hash) { + return void upload_complete(Env, safeKey, msg[1], function (e, hash) { WARN(e, hash); Respond(e, hash); }); @@ -1516,8 +1512,11 @@ RPC.create = function ( }); case 'UPLOAD_CANCEL': if (!privileged) { return deny(); } - return void upload_cancel(Env, safeKey, function (e) { - WARN(e); + // msg[1] is fileSize + // if we pass it here, we can start an upload right away without calling + // UPLOAD_STATUS again + return void upload_cancel(Env, safeKey, msg[1], function (e) { + WARN(e, 'UPLOAD_CANCEL'); Respond(e); }); default: diff --git a/www/common/common-hash.js b/www/common/common-hash.js index 2b75b0e8e..4b0c2c607 100644 --- a/www/common/common-hash.js +++ b/www/common/common-hash.js @@ -67,23 +67,6 @@ define([ } }; - // V1 - /*var getEditHashFromKeys = Hash.getEditHashFromKeys = function (chanKey, keys) { - if (typeof keys === 'string') { - return chanKey + keys; - } - if (!keys.editKeyStr) { return; } - return '/1/edit/' + hexToBase64(chanKey) + '/'+Crypto.b64RemoveSlashes(keys.editKeyStr)+'/'; - }; - var getViewHashFromKeys = Hash.getViewHashFromKeys = function (chanKey, keys) { - if (typeof keys === 'string') { - return; - } - return '/1/view/' + hexToBase64(chanKey) + '/'+Crypto.b64RemoveSlashes(keys.viewKeyStr)+'/'; - }; - var getFileHashFromKeys = Hash.getFileHashFromKeys = function (fileKey, cryptKey) { - return '/1/' + hexToBase64(fileKey) + '/' + Crypto.b64RemoveSlashes(cryptKey) + '/'; - };*/ Hash.getUserHrefFromKeys = function (origin, username, pubkey) { return origin + '/user/#/1/' + username + '/' + pubkey.replace(/\//g, '-'); }; @@ -108,7 +91,7 @@ define([ password: Boolean(password), version: 2, type: type, - keys: cryptor.fileKeyStr + keys: cryptor }); } cryptor = Crypto.createEditCryptor2(void 0, void 0, password); @@ -116,7 +99,7 @@ define([ password: Boolean(password), version: 2, type: type, - keys: cryptor.editKeyStr + keys: cryptor }); }; @@ -374,8 +357,8 @@ Version 1 } } } else if (parsed.type === "file") { - secret.channel = base64ToHex(secret.keys.chanId); secret.keys = Crypto.createFileCryptor2(parsed.key, password); + secret.channel = base64ToHex(secret.keys.chanId); secret.key = secret.keys.fileKeyStr; if (secret.channel.length !== 48 || secret.key.length !== 24) { throw new Error("The channel key and/or the encryption key is invalid"); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 68debf694..0d934d20b 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -204,8 +204,8 @@ define([ }); }; - common.uploadComplete = function (cb) { - postMessage("UPLOAD_COMPLETE", null, function (obj) { + common.uploadComplete = function (id, cb) { + postMessage("UPLOAD_COMPLETE", id, function (obj) { if (obj && obj.error) { return void cb(obj.error); } cb(null, obj); }); @@ -218,8 +218,8 @@ define([ }); }; - common.uploadCancel = function (cb) { - postMessage("UPLOAD_CANCEL", null, function (obj) { + common.uploadCancel = function (size, cb) { + postMessage("UPLOAD_CANCEL", {size: size}, function (obj) { if (obj && obj.error) { return void cb(obj.error); } cb(null, obj); }); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 20cea6cd0..f64f9efbe 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -230,9 +230,9 @@ define([ }); }; - Store.uploadComplete = function (data, cb) { + Store.uploadComplete = function (id, cb) { if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } - store.rpc.uploadComplete(function (err, res) { + store.rpc.uploadComplete(id, function (err, res) { if (err) { return void cb({error:err}); } cb(res); }); @@ -248,7 +248,7 @@ define([ Store.uploadCancel = function (data, cb) { if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } - store.rpc.uploadCancel(function (err, res) { + store.rpc.uploadCancel(data.size, function (err, res) { if (err) { return void cb({error:err}); } cb(res); }); diff --git a/www/common/outer/upload.js b/www/common/outer/upload.js index 9ccc32500..f911aba28 100644 --- a/www/common/outer/upload.js +++ b/www/common/outer/upload.js @@ -13,16 +13,14 @@ define([ // if it exists, path contains the new pad location in the drive var path = file.path; - // XXX - // PASSWORD_FILES - var password; + var password = file.password; var hash = Hash.createRandomHash('file', password); var secret = Hash.getSecrets('file', hash, password); var key = secret.keys.cryptKey; var id = secret.channel; - //var key = Nacl.randomBytes(32); - // XXX provide channel id to "next" + // XXX check id here (getFileSize) + var next = FileCrypto.encrypt(u8, metadata, key); var estimate = FileCrypto.computeEncryptedSize(u8.length, metadata); @@ -53,7 +51,7 @@ define([ } // if not box then done - common.uploadComplete(function (e/*, id*/) { // XXX id is given, not asked + common.uploadComplete(id, function (e) { if (e) { return void console.error(e); } var uri = ['', 'blob', id.slice(0,2), id].join('/'); console.log("encrypted blob is now available as %s", uri); @@ -64,11 +62,11 @@ define([ if (noStore) { return void onComplete(href); } - // PASSWORD_FILES var data = { title: title || "", href: href, path: path, + password: password, channel: id }; common.setPadTitle(data, function (err) { @@ -89,11 +87,10 @@ define([ if (pending) { return void onPending(function () { // if the user wants to cancel the pending upload to execute that one - common.uploadCancel(function (e, res) { + common.uploadCancel(estimate, function (e) { if (e) { return void console.error(e); } - console.log(res); next(again); }); }); diff --git a/www/common/pinpad.js b/www/common/pinpad.js index b200f5493..1f31a884a 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -176,8 +176,8 @@ define([ }); }; - exp.uploadComplete = function (cb) { - rpc.send('UPLOAD_COMPLETE', null, function (e, res) { + exp.uploadComplete = function (id, cb) { + rpc.send('UPLOAD_COMPLETE', id, function (e, res) { if (e) { return void cb(e); } var id = res[0]; if (typeof(id) !== 'string') { @@ -203,8 +203,8 @@ define([ }); }; - exp.uploadCancel = function (cb) { - rpc.send('UPLOAD_CANCEL', void 0, function (e) { + exp.uploadCancel = function (size, cb) { + rpc.send('UPLOAD_CANCEL', size, function (e) { if (e) { return void cb(e); } cb(); });