prepare for upload

pull/1/head
ansuz 8 years ago
parent e2942f959b
commit e132ccf94a

@ -10,3 +10,4 @@ NetFluxWebsocketSrv.js
NetFluxWebsocketServer.js NetFluxWebsocketServer.js
WebRTCSrv.js WebRTCSrv.js
www/common/media-tag.js www/common/media-tag.js
www/scratch

@ -2,39 +2,75 @@ define([
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
], function () { ], function () {
var Nacl = window.nacl; var Nacl = window.nacl;
var PARANOIA = true;
var chunkLength = 131088; var plainChunkLength = 128 * 1024;
var cypherChunkLength = 131088;
var slice = function (A) { var slice = function (A) {
return Array.prototype.slice.call(A); return Array.prototype.slice.call(A);
}; };
var createNonce = function () {
return new Uint8Array(new Array(24).fill(0));
};
var increment = function (N) { var increment = function (N) {
var l = N.length; var l = N.length;
while (l-- > 1) { while (l-- > 1) {
if (N[l] !== 255) { return void N[l]++; } if (PARANOIA) {
if (typeof(N[l]) !== 'number') {
throw new Error('E_UNSAFE_TYPE');
}
if (N[l] > 255) {
throw new Error('E_OUT_OF_BOUNDS');
}
}
/* jshint probably suspects this is unsafe because we lack types
but as long as this is only used on nonces, it should be safe */
if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line
N[l] = 0; N[l] = 0;
// you don't need to worry about this running out.
// you'd need a REAAAALLY big file
if (l === 0) { return true; } if (l === 0) { return true; }
} }
}; };
var joinChunks = function (B) { var joinChunks = function (chunks) {
return new Uint8Array(chunks.reduce(function (A, B) { return new Uint8Array(chunks.reduce(function (A, B) {
return slice(A).concat(slice(B)); return slice(A).concat(slice(B));
}, [])); }, []));
}; };
var padChunk = function (A) {
var padding;
if (A.length === plainChunkLength) { return A; }
if (A.length < plainChunkLength) {
padding = new Array(plainChunkLength - A.length).fill(32);
return A.concat(padding);
}
if (A.length > plainChunkLength) {
// how many times larger is it?
var chunks = Math.ceil(A.length / plainChunkLength);
padding = new Array((plainChunkLength * chunks) - A.length).fill(32);
return A.concat(padding);
}
};
var decrypt = function (u8, key, cb) { var decrypt = function (u8, key, cb) {
var nonce = new Uint8Array(new Array(24).fill(0)); var nonce = createNonce();
var i = 0; var i = 0;
var takeChunk = function () { var takeChunk = function () {
let start = i * chunkLength; var start = i * cypherChunkLength;
let end = start + chunkLength; var end = start + cypherChunkLength;
i++; i++;
let box = new Uint8Array(u8.subarray(start, end)); var box = new Uint8Array(u8.subarray(start, end));
// decrypt the chunk // decrypt the chunk
let plaintext = Nacl.secretbox.open(box, nonce, key); var plaintext = Nacl.secretbox.open(box, nonce, key);
// TODO handle nonce-too-large-error
increment(nonce); increment(nonce);
return plaintext; return plaintext;
}; };
@ -46,8 +82,9 @@ define([
}; };
// decrypt metadata // decrypt metadata
for (; !res.metadata && i * chunkLength < u8.length;) { var chunk;
var chunk = takeChunk(); for (; !res.metadata && i * cypherChunkLength < u8.length;) {
chunk = takeChunk();
buffer += Nacl.util.encodeUTF8(chunk); buffer += Nacl.util.encodeUTF8(chunk);
try { try {
res.metadata = JSON.parse(buffer); res.metadata = JSON.parse(buffer);
@ -63,15 +100,16 @@ define([
}); });
} }
var fail = function () {
cb("DECRYPTION_ERROR");
};
var chunks = []; var chunks = [];
// decrypt file contents // decrypt file contents
for (;i * chunkLength < u8.length;) { for (;i * cypherChunkLength < u8.length;) {
let chunk = takeChunk(); chunk = takeChunk();
if (!chunk) { if (!chunk) {
return void window.setTimeout(function () { return window.setTimeout(fail);
cb('DECRYPTION_ERROR');
});
//throw new Error('failed to parse');
} }
chunks.push(chunk); chunks.push(chunk);
} }
@ -82,7 +120,63 @@ define([
cb(void 0, res); cb(void 0, res);
}; };
// 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 nonce = createNonce();
// encode metadata
var metaBuffer = Array.prototype.slice
.call(Nacl.util.decodeUTF8(JSON.stringify(metadata)));
var plaintext = new Uint8Array(padChunk(metaBuffer));
var chunks = [];
var j = 0;
var start;
var end;
var part;
var box;
// prepend some metadata
for (;j * plainChunkLength < plaintext.length; j++) {
start = j * plainChunkLength;
end = start + plainChunkLength;
part = plaintext.subarray(start, end);
box = Nacl.secretbox(part, nonce, key);
chunks.push(box);
increment(nonce);
}
// append the encrypted file chunks
var i = 0;
for (;i * plainChunkLength < u8.length; i++) {
start = i * plainChunkLength;
end = start + plainChunkLength;
part = new Uint8Array(u8.subarray(start, end));
box = Nacl.secretbox(part, nonce, key);
chunks.push(box);
increment(nonce);
}
// TODO do something with the chunks...
};
return { return {
decrypt: decrypt, decrypt: decrypt,
encrypt: encrypt,
}; };
}); });

