diff --git a/scripts/tests/roster.js b/scripts/tests/roster.js new file mode 100644 index 000000000..940745a26 --- /dev/null +++ b/scripts/tests/roster.js @@ -0,0 +1,3 @@ +module.exports = require("../../www/common/outer/roster.js"); + + diff --git a/scripts/tests/test-rpc.js b/scripts/tests/test-rpc.js index 8b8c806e6..e21de20c5 100644 --- a/scripts/tests/test-rpc.js +++ b/scripts/tests/test-rpc.js @@ -1,12 +1,14 @@ /* globals process */ var Client = require("../../lib/client/"); -var Mailbox = require("../../www/bower_components/chainpad-crypto").Mailbox; +var Crypto = require("../../www/bower_components/chainpad-crypto"); +var Mailbox = Crypto.Mailbox; var Nacl = require("tweetnacl"); 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 Roster = require("./roster"); var createMailbox = function (config, cb) { var webchannel; @@ -30,6 +32,15 @@ var createMailbox = function (config, cb) { }); }; +var createRoster = function (config, cb) { + Roster.create({ + network: config.network, + channel: config.channel, + owners: config.owners, + crypto: config.crypto, + }, cb); +}; + process.on('unhandledRejection', function (err) { console.error(err); }); @@ -50,11 +61,16 @@ var makeEdKeys = function () { }; }; +var makeRosterHash = function () { + return Hash.createRandomHash('pad', '');//.replace(/\/pad\//, '/roster/'); +}; + var EMPTY_ARRAY_HASH = 'slspTLTetp6gCkw88xE5BIAbYBXllWvQGahXCx/h1gQOlE7zze4W0KRlA8puZZol8hz5zt3BPzUqPJgTjBXWrw=='; var createUser = function (config, cb) { // config should contain keys for a team rpc (ed) // teamEdKeys + // rosterHash var user; nThen(function (w) { @@ -75,6 +91,26 @@ var createUser = function (config, cb) { user.mailbox = Mailbox.createEncryptor(user.curveKeys); user.mailboxChannel = Hash.createChannelId(); + //console.log(config.rosterHash); + //console.log(Hash.parseTypeHash('pad', config.rosterHash)); + + user.roster = Hash.getSecrets('pad', config.rosterHash, ''); + console.log(user.roster); + var crypto = Crypto.createEncryptor(user.roster.keys); + + console.log(crypto); + + createRoster({ + network: network, + channel: user.roster.channel, + owners: [ user.edKeys.edPublic ], + crypto: crypto, + validateKey: user.roster.validateKey, + }, w(function (err, roster) { + if (err) { return void console.error(err); } + user.roster = roster; + })); + // create an anon rpc for alice Rpc.createAnonymous(network, w(function (err, rpc) { if (err) { @@ -221,6 +257,7 @@ var alice, bob; nThen(function (w) { var sharedConfig = { teamEdKeys: makeEdKeys(), + rosterHash: makeRosterHash(), }; createUser(sharedConfig, w(function (err, _alice) { diff --git a/www/common/outer/roster.js b/www/common/outer/roster.js new file mode 100644 index 000000000..672ea790e --- /dev/null +++ b/www/common/outer/roster.js @@ -0,0 +1,98 @@ +(function () { +var factory = function (Util, Hash, CPNetflux) { + var Roster = {}; + + Roster.commands = {}; + + Roster.create = function (config, _cb) { + if (typeof(_cb) !== 'function') { throw new Error("EXPECTED_CALLBACK"); } + var cb = Util.once(Util.mkAsync(_cb)); + + if (!config.network) { return void cb("EXPECTED_NETWORK"); } + if (!config.channel) { return void cb("EXPECTED_CHANNEL"); } + if (!config.owners) { return void cb("EXPECTED_OWNERS"); } + if (!config.crypto) { return void cb("EXPECTED_CRYPTO"); } + + var roster = {}; + + /* Commands + * addUser(key, role) // owner, member + * describeUser(key, data) // mailbox, role + * removeUser(key) + */ + + /* Events + * checkpoint(id) + * description(data) + * metadata change + */ + + var ready = false; + var onReady = function (/* info */) { + ready = true; + cb(void 0, roster); + }; + + var onChannelError = function (info) { + if (!ready) { return void cb(info); } // XXX make sure we don't reconnect + console.error("CHANNEL_ERROR", info); + }; + + var onConnect = function (/* wc, sendMessage */) { + Util.both(Util.bake(console.log, "onConnect"), console.log).apply(null, arguments); + }; + + var onMessage = function (msg, user, vKey, isCp, hash /*, author */) { + if (isCp) { roster.lastKnownCp = hash; } + console.log("onMessage"); + console.log.apply(null, arguments); + }; + + + CPNetflux.start({ + lastKnownHash: config.lastKnownHash, + + network: config.network, + channel: config.channel, + + crypto: config.crypto, + validateKey: config.validateKey, + + owners: config.owners, + + onChannelError: onChannelError, + onReady: onReady, + onConnect: onConnect, + onConnectionChange: function () {}, + onMessage: onMessage, + + noChainPad: true, + }); + }; + + return Roster; +}; + + if (typeof(module) !== 'undefined' && module.exports) { + module.exports = factory( + require("../common-util"), + require("../common-hash"), + require("../../bower_components/chainpad-netflux/chainpad-netflux.js") + ); + } else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) { + define([ + '/common/common-util.js', + '/common/common-hash.js', + '/bower_components/chainpad-netflux/chainpad-netflux.js', + //'/bower_components/tweetnacl/nacl-fast.min.js', + ], function (Util, Hash, CPNF) { + return factory.apply(null, [ + Util, + Hash, + CPNF + ]); + }); + } else { + // I'm not gonna bother supporting any other kind of instanciation + } +}());