mirror of https://github.com/xwiki-labs/cryptpad
test mailboxes and RPCs from the command line, fix some minor errors
This commit is contained in:
parent
75b655e1e8
commit
dc078c1ca1
|
@ -3,19 +3,9 @@ var WebSocket = require("ws"); // jshint ignore:line
|
||||||
var nThen = require("nthen");
|
var nThen = require("nthen");
|
||||||
|
|
||||||
var Util = require("../../www/common/common-util");
|
var Util = require("../../www/common/common-util");
|
||||||
var Rpc = require("../../www/common/rpc");
|
|
||||||
|
|
||||||
var Nacl = require("tweetnacl");
|
var Nacl = require("tweetnacl");
|
||||||
|
|
||||||
var makeKeys = function () {
|
|
||||||
var keys = Nacl.sign.keyPair.fromSeed(Nacl.randomBytes(Nacl.sign.seedLength));
|
|
||||||
return {
|
|
||||||
secret: Nacl.util.encodeBase64(keys.secretKey),
|
|
||||||
public: Nacl.util.encodeBase64(keys.publicKey),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var Client = module.exports;
|
var Client = module.exports;
|
||||||
|
|
||||||
var createNetwork = Client.createNetwork = function (url, cb) {
|
var createNetwork = Client.createNetwork = function (url, cb) {
|
||||||
|
@ -30,8 +20,7 @@ var createNetwork = Client.createNetwork = function (url, cb) {
|
||||||
.on('error', function (err) {
|
.on('error', function (err) {
|
||||||
CB(err);
|
CB(err);
|
||||||
})
|
})
|
||||||
.on('close', function (err) {
|
.on('close', function (/* err */) {
|
||||||
console.log("CLOSE_ERROR", err);
|
|
||||||
delete info.websocket;
|
delete info.websocket;
|
||||||
});
|
});
|
||||||
return info.websocket;
|
return info.websocket;
|
||||||
|
@ -102,21 +91,6 @@ Client.create = function (config, cb) {
|
||||||
w.abort();
|
w.abort();
|
||||||
CB(err);
|
CB(err);
|
||||||
});
|
});
|
||||||
}).nThen(function (w) {
|
|
||||||
// connect to the anonRpc
|
|
||||||
Rpc.createAnonymous(config.network, w(function (err, rpc) {
|
|
||||||
if (err) {
|
|
||||||
return void CB('ANON_RPC_CONNECT_ERR');
|
|
||||||
}
|
|
||||||
client.anonRpc = rpc;
|
|
||||||
}));
|
|
||||||
var keys = makeKeys();
|
|
||||||
Rpc.create(config.network, keys.secret, keys.public, w(function (err, rpc) {
|
|
||||||
if (err) {
|
|
||||||
return void CB('RPC_CONNECT_ERR');
|
|
||||||
}
|
|
||||||
client.rpc = rpc;
|
|
||||||
}));
|
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
CB(void 0, client);
|
CB(void 0, client);
|
||||||
});
|
});
|
||||||
|
|
|
@ -98,10 +98,24 @@
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||||
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
|
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
|
||||||
},
|
},
|
||||||
|
"chainpad-crypto": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chainpad-crypto/-/chainpad-crypto-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-7MJ7qPz/C4sJPsDhPMjdSRmliOCPoRO0XM1vUomcgXA6HINlW+if9AAt/H4q154nYhZ/b57njgC6cWgd/RDidg==",
|
||||||
|
"requires": {
|
||||||
|
"tweetnacl": "git://github.com/dchest/tweetnacl-js.git#v0.12.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": {
|
||||||
|
"version": "git://github.com/dchest/tweetnacl-js.git#8a21381d696acdc4e99c9f706f1ad23285795f79",
|
||||||
|
"from": "git://github.com/dchest/tweetnacl-js.git#v0.12.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"chainpad-server": {
|
"chainpad-server": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-3.0.5.tgz",
|
||||||
"integrity": "sha512-NRfV7FFBEYy4ZVX7h0P5znu55X8v5K4iGWeMGihkfWZLKu70GmCPUTwpBCP79dUvnCToKEa4/e8aoSPcvZC8pA==",
|
"integrity": "sha512-USKOMSHsNjnme81Qy3nQ+ji9eCkBPokYH4T82LVHAI0aayTSCXcTPUDLVGDBCRqe8NsXU4io1WPXn1KiZwB8fA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"nthen": "^0.1.8",
|
"nthen": "^0.1.8",
|
||||||
"pull-stream": "^3.6.9",
|
"pull-stream": "^3.6.9",
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
"url": "git://github.com/xwiki-labs/cryptpad.git"
|
"url": "git://github.com/xwiki-labs/cryptpad.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chainpad-server": "~3.0.2",
|
"chainpad-crypto": "^0.2.2",
|
||||||
|
"chainpad-server": "^3.0.5",
|
||||||
"express": "~4.16.0",
|
"express": "~4.16.0",
|
||||||
"fs-extra": "^7.0.0",
|
"fs-extra": "^7.0.0",
|
||||||
"get-folder-size": "^2.0.1",
|
"get-folder-size": "^2.0.1",
|
||||||
|
|
|
@ -1,7 +1,38 @@
|
||||||
|
/* globals process */
|
||||||
|
|
||||||
var Client = require("../../lib/client/");
|
var Client = require("../../lib/client/");
|
||||||
var Mailbox = require("../../www/bower_components/chainpad-crypto").Mailbox;
|
var Mailbox = require("../../www/bower_components/chainpad-crypto").Mailbox;
|
||||||
var Nacl = require("tweetnacl");
|
var Nacl = require("tweetnacl");
|
||||||
var nThen = require("nthen");
|
var nThen = require("nthen");
|
||||||
|
var Rpc = require("../../www/common/rpc");
|
||||||
|
var Hash = require("../../www/common/common-hash");
|
||||||
|
var CpNetflux = require("../../www/bower_components/chainpad-netflux");
|
||||||
|
|
||||||
|
var createMailbox = function (config, cb) {
|
||||||
|
var webchannel;
|
||||||
|
|
||||||
|
CpNetflux.start({
|
||||||
|
network: config.network,
|
||||||
|
channel: config.channel,
|
||||||
|
crypto: config.crypto,
|
||||||
|
owners: [ config.edPublic ],
|
||||||
|
|
||||||
|
noChainPad: true,
|
||||||
|
onConnect: function (wc /*, sendMessage */) {
|
||||||
|
webchannel = wc;
|
||||||
|
},
|
||||||
|
onMessage: function (/* msg, user, vKey, isCp, hash, author */) {
|
||||||
|
|
||||||
|
},
|
||||||
|
onReady: function () {
|
||||||
|
cb(void 0, webchannel);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on('unhandledRejection', function (err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
var makeCurveKeys = function () {
|
var makeCurveKeys = function () {
|
||||||
var pair = Nacl.box.keyPair();
|
var pair = Nacl.box.keyPair();
|
||||||
|
@ -11,14 +42,166 @@ var makeCurveKeys = function () {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Client.create(function (err, client) {
|
var makeEdKeys = function () {
|
||||||
if (err) { return void console.error(err); }
|
var keys = Nacl.sign.keyPair.fromSeed(Nacl.randomBytes(Nacl.sign.seedLength));
|
||||||
|
return {
|
||||||
|
edPrivate: Nacl.util.encodeBase64(keys.secretKey),
|
||||||
|
edPublic: Nacl.util.encodeBase64(keys.publicKey),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var EMPTY_ARRAY_HASH = 'slspTLTetp6gCkw88xE5BIAbYBXllWvQGahXCx/h1gQOlE7zze4W0KRlA8puZZol8hz5zt3BPzUqPJgTjBXWrw==';
|
||||||
|
|
||||||
|
var createUser = function (config, cb) {
|
||||||
|
// config should contain keys for a team rpc (ed)
|
||||||
|
// teamEdKeys
|
||||||
|
|
||||||
|
var user;
|
||||||
|
nThen(function (w) {
|
||||||
|
Client.create(w(function (err, client) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
return void cb(err);
|
||||||
|
}
|
||||||
|
user = client;
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
// make all the parameters you'll need
|
||||||
|
|
||||||
|
var network = user.network = user.config.network;
|
||||||
|
user.edKeys = makeEdKeys();
|
||||||
|
|
||||||
|
user.curveKeys = makeCurveKeys();
|
||||||
|
user.mailbox = Mailbox.createEncryptor(user.curveKeys);
|
||||||
|
user.mailboxChannel = Hash.createChannelId();
|
||||||
|
|
||||||
|
// create an anon rpc for alice
|
||||||
|
Rpc.createAnonymous(network, w(function (err, rpc) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
user.shutdown();
|
||||||
|
return void console.error('ANON_RPC_CONNECT_ERR');
|
||||||
|
}
|
||||||
|
user.anonRpc = rpc;
|
||||||
|
}));
|
||||||
|
|
||||||
|
Rpc.create(network, user.edKeys.edPrivate, user.edKeys.edPublic, w(function (err, rpc) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
user.shutdown();
|
||||||
|
console.error(err);
|
||||||
|
return console.log('RPC_CONNECT_ERR');
|
||||||
|
}
|
||||||
|
user.rpc = rpc;
|
||||||
|
}));
|
||||||
|
|
||||||
|
Rpc.create(network, config.teamEdKeys.edPrivate, config.teamEdKeys.edPublic, w(function (err, rpc) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
user.shutdown();
|
||||||
|
return console.log('RPC_CONNECT_ERR');
|
||||||
|
}
|
||||||
|
user.team_rpc = rpc;
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
// some basic sanity checks...
|
||||||
|
user.rpc.send('GET_HASH', user.edKeys.edPublic, w(function (err, hash) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
return void cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash || hash[0] !== EMPTY_ARRAY_HASH) {
|
||||||
|
console.error("EXPECTED EMPTY ARRAY HASH");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
// create and subscribe to your mailbox
|
||||||
|
createMailbox({
|
||||||
|
network: user.network,
|
||||||
|
channel: user.mailboxChannel,
|
||||||
|
crypto: user.mailbox,
|
||||||
|
edPublic: user.edKeys.edPublic,
|
||||||
|
}, w(function (err, wc) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
console.error("Mailbox creation error");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
wc.leave();
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
// confirm that you own your mailbox
|
||||||
|
user.anonRpc.send("GET_METADATA", user.mailboxChannel, w(function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
return void cb(err);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (data[0].owners[0] !== user.edKeys.edPublic) {
|
||||||
|
throw new Error("INCORRECT MAILBOX OWNERSHIP METADATA");
|
||||||
|
}
|
||||||
|
} catch (err2) {
|
||||||
|
w.abort();
|
||||||
|
return void cb(err2);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
|
||||||
|
}).nThen(function () {
|
||||||
|
|
||||||
|
cb(void 0, user);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var alice, bob;
|
||||||
|
|
||||||
|
nThen(function (w) {
|
||||||
|
var sharedConfig = {
|
||||||
|
teamEdKeys: makeEdKeys(),
|
||||||
|
};
|
||||||
|
|
||||||
|
createUser(sharedConfig, w(function (err, _alice) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
return void console.log(err);
|
||||||
|
}
|
||||||
|
alice = _alice;
|
||||||
|
}));
|
||||||
|
createUser(sharedConfig, w(function (err, _bob) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
return void console.log(err);
|
||||||
|
}
|
||||||
|
bob = _bob;
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
// Alice sends a message to Bob's mailbox
|
||||||
|
|
||||||
|
|
||||||
|
var message = alice.mailbox.encrypt(JSON.stringify({
|
||||||
|
type: "CHEESE",
|
||||||
|
author: alice.curveKeys.curvePublic,
|
||||||
|
content: {
|
||||||
|
text: "CAMEMBERT",
|
||||||
|
}
|
||||||
|
}), bob.curveKeys.curvePublic);
|
||||||
|
|
||||||
|
alice.anonRpc.send('WRITE_PRIVATE_MESSAGE', [bob.mailboxChannel, message], w(function (err, response) {
|
||||||
|
if (err) {
|
||||||
|
return void console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX validate that the write was actually successful by checking its size
|
||||||
|
|
||||||
|
response = response;
|
||||||
|
// shutdown doesn't work, so we need to do this instead
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
|
||||||
|
nThen(function () {
|
||||||
|
|
||||||
nThen(function () { // BASIC KEY MANAGEMENT
|
|
||||||
// generate keys with login
|
|
||||||
// signing keys
|
|
||||||
// curve keys
|
|
||||||
// drive
|
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
// make a drive
|
// make a drive
|
||||||
// pin it
|
// pin it
|
||||||
|
@ -46,29 +229,9 @@ Client.create(function (err, client) {
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
}).nThen(function () {
|
||||||
var channel = "d34ebe83931382fcad9fe2e2d0e2cb5f"; // channel
|
alice.shutdown();
|
||||||
var recipient = "e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmw="; // curvePublic
|
bob.shutdown();
|
||||||
|
|
||||||
// curve keys
|
|
||||||
var keys = makeCurveKeys();
|
|
||||||
var cryptor = Mailbox.createEncryptor(keys);
|
|
||||||
|
|
||||||
var message = cryptor.encrypt(JSON.stringify({
|
|
||||||
type: "CHEESE",
|
|
||||||
author: keys.curvePublic,
|
|
||||||
content: {
|
|
||||||
text: "CAMEMBERT",
|
|
||||||
}
|
|
||||||
}), recipient);
|
|
||||||
|
|
||||||
client.anonRpc.send('WRITE_PRIVATE_MESSAGE', [channel, message], function (err, response) {
|
|
||||||
if (err) {
|
|
||||||
return void console.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
response = response;
|
|
||||||
// shutdown doesn't work, so we need to do this instead
|
|
||||||
client.shutdown();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
(function () {
|
(function (window) {
|
||||||
var factory = function (Util, Crypto, Nacl) {
|
var factory = function (Util, Crypto, Nacl) {
|
||||||
var Hash = window.CryptPad_Hash = {};
|
var Hash = window.CryptPad_Hash = {};
|
||||||
|
|
||||||
|
@ -547,4 +547,4 @@ Version 1
|
||||||
} else {
|
} else {
|
||||||
// unsupported initialization
|
// unsupported initialization
|
||||||
}
|
}
|
||||||
}());
|
}(typeof(window) !== 'undefined'? window : {}));
|
||||||
|
|
|
@ -19,11 +19,7 @@ var factory = function (Util, Nacl) {
|
||||||
// and finally sends it off to the historyKeeper, which delegates its
|
// and finally sends it off to the historyKeeper, which delegates its
|
||||||
// processing to the RPC submodule
|
// processing to the RPC submodule
|
||||||
var sendMsg = function (ctx, data, cb) {
|
var sendMsg = function (ctx, data, cb) {
|
||||||
// enforce async behaviour
|
if (typeof(cb) !== 'function') { throw new Error('expected callback'); }
|
||||||
setTimeout(function () {
|
|
||||||
if (typeof(cb) !== 'function') {
|
|
||||||
return console.error('expected callback');
|
|
||||||
}
|
|
||||||
|
|
||||||
var network = ctx.network;
|
var network = ctx.network;
|
||||||
var hkn = network.historyKeeper;
|
var hkn = network.historyKeeper;
|
||||||
|
@ -38,7 +34,6 @@ var factory = function (Util, Nacl) {
|
||||||
pending.called = 0;
|
pending.called = 0;
|
||||||
|
|
||||||
return network.sendto(hkn, JSON.stringify([txid, data]));
|
return network.sendto(hkn, JSON.stringify([txid, data]));
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var matchesAnon = function (ctx, txid) {
|
var matchesAnon = function (ctx, txid) {
|
||||||
|
@ -190,9 +185,11 @@ var factory = function (Util, Nacl) {
|
||||||
connected: true,
|
connected: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var send = ctx.send = function (type, msg, cb) {
|
var send = ctx.send = function (type, msg, _cb) {
|
||||||
|
var cb = Util.mkAsync(_cb);
|
||||||
|
|
||||||
if (!ctx.connected && type !== 'COOKIE') {
|
if (!ctx.connected && type !== 'COOKIE') {
|
||||||
return void Util.mkAsync(cb)("DISCONNECTED");
|
return void cb("DISCONNECTED");
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct a signed message...
|
// construct a signed message...
|
||||||
|
@ -233,12 +230,9 @@ var factory = function (Util, Nacl) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
send.unauthenticated = function (type, msg, cb) {
|
send.unauthenticated = function (type, msg, _cb) {
|
||||||
if (!ctx.connected) {
|
var cb = Util.mkAsync(_cb);
|
||||||
return void setTimeout(function () {
|
if (!ctx.connected) { return void cb('DISCONNECTED'); }
|
||||||
cb('DISCONNECTED');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct an unsigned message
|
// construct an unsigned message
|
||||||
var data = [null, keys.publicKeyString, null, type, msg];
|
var data = [null, keys.publicKeyString, null, type, msg];
|
||||||
|
@ -284,8 +278,10 @@ var factory = function (Util, Nacl) {
|
||||||
return initAuthenticatedRpc(networkContext, keys);
|
return initAuthenticatedRpc(networkContext, keys);
|
||||||
};
|
};
|
||||||
|
|
||||||
var create = function (network, edPrivateKey, edPublicKey, cb) {
|
var create = function (network, edPrivateKey, edPublicKey, _cb) {
|
||||||
if (typeof(cb) !== 'function') { throw new Error("expected callback"); }
|
if (typeof(_cb) !== 'function') { throw new Error("expected callback"); }
|
||||||
|
|
||||||
|
var cb = Util.mkAsync(_cb);
|
||||||
|
|
||||||
var signKey;
|
var signKey;
|
||||||
|
|
||||||
|
@ -335,12 +331,9 @@ var factory = function (Util, Nacl) {
|
||||||
// any particular network will only ever need one anonymous rpc
|
// any particular network will only ever need one anonymous rpc
|
||||||
networkContext.anon = ctx;
|
networkContext.anon = ctx;
|
||||||
|
|
||||||
ctx.send = function (type, msg, cb) {
|
ctx.send = function (type, msg, _cb) {
|
||||||
if (!ctx.connected) {
|
var cb = Util.mkAsync(_cb);
|
||||||
return void setTimeout(function () {
|
if (!ctx.connected) { return void cb('DISCONNECTED'); }
|
||||||
cb('DISCONNECTED');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct an unsigned message...
|
// construct an unsigned message...
|
||||||
var data = [type, msg];
|
var data = [type, msg];
|
||||||
|
@ -382,7 +375,10 @@ var factory = function (Util, Nacl) {
|
||||||
return networkContext.anon || initAnonRpc(networkContext);
|
return networkContext.anon || initAnonRpc(networkContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
var createAnonymous = function (network, cb) {
|
var createAnonymous = function (network, _cb) {
|
||||||
|
// enforce asynchrony
|
||||||
|
var cb = Util.mkAsync(_cb);
|
||||||
|
|
||||||
if (typeof(cb) !== 'function') { throw new Error("expected callback"); }
|
if (typeof(cb) !== 'function') { throw new Error("expected callback"); }
|
||||||
if (!network) { return void cb('NO_NETWORK'); }
|
if (!network) { return void cb('NO_NETWORK'); }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue