prepare for upload
This commit is contained in:
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…
x
Reference in New Issue
Block a user