@ -14,14 +14,44 @@
padding: 0px; padding: 0px;
display: inline-block; display: inline-block;
} }
media-tag * { #file {
max-width: 100%; display: block;
height: 300px;
width: 300px;
border: 2px solid black;
margin: 50px;
} }
.inputfile {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.inputfile + label {
border: 2px solid black;
display: block;
height: 500px;
width: 500px;
background-color: rgba(50, 50, 50, .10);
margin: 50px;
}
.inputfile:focus + label,
.inputfile + label:hover {
background-color: rgba(50, 50, 50, 0.30);
}
</style> </style>
</head> </head>
<body> <body>
<div id="toolbar" class="toolbar-container"></div> <div id="toolbar" class="toolbar-container"></div>
<media-tag id="encryptedFile" data-attr-width="4000" data-attr-height="1500"></media-tag> <div id="upload-form" style="display: none;">
<input type="file" name="file" id="file" class="inputfile" />
<label for="file">Choose a file</label>
</div>
</body> </body>
</html> </html>

@ -6,12 +6,14 @@ define([
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/visible.js', '/common/visible.js',
'/common/notify.js', '/common/notify.js',
'/file/file-crypto.js',
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
'/bower_components/file-saver/FileSaver.min.js', '/bower_components/file-saver/FileSaver.min.js',
], function ($, Crypto, realtimeInput, Toolbar, Cryptpad, Visible, Notify) { ], function ($, Crypto, realtimeInput, Toolbar, Cryptpad, Visible, Notify, FileCrypto) {
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
var saveAs = window.saveAs; var saveAs = window.saveAs;
//window.Nacl = window.nacl; var Nacl = window.nacl;
$(function () { $(function () {
var ifrw = $('#pad-iframe')[0].contentWindow; var ifrw = $('#pad-iframe')[0].contentWindow;
@ -19,18 +21,40 @@ define([
Cryptpad.addLoadingScreen(); Cryptpad.addLoadingScreen();
var fetch = function (src, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", src, true);
xhr.responseType = "arraybuffer";
xhr.onload = function (e) {
return void cb(void 0, new Uint8Array(xhr.response));
};
xhr.send(null);
};
var upload = function (blob, id, key) {
Cryptpad.alert("UPLOAD IS NOT IMPLEMENTED YET");
};
var myFile;
var myDataType;
var uploadMode = false;
var andThen = function () { var andThen = function () {
var $bar = $iframe.find('.toolbar-container'); var $bar = $iframe.find('.toolbar-container');
var secret = Cryptpad.getSecrets();
if (!secret.keys) { throw new Error("You need a hash"); } // TODO
var cryptKey = secret.keys && secret.keys.fileKeyStr;
var fileId = secret.channel;
var hexFileName = Cryptpad.base64ToHex(fileId);
var type = "image/png";
// Test hash: // Test hash:
// #/2/K6xWU-LT9BJHCQcDCT-DcQ/TBo77200c0e-FdldQFcnQx4Y/ // #/2/K6xWU-LT9BJHCQcDCT-DcQ/TBo77200c0e-FdldQFcnQx4Y/
var secret;
var hexFileName;
if (window.location.hash) {
secret = Cryptpad.getSecrets();
if (!secret.keys) { throw new Error("You need a hash"); } // TODO
hexFileName = Cryptpad.base64ToHex(secret.channel);
} else {
uploadMode = true;
}
//window.location.hash = '/2/K6xWU-LT9BJHCQcDCT-DcQ/VLIgpQOgmSaW3AQcUCCoJnYvCbMSO0MKBqaICSly9fo=';
var parsed = Cryptpad.parsePadUrl(window.location.href); var parsed = Cryptpad.parsePadUrl(window.location.href);
var defaultName = Cryptpad.getDefaultName(parsed); var defaultName = Cryptpad.getDefaultName(parsed);
@ -67,21 +91,20 @@ define([
var exportFile = function () { var exportFile = function () {
var suggestion = document.title; var suggestion = document.title;
Cryptpad.prompt(Messages.exportPrompt, Cryptpad.prompt(Messages.exportPrompt,
Cryptpad.fixFileName(suggestion) + '.html', function (filename) { Cryptpad.fixFileName(suggestion), function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; } if (!(typeof(filename) === 'string' && filename)) { return; }
//var blob = new Blob([html], {type: "text/html;charset=utf-8"}); var blob = new Blob([myFile], {type: myDataType});
saveAs(blob, filename); saveAs(blob, filename);
}); });
}; };
var $mt = $iframe.find('#encryptedFile'); var displayed = ['useradmin', 'newpad', 'limit'];
$mt.attr('src', '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName); if (secret && hexFileName) {
$mt.attr('data-crypto-key', cryptKey); displayed.push('share');
$mt.attr('data-type', type); }
require(['/common/media-tag.js'], function (MediaTag) {
var configTb = { var configTb = {
displayed: ['useradmin', 'share', 'newpad'], displayed: displayed,
ifrw: ifrw, ifrw: ifrw,
common: Cryptpad, common: Cryptpad,
title: { title: {
@ -102,10 +125,42 @@ define([
updateTitle(Cryptpad.initialName || getTitle() || defaultName); updateTitle(Cryptpad.initialName || getTitle() || defaultName);
var mt = MediaTag($mt[0]); if (!uploadMode) {
var src = Cryptpad.getBlobPathFromHex(hexFileName);
return fetch(src, function (e, u8) {
// now decrypt the u8
if (e) { return window.alert('error'); }
var cryptKey = secret.keys && secret.keys.fileKeyStr;
var key = Nacl.util.decodeBase64(cryptKey);
FileCrypto.decrypt(u8, key, function (e, data) {
console.log(data);
var title = document.title = data.metadata.filename;
myFile = data.content;
myDataType = data.metadata.type;
updateTitle(title || defaultName);
Cryptpad.removeLoadingScreen(); Cryptpad.removeLoadingScreen();
}); });
});
}
var $form = $iframe.find('#upload-form');
$form.css({
display: 'block',
});
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.readAsText(file);
});
// we're in upload mode
Cryptpad.removeLoadingScreen();
}; };
Cryptpad.ready(function (err, anv) { Cryptpad.ready(function (err, anv) {

Loading…
Cancel
Save