diff --git a/www/file/file-crypto.js b/www/file/file-crypto.js index 924cbe334..4af79aa04 100644 --- a/www/file/file-crypto.js +++ b/www/file/file-crypto.js @@ -122,15 +122,7 @@ define([ // metadata /* { filename: 'raccoon.jpg', type: 'image/jpeg' } */ - - - /* TODO - in your callback, return an object which you can iterate... - - - */ - - var encrypt = function (u8, metadata, key, cb) { + var encrypt = function (u8, metadata, key) { var nonce = createNonce(); // encode metadata @@ -139,44 +131,62 @@ define([ var plaintext = new Uint8Array(padChunk(metaBuffer)); - var chunks = []; var j = 0; + var i = 0; - var start; - var end; + /* + 0: metadata + 1: u8 + 2: done + */ - var part; - var box; + var state = 0; - // prepend some metadata - for (;j * plainChunkLength < plaintext.length; j++) { - start = j * plainChunkLength; - end = start + plainChunkLength; + var next = function (cb) { + var start; + var end; + var part; + var box; - part = plaintext.subarray(start, end); - box = Nacl.secretbox(part, nonce, key); - chunks.push(box); - increment(nonce); - } + if (state === 0) { // metadata... + start = j * plainChunkLength; + end = start + plainChunkLength; - // append the encrypted file chunks - var i = 0; - for (;i * plainChunkLength < u8.length; i++) { + part = plaintext.subarray(start, end); + box = Nacl.secretbox(part, nonce, key); + increment(nonce); + + j++; + + // metadata is done + if (j * plainChunkLength >= plaintext.length) { + return void cb(state++, box); + } + + return void cb(state, box); + } + + // encrypt the rest of the file... start = i * plainChunkLength; end = start + plainChunkLength; - part = new Uint8Array(u8.subarray(start, end)); + part = u8.subarray(start, end); box = Nacl.secretbox(part, nonce, key); - chunks.push(box); increment(nonce); - } + i++; + // regular data is done + if (i * plainChunkLength >= u8.length) { state = 2; } + + return void cb(state, box); + }; - // TODO do something with the chunks... + return next; }; return { decrypt: decrypt, encrypt: encrypt, + joinChunks: joinChunks, }; }); diff --git a/www/file/main.js b/www/file/main.js index 24ef72f2b..004a665e0 100644 --- a/www/file/main.js +++ b/www/file/main.js @@ -14,6 +14,8 @@ define([ var saveAs = window.saveAs; var Nacl = window.nacl; + var APP = {}; + $(function () { var ifrw = $('#pad-iframe')[0].contentWindow; @@ -31,12 +33,93 @@ define([ xhr.send(null); }; - var upload = function (blob, id, key) { - Cryptpad.alert("UPLOAD IS NOT IMPLEMENTED YET"); - }; - var myFile; var myDataType; + + var upload = function (blob, metadata) { + console.log(metadata); + var u8 = new Uint8Array(blob); + + var key = Nacl.randomBytes(32); + var next = FileCrypto.encrypt(u8, metadata, key); + + var chunks = []; + + var sendChunk = function (box, cb) { + var enc = Nacl.util.encodeBase64(box); + + chunks.push(box); + Cryptpad.rpc.send('UPLOAD', enc, function (e, msg) { + cb(e, msg); + }); + }; + + var again = function (state, box) { + switch (state) { + case 0: + sendChunk(box, function (e, msg) { + if (e) { return console.error(e); } + next(again); + }); + break; + case 1: + sendChunk(box, function (e, msg) { + if (e) { return console.error(e); } + next(again); + }); + break; + case 2: + sendChunk(box, function (e, msg) { + if (e) { return console.error(e); } + Cryptpad.rpc.send('UPLOAD_COMPLETE', '', function (e, res) { + if (e) { return void console.error(e); } + var id = res[0]; + var uri = ['', 'blob', id.slice(0,2), id].join('/'); + console.log("encrypted blob is now available as %s", uri); + + window.location.hash = [ + '', + 2, + Cryptpad.hexToBase64(id).replace(/\//g, '-'), + Nacl.util.encodeBase64(key).replace(/\//g, '-'), + '' + ].join('/'); + + APP.$form.hide(); + + var newU8 = FileCrypto.joinChunks(chunks); + FileCrypto.decrypt(newU8, key, function (e, res) { + var title = document.title = res.metadata.filename; + myFile = res.content; + myDataType = res.metadata.type; + }); + }); + }); + break; + default: + throw new Error("E_INVAL_STATE"); + } + }; + + Cryptpad.rpc.send('UPLOAD_STATUS', '', function (e, pending) { + if (e) { + console.error(e); + return void Cryptpad.alert("something went wrong"); + } + + if (pending[0]) { + return void Cryptpad.confirm('upload pending, abort?', function (yes) { + if (!yes) { return; } + Cryptpad.rpc.send('UPLOAD_CANCEL', '', function (e, res) { + if (e) { return void console.error(e); } + console.log(res); + }); + }); + } + next(again); + }); + }; + var uploadMode = false; var andThen = function () { @@ -54,8 +137,6 @@ define([ uploadMode = true; } - //window.location.hash = '/2/K6xWU-LT9BJHCQcDCT-DcQ/VLIgpQOgmSaW3AQcUCCoJnYvCbMSO0MKBqaICSly9fo='; - var parsed = Cryptpad.parsePadUrl(window.location.href); var defaultName = Cryptpad.getDefaultName(parsed); @@ -136,7 +217,7 @@ define([ FileCrypto.decrypt(u8, key, function (e, data) { console.log(data); - var title = document.title = data.metadata.filename; + var title = document.title = data.metadata.name; myFile = data.content; myDataType = data.metadata.type; updateTitle(title || defaultName); @@ -146,7 +227,11 @@ define([ }); } - var $form = $iframe.find('#upload-form'); + if (!Cryptpad.isLoggedIn()) { + return Cryptpad.alert("You must be logged in to upload files"); + } + + var $form = APP.$form = $iframe.find('#upload-form'); $form.css({ display: 'block', }); @@ -154,10 +239,13 @@ define([ var $file = $form.find("#file").on('change', function (e) { var file = e.target.files[0]; var reader = new FileReader(); - reader.onload = function (e) { - upload(e.target.result); + reader.onloadend = function (e) { + upload(this.result, { + name: file.name, + type: file.type, + }); }; - reader.readAsText(file); + reader.readAsArrayBuffer(file); }); // we're in upload mode