diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index bda8672cf..692855912 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -362,20 +362,6 @@ define(function () { // Initial states - out.initialState = [ - '
',
- 'Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge.',
- '
',
- 'Ce que vous tapez ici est chiffré de manière que seules les personnes avec le lien peuvent y accéder.',
- '
',
- 'Même le serveur est incapable de voir ce que vous tapez.',
- '
', - '', - 'Ce que vous voyez ici, ce que vous entendez, quand vous partez, ça reste ici', - '', - '
', - ].join(''); out.initialState = [ '',
'Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.',
diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js
index 0c6af6d81..961612197 100644
--- a/customize.dist/translations/messages.js
+++ b/customize.dist/translations/messages.js
@@ -365,9 +365,6 @@ define(function () {
out.header_france = 'With
from
by
';
-
- // TODO Hardcode cause YOLO
- //out.header_xwiki = '
';
out.header_support = '
';
out.header_logoTitle = 'Go to the main page';
diff --git a/rpc.js b/rpc.js
index 66c8af873..3c4e3507b 100644
--- a/rpc.js
+++ b/rpc.js
@@ -1,6 +1,4 @@
-/* Use Nacl for checking signatures of messages
-
-*/
+/* Use Nacl for checking signatures of messages */
var Nacl = require("tweetnacl");
var RPC = module.exports;
@@ -15,43 +13,124 @@ var isValidChannel = function (chan) {
return /^[a-fA-F0-9]/.test(chan);
};
-var checkSignature = function (signedMsg, publicKey) {
- if (!(signedMsg && publicKey)) { return null; }
+var makeCookie = function (seq) {
+ return [
+ Math.floor(new Date() / (1000*60*60*24)),
+ process.pid, // jshint ignore:line
+ seq
+ ].join('|');
+};
+
+var parseCookie = function (cookie) {
+ if (!(cookie && cookie.split)) { return null; }
+
+ var parts = cookie.split('|');
+ if (parts.length !== 3) { return null; }
+
+ var c = {};
+ c.time = new Date(parts[0]);
+ c.pid = parts[1];
+ c.seq = parts[2];
+ return c;
+};
+
+var isValidCookie = function (ctx, cookie) {
+ var now = +new Date();
+ if (now - cookie.time > 300000) { // 5 minutes
+ return false;
+ }
+
+ // different process. try harder
+ if (process.pid !== cookie.pid) { // jshint ignore:line
+ return false;
+ }
+
+ //if (cookie.seq !==
+
+ return true;
+};
+
+var checkSignature = function (signedMsg, signature, publicKey) {
+ if (!(signedMsg && publicKey)) { return false; }
var signedBuffer;
var pubBuffer;
+ var signatureBuffer;
+
try {
- signedBuffer = Nacl.util.decodeBase64(signedMsg);
- pubBuffer = Nacl.util.decodeBase64(publicKey);
+ signedBuffer = Nacl.util.decodeUTF8(signedMsg);
} catch (e) {
+ console.log('invalid signedBuffer');
+ console.log(signedMsg);
return null;
}
- var opened = Nacl.sign.open(signedBuffer, pubBuffer);
-
- if (opened) {
- var decoded = Nacl.util.encodeUTF8(opened);
- try {
- return JSON.parse(decoded);
- } catch (e) { } // fall through to return
+ try {
+ pubBuffer = Nacl.util.decodeBase64(publicKey);
+ } catch (e) {
+ return false;
}
- return null;
+
+ try {
+ signatureBuffer = Nacl.util.decodeBase64(signature);
+ } catch (e) {
+ return false;
+ }
+
+ if (pubBuffer.length !== 32) {
+ console.log('public key length: ' + pubBuffer.length);
+ console.log(publicKey);
+ return false;
+ }
+
+ if (signatureBuffer.length !== 64) {
+ return false;
+ }
+
+ return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer);
};
RPC.create = function (config, cb) {
// load pin-store...
console.log('loading rpc module...');
- var rpc = function (ctx, args, respond) {
- if (args.length < 2) {
+
+ var Cookies = {};
+
+
+
+ var rpc = function (ctx, data, respond) {
+ if (!data.length) {
return void respond("INSUFFICIENT_ARGS");
+ } else if (data.length !== 1) {
+ console.log(data.length);
}
- var signed = args[0];
- var publicKey = args[1];
+ var msg = data[0].slice(0);
+ var signature = msg.shift();
+ var publicKey = msg.shift();
+ var cookie = parseCookie(msg.shift());
- var msg = checkSignature(signed, publicKey);
- if (!msg) {
+ if (!cookie) {
+ // no cookie is fine if the RPC is to get a cookie
+ if (msg[0] !== 'COOKIE') {
+ return void respond('NO_COOKIE');
+ }
+ } else if (!isValidCookie(cookie)) { // is it a valid cookie?
+ return void respond('INVALID_COOKIE');
+ }
+
+ var serialized = JSON.stringify(msg);
+
+ if (!(serialized && publicKey)) {
+ return void respond('INVALID_MESSAGE_OR_PUBLIC_KEY');
+ }
+
+ if (checkSignature(serialized, signature, publicKey) !== true) {
+ return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY");
+ }
+
+ if (!msg.length) {
return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY");
}
@@ -60,6 +139,8 @@ RPC.create = function (config, cb) {
}
switch (msg[0]) {
+ case 'COOKIE':
+ return void respond(void 0, makeCookie());
case 'ECHO':
return void respond(void 0, msg);
case 'RESET':
diff --git a/www/common/rpc.js b/www/common/rpc.js
index 25248b147..5c176963a 100644
--- a/www/common/rpc.js
+++ b/www/common/rpc.js
@@ -1,8 +1,6 @@
define([
- '/common/encode.js',
-
'/bower_components/tweetnacl/nacl-fast.min.js',
-], function (Encode) {
+], function () {
var MAX_LAG_BEFORE_TIMEOUT = 30000;
var Nacl = window.nacl;
@@ -11,34 +9,27 @@ define([
.toString(32).replace(/\./g, '');
};
- var signMsg = function (type, msg, signKey) {
- var toSign = JSON.stringify([type, msg]);
- var buffer = Nacl.util.decodeUTF8(toSign);
- return Nacl.util.encodeBase64(Nacl.sign(buffer, signKey));
+ var signMsg = function (data, signKey) {
+ var buffer = Nacl.util.decodeUTF8(JSON.stringify(data));
+ return Nacl.util.encodeBase64(Nacl.sign.detached(buffer, signKey));
};
- /*
+/*
types of messages:
pin -> hash
unpin -> hash
getHash -> hash
getTotalSize -> bytes
getFileSize -> bytes
-
- */
-
-/* RPC communicates only with the history keeper
- messages have the format:
- [TYPE, txid, msg]
*/
- var sendMsg = function (ctx, type, signed, id, cb) {
+
+ var sendMsg = function (ctx, data, cb) {
var network = ctx.network;
var hkn = network.historyKeeper;
var txid = uid();
ctx.pending[txid] = cb;
-
- return network.sendto(hkn, JSON.stringify([txid, signed, id]));
+ return network.sendto(hkn, JSON.stringify([txid, data]));
};
var parse = function (msg) {
@@ -49,20 +40,20 @@ types of messages:
}
};
-/* Returning messages have the format:
- [txid, {}]
-*/
var onMsg = function (ctx, msg) {
var parsed = parse(msg);
if (!parsed) {
- // TODO handle error
- console.log(msg);
- return;
+ return void console.error(new Error('could not parse message: %s', msg));
}
var txid = parsed[0];
var pending = ctx.pending[txid];
+
+ if (!(parsed && parsed.slice)) {
+ return void console.error('MALFORMED_RPC_RESPONSE');
+ }
+
var response = parsed.slice(1);
if (typeof(pending) === 'function') {
@@ -76,39 +67,57 @@ types of messages:
};
var create = function (network, edPrivateKey, edPublicKey) {
- var signKey = Nacl.util.decodeBase64(edPrivateKey);
+ var signKey;
try {
+ signKey = Nacl.util.decodeBase64(edPrivateKey);
if (signKey.length !== 64) {
throw new Error('private key did not match expected length of 64');
}
- } catch (err) {
- throw new Error("private signing key is not valid");
- }
+ } catch (err) { throw err; }
- // TODO validate public key as well
+ var pubBuffer;
+ try {
+ pubBuffer = Nacl.util.decodeBase64(edPublicKey);
+ if (pubBuffer.length !== 32) {
+ throw new Error('expected public key to be 32 uint');
+ }
+ } catch (err) { throw err; }
var ctx = {
- //privateKey: Encode.hexToUint8Array(edPrivateKey),
seq: new Date().getTime(),
network: network,
timeouts: {}, // timeouts
pending: {}, // callbacks
+ cookie: null,
};
- var pin = function (channel, cb) { };
-
var send = function (type, msg, cb) {
// construct a signed message...
- var signed = signMsg(type, msg, signKey);
+ var data = [type, msg];
+ var sig = signMsg(data, signKey);
- return sendMsg(ctx, type, signed, edPublicKey, cb);
+ data.unshift(ctx.cookie); //
+ data.unshift(edPublicKey);
+ data.unshift(sig);
+
+ // [sig, edPublicKey, cookie, type, msg]
+ return sendMsg(ctx, data, cb);
};
+
+ var getCookie = function (cb) {
+ send('COOKIE', "", function (e, msg) {
+ console.log('cookie message', e, msg);
+ cb(e, msg);
+ });
+ };
+
network.on('message', function (msg, sender) {
onMsg(ctx, msg);
});
return {
send: send,
+ ready: getCookie,
};
};
diff --git a/www/examples/rpc/main.js b/www/examples/rpc/main.js
index ee01c7897..5802885c8 100644
--- a/www/examples/rpc/main.js
+++ b/www/examples/rpc/main.js
@@ -24,65 +24,72 @@ define([
b: 7,
};
- // console.log(payload);
- rpc.send('ECHO', payload, function (e, msg) {
- if (e) { return void console.error(e); }
- console.log(msg);
- });
+ rpc.ready(function () {
- // test a non-existent RPC call
- rpc.send('PEWPEW', ['pew'], function (e, msg) {
- if (e) {
- if (e === 'UNSUPPORTED_RPC_CALL') { return; }
- return void console.error(e);
- }
- console.log(msg);
- });
+ // console.log(payload);
+ rpc.send('ECHO', payload, function (e, msg) {
+ if (e) { return void console.error(e); }
+ console.log(msg);
+ });
- var list = Cryptpad.getUserChannelList();
- if (list.length) {
- rpc.send('GET_FILE_SIZE', list[0], function (e, msg) {
+ // test a non-existent RPC call
+ rpc.send('PEWPEW', ['pew'], function (e, msg) {
if (e) {
+ if (e === 'UNSUPPORTED_RPC_CALL') { return; }
return void console.error(e);
}
console.log(msg);
});
- }
-
- rpc.send('GET_FILE_SIZE', 'pewpew', function (e, msg) {
- if (e) {
- if (e === 'INVALID_CHAN') { return; }
- return void console.error(e);
- }
- console.log(msg);
- });
-
- rpc.send('GET_FILE_SIZE', '26f014b2ab959418605ea37a6785f317', function (e, msg) {
- if (e) {
- if (e === 'ENOENT') { return; }
- return void console.error(e);
- }
- console.error("EXPECTED ENOENT");
- console.log(msg);
- });
-
- (function () {
- var bytes = 0;
- list.forEach(function (chan) {
- rpc.send('GET_FILE_SIZE', chan, function (e, msg) {
- if (e) { return void console.error(e); }
- if (msg && msg[0] && typeof(msg[0]) === 'number') {
- bytes += msg[0];
- console.log(bytes);
- } else {
- console.log(msg);
-
+ var list = Cryptpad.getUserChannelList();
+ if (list.length) {
+ rpc.send('GET_FILE_SIZE', list[0], function (e, msg) {
+ if (e) {
+ return void console.error(e);
}
+ console.log(msg);
});
- });
- }());
+ }
+ rpc.send('GET_FILE_SIZE', 'pewpew', function (e, msg) {
+ if (e) {
+ if (e === 'INVALID_CHAN') { return; }
+ return void console.error(e);
+ }
+ console.log(msg);
+ });
+
+ rpc.send('GET_FILE_SIZE', '26f014b2ab959418605ea37a6785f317', function (e, msg) {
+ if (e) {
+ if (e === 'ENOENT') { return; }
+ return void console.error(e);
+ }
+ console.error("EXPECTED ENOENT");
+ console.log(msg);
+ });
+
+ if (false) {
+ (function () {
+ var bytes = 0;
+ list.forEach(function (chan) {
+ rpc.send('GET_FILE_SIZE', chan, function (e, msg) {
+ if (e) {
+ if (e === 'ENOENT') {
+ return void console.log(e, chan);
+ }
+ return void console.error(e);
+ }
+ if (msg && msg[0] && typeof(msg[0]) === 'number') {
+ bytes += msg[0];
+ console.log(bytes);
+ } else {
+ console.log(msg);
+ }
+ });
+ });
+ }());
+ }
+ });
});
});
});