diff --git a/lib/client/index.js b/lib/client/index.js new file mode 100644 index 000000000..b2cfec437 --- /dev/null +++ b/lib/client/index.js @@ -0,0 +1,119 @@ +var Netflux = require("netflux-websocket"); +var WebSocket = require("ws"); // jshint ignore:line +var nThen = require("nthen"); + +var Util = require("../../www/common/common-util"); +var Rpc = require("../../www/common/rpc"); + +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 createNetwork = Client.createNetwork = function (url, cb) { + var CB = Util.once(cb); + + var info = {}; + + Netflux.connect(url, function (url) { + info.websocket = new WebSocket(url) + .on('error', function (err) { + console.log(err); + }) + .on('close', function (err) { + console.log("close"); + console.log(err); + }); + return info.websocket; + }).then(function (network) { + info.network = network; + CB(void 0, info); + }, function (err) { + CB(err); + }); +}; + +var die = function (client) { + var disconnect = Util.find(client, ['config', 'network', 'disconnect']); + if (typeof(disconnect) === 'function') { + disconnect(); + } else { + console.error("disconnect was not a function"); + } + var close = Util.find(client, ['config', 'websocket', 'close']); + if (typeof(close) === 'function') { + client.config.websocket.close(); + } else { + console.error("close was not a function"); + } +}; + +Client.create = function (config, cb) { + if (typeof(config) === 'function') { + cb = config; + config = {}; + } + var client = { + config: config, + }; + var CB = Util.once(function (err, arg) { + if (err) { die(client); } + cb(err, arg); + }); + + client.shutdown = function () { + die(client); + }; + + nThen(function (w) { + if (config.network) { return; } + // connect to the network... + createNetwork('ws://localhost:3000/cryptpad_websocket', w(function (err, info) { + //console.log(_network); + config.network = info.network; + config.websocket = info.websocket; + })); + }).nThen(function (w) { + // make sure the network has a historyKeeper id on it + // we're responsible for adding it + if (config.network.historyKeeper) { return; } + var channel = Util.uint8ArrayToHex(Nacl.randomBytes(16)); + config.network.join(channel).then(w(function (wc) { + wc.members.some(function (member) { + if (member.length !== 16) { return; } + config.network.historyKeeper = member; + return true; + }); + wc.leave(); + }), function (err) { + w.abort(); + 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 () { + CB(void 0, client); + }); +}; + diff --git a/package-lock.json b/package-lock.json index 0fb182b2d..4c32aff68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cryptpad", - "version": "3.0.0", + "version": "3.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -800,6 +800,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "netflux-websocket": { + "version": "0.1.20", + "resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-0.1.20.tgz", + "integrity": "sha512-svFkw4ol4gmkcXKnx5kF/8tR9mmtTCDzUlLy4mSlcNl/4iWlbDmgwp/+aJ3nqtv8fg12m+DAFGX2+fbC0//dcg==" + }, "nthen": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/nthen/-/nthen-0.1.8.tgz", diff --git a/package.json b/package.json index 8034e1b33..8bd93b82d 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "chainpad-server": "~3.0.2", "express": "~4.16.0", "fs-extra": "^7.0.0", + "get-folder-size": "^2.0.1", + "netflux-websocket": "^0.1.20", "nthen": "0.1.8", "pull-stream": "^3.6.1", "replify": "^1.2.0", @@ -18,8 +20,7 @@ "sortify": "^1.0.4", "stream-to-pull-stream": "^1.7.2", "tweetnacl": "~0.12.2", - "ws": "^3.3.1", - "get-folder-size": "^2.0.1" + "ws": "^3.3.1" }, "devDependencies": { "flow-bin": "^0.59.0", @@ -38,6 +39,7 @@ "lint:less": "./node_modules/lesshint/bin/lesshint -c ./.lesshintrc ./customize.dist/src/less2/", "flow": "./node_modules/.bin/flow", "test": "node scripts/TestSelenium.js", + "test-rpc": "cd scripts && node test-rpc", "template": "cd customize.dist/src && for page in ../index.html ../privacy.html ../terms.html ../about.html ../contact.html ../what-is-cryptpad.html ../features.html ../../www/login/index.html ../../www/register/index.html ../../www/user/index.html;do echo $page; cp template.html $page; done;" } } diff --git a/scripts/test-rpc.js b/scripts/test-rpc.js new file mode 100644 index 000000000..79177464d --- /dev/null +++ b/scripts/test-rpc.js @@ -0,0 +1,43 @@ +/* globals process */ +var Client = require("../lib/client/"); +var Mailbox = require("../www/bower_components/chainpad-crypto").Mailbox; +var Nacl = require("tweetnacl"); + +var makeKeys = function () { + var pair = Nacl.box.keyPair(); + return { + curvePrivate: Nacl.util.encodeBase64(pair.secretKey), + curvePublic: Nacl.util.encodeBase64(pair.publicKey), + }; +}; + +Client.create(function (err, client) { + if (err) { + console.error(err); + process.exit(1); + } + + var channel = "d34ebe83931382fcad9fe2e2d0e2cb5f"; // channel + var recipient = "e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmw="; // curvePublic + + var keys = makeKeys(); + 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(); + }); +});