Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging

This commit is contained in:
yflory 2017-05-12 16:33:56 +02:00
commit 89a993be3c
11 changed files with 158 additions and 22 deletions

View File

@ -116,6 +116,12 @@ module.exports = {
'contact', 'contact',
], ],
/* Domain
* If you want to have enable payments on your CryptPad instance, it has to be able to tell
* our account server what is your domain
*/
// domain: 'https://cryptpad.fr',
/* /*
You have the option of specifying an alternative storage adaptor. You have the option of specifying an alternative storage adaptor.
These status of these alternatives are specified in their READMEs, These status of these alternatives are specified in their READMEs,

View File

@ -1,7 +1,7 @@
{ {
"name": "cryptpad", "name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server", "description": "realtime collaborative visual editor with zero knowlege server",
"version": "1.6.0", "version": "1.8.0",
"dependencies": { "dependencies": {
"chainpad-server": "^1.0.1", "chainpad-server": "^1.0.1",
"express": "~4.10.1", "express": "~4.10.1",

84
rpc.js
View File

@ -7,11 +7,14 @@ var Nacl = require("tweetnacl");
var Fs = require("fs"); var Fs = require("fs");
var Path = require("path"); var Path = require("path");
var Https = require("https");
var RPC = module.exports; var RPC = module.exports;
var Store = require("./storage/file"); var Store = require("./storage/file");
var DEFAULT_LIMIT = 100;
var isValidChannel = function (chan) { var isValidChannel = function (chan) {
return /^[a-fA-F0-9]/.test(chan) || return /^[a-fA-F0-9]/.test(chan) ||
[32, 48].indexOf(chan.length) !== -1; [32, 48].indexOf(chan.length) !== -1;
@ -454,8 +457,64 @@ var isPrivilegedUser = function (publicKey, cb) {
}); });
}; };
var getLimit = function (cb) { // The limits object contains storage limits for all the publicKey that have paid
cb = cb; // TODO // To each key is associated an object containing the 'limit' value and a 'note' explaining that limit
var limits = {};
var updateLimits = function (config, publicKey, cb) {
if (typeof cb !== "function") { cb = function () {}; }
var body = JSON.stringify({
domain: config.domain,
subdomain: config.subdomain
});
var options = {
host: 'accounts.cryptpad.fr',
path: '/api/getauthorized',
method: 'POST',
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body)
}
};
var req = Https.request(options, function (response) {
if (!('' + req.statusCode).match(/^2\d\d$/)) {
return void cb('SERVER ERROR ' + req.statusCode);
}
var str = '';
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
try {
var json = JSON.parse(str);
limits = json;
var l;
if (publicKey) {
var limit = limits[publicKey];
l = limit && typeof limit.limit === "number" ? limit.limit : DEFAULT_LIMIT;
}
cb(void 0, l);
} catch (e) {
cb(e);
}
});
});
req.on('error', function (e) {
if (!config.domain) { return cb(); }
cb(e);
});
req.end(body);
};
var getLimit = function (publicKey, cb) {
var limit = limits[publicKey];
cb(void 0, limit && typeof(limit.limit) === "number"?
limit.limit : DEFAULT_LIMIT);
}; };
var safeMkdir = function (path, cb) { var safeMkdir = function (path, cb) {
@ -714,10 +773,16 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
}); });
case 'GET_FILE_SIZE': case 'GET_FILE_SIZE':
return void getFileSize(ctx.store, msg[1], Respond); return void getFileSize(ctx.store, msg[1], Respond);
case 'GET_LIMIT': // TODO implement this and cache it per-user case 'UPDATE_LIMITS':
return void getLimit(function (e, limit) { return void updateLimits(config, safeKey, function (e, limit) {
if (e) { return void Respond(e); }
Respond(void 0, limit);
});
case 'GET_LIMIT':
return void getLimit(safeKey, function (e, limit) {
if (e) { return void Respond(e); }
limit = limit; limit = limit;
Respond('NOT_IMPLEMENTED'); Respond(void 0, limit);
}); });
case 'GET_MULTIPLE_FILE_SIZE': case 'GET_MULTIPLE_FILE_SIZE':
return void getMultipleFileSize(ctx.store, msg[1], function (e, dict) { return void getMultipleFileSize(ctx.store, msg[1], function (e, dict) {
@ -725,7 +790,6 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
Respond(void 0, dict); Respond(void 0, dict);
}); });
// restricted to privileged users... // restricted to privileged users...
case 'UPLOAD': case 'UPLOAD':
if (!privileged) { return deny(); } if (!privileged) { return deny(); }
@ -775,6 +839,14 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
handleMessage(session.privilege); handleMessage(session.privilege);
}; };
var updateLimitDaily = function () {
updateLimits(config, undefined, function (e) {
if (e) { console.error('Error updating the storage limits', e); }
});
};
updateLimitDaily();
setInterval(updateLimitDaily, 24*3600*1000);
Store.create({ Store.create({
filePath: pinPath, filePath: pinPath,
}, function (s) { }, function (s) {

View File

@ -21,7 +21,7 @@ define([], function () {
.replace(/ +$/, "") .replace(/ +$/, "")
.split(" "); .split(" ");
var byteString = String.fromCharCode.apply(null, hexArray); var byteString = String.fromCharCode.apply(null, hexArray);
return window.btoa(byteString).replace(/\//g, '-').slice(0,-2); return window.btoa(byteString).replace(/\//g, '-').replace(/=+$/, '');
}; };
Util.base64ToHex = function (b64String) { Util.base64ToHex = function (b64String) {
@ -90,11 +90,21 @@ define([], function () {
}; };
Util.fetch = function (src, cb) { Util.fetch = function (src, cb) {
var done = false;
var CB = function (err, res) {
if (done) { return; }
done = true;
cb(err, res);
};
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open("GET", src, true); xhr.open("GET", src, true);
xhr.responseType = "arraybuffer"; xhr.responseType = "arraybuffer";
xhr.onload = function () { xhr.onload = function () {
return void cb(void 0, new Uint8Array(xhr.response)); return void CB(void 0, new Uint8Array(xhr.response));
};
xhr.onerror = function () {
CB('XHR_ERROR');
}; };
xhr.send(null); xhr.send(null);
}; };

View File

@ -746,8 +746,15 @@ define([
}); });
}; };
common.updatePinLimit = function (cb) {
if (!pinsReady()) { return void cb('[RPC_NOT_READY]'); }
rpc.getFileListSize(cb);
};
common.getPinLimit = function (cb) { common.getPinLimit = function (cb) {
cb(void 0, typeof(AppConfig.pinLimit) === 'number'? AppConfig.pinLimit: 1000); if (!pinsReady()) { return void cb('[RPC_NOT_READY]'); }
rpc.getFileListSize(cb);
//cb(void 0, typeof(AppConfig.pinLimit) === 'number'? AppConfig.pinLimit: 1000);
}; };
common.isOverPinLimit = function (cb) { common.isOverPinLimit = function (cb) {

File diff suppressed because one or more lines are too long

View File

@ -121,6 +121,29 @@ define([
}); });
}; };
// Update the limit value for all the users and return the limit for your publicKey
exp.updatePinLimits = function (cb) {
rpc.send('UPDATE_LIMITS', undefined, function (e, response) {
if (e) { return void cb(e); }
if (response && typeof response === "number") {
cb (void 0, response);
} else {
cb('INVALID_RESPONSE');
}
});
};
// Get the storage limit associated with your publicKey
exp.getLimit = function (cb) {
rpc.send('GET_LIMIT', undefined, function (e, response) {
if (e) { return void cb(e); }
if (response && typeof response === "number") {
cb (void 0, response);
} else {
cb('INVALID_RESPONSE');
}
});
};
cb(e, exp); cb(e, exp);
}); });
}; };

View File

@ -7,6 +7,12 @@ define([
var plainChunkLength = 128 * 1024; var plainChunkLength = 128 * 1024;
var cypherChunkLength = 131088; var cypherChunkLength = 131088;
var computeEncryptedSize = function (bytes, meta) {
var metasize = Nacl.util.decodeUTF8(JSON.stringify(meta)).length;
var chunks = Math.ceil(bytes / plainChunkLength);
return metasize + 18 + (chunks * 16) + bytes;
};
var encodePrefix = function (p) { var encodePrefix = function (p) {
return [ return [
65280, // 255 << 8 65280, // 255 << 8
@ -131,23 +137,15 @@ define([
var i = 0; var i = 0;
/*
0: metadata
1: u8
2: done
*/
var state = 0; var state = 0;
var next = function (cb) { var next = function (cb) {
if (state === 2) { return void cb(); }
var start; var start;
var end; var end;
var part; var part;
var box; var box;
// DONE
if (state === 2) { return void cb(); }
if (state === 0) { // metadata... if (state === 0) { // metadata...
part = new Uint8Array(plaintext); part = new Uint8Array(plaintext);
box = Nacl.secretbox(part, nonce, key); box = Nacl.secretbox(part, nonce, key);
@ -159,6 +157,7 @@ define([
var prefixed = new Uint8Array(encodePrefix(box.length) var prefixed = new Uint8Array(encodePrefix(box.length)
.concat(slice(box))); .concat(slice(box)));
state++; state++;
return void cb(void 0, prefixed); return void cb(void 0, prefixed);
} }
@ -184,5 +183,6 @@ define([
decrypt: decrypt, decrypt: decrypt,
encrypt: encrypt, encrypt: encrypt,
joinChunks: joinChunks, joinChunks: joinChunks,
computeEncryptedSize: computeEncryptedSize,
}; };
}); });

View File

@ -36,6 +36,7 @@ define([
var key = Nacl.randomBytes(32); var key = Nacl.randomBytes(32);
var next = FileCrypto.encrypt(u8, metadata, key); var next = FileCrypto.encrypt(u8, metadata, key);
var estimate = FileCrypto.computeEncryptedSize(blob.byteLength, metadata);
var chunks = []; var chunks = [];
var sendChunk = function (box, cb) { var sendChunk = function (box, cb) {
@ -47,15 +48,21 @@ define([
}); });
}; };
var actual = 0;
var again = function (err, box) { var again = function (err, box) {
if (err) { throw new Error(err); } if (err) { throw new Error(err); }
if (box) { if (box) {
actual += box.length;
return void sendChunk(box, function (e) { return void sendChunk(box, function (e) {
if (e) { return console.error(e); } if (e) { return console.error(e); }
next(again); next(again);
}); });
} }
if (actual !== estimate) {
console.error('Estimated size does not match actual size');
}
// if not box then done // if not box then done
Cryptpad.rpc.send('UPLOAD_COMPLETE', '', function (e, res) { Cryptpad.rpc.send('UPLOAD_COMPLETE', '', function (e, res) {
if (e) { return void console.error(e); } if (e) { return void console.error(e); }
@ -168,11 +175,15 @@ define([
if (!uploadMode) { if (!uploadMode) {
var src = Cryptpad.getBlobPathFromHex(hexFileName); var src = Cryptpad.getBlobPathFromHex(hexFileName);
return Cryptpad.fetch(src, function (e, u8) { return Cryptpad.fetch(src, function (e, u8) {
if (e) { return void Cryptpad.alert(e); }
// now decrypt the u8 // now decrypt the u8
if (e) { return window.alert('error'); }
var cryptKey = secret.keys && secret.keys.fileKeyStr; var cryptKey = secret.keys && secret.keys.fileKeyStr;
var key = Nacl.util.decodeBase64(cryptKey); var key = Nacl.util.decodeBase64(cryptKey);
if (!u8 || !u8.length) {
return void Cryptpad.errorLoadingScreen(e);
}
FileCrypto.decrypt(u8, key, function (e, data) { FileCrypto.decrypt(u8, key, function (e, data) {
if (e) { if (e) {
Cryptpad.removeLoadingScreen(); Cryptpad.removeLoadingScreen();

View File

@ -16,6 +16,8 @@
} }
media-tag * { media-tag * {
max-width: 100%; max-width: 100%;
margin: auto;
display: block;
} }
</style> </style>
</head> </head>

View File

@ -20,6 +20,11 @@ define([
Cryptpad.addLoadingScreen(); Cryptpad.addLoadingScreen();
var andThen = function () { var andThen = function () {
$(window.document).on('decryption', function (e) {
var decrypted = e.originalEvent;
console.log(decrypted.blob, decrypted.metadata);
});
var $bar = $iframe.find('.toolbar-container'); var $bar = $iframe.find('.toolbar-container');
var secret = Cryptpad.getSecrets(); var secret = Cryptpad.getSecrets();