|
|
|
@ -1,7 +1,38 @@ |
|
|
|
/* globals process */ |
|
|
|
|
|
|
|
var Client = require("../../lib/client/"); |
|
|
|
var Mailbox = require("../../www/bower_components/chainpad-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 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 pair = Nacl.box.keyPair(); |
|
|
|
@ -11,14 +42,166 @@ var makeCurveKeys = function () { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Client.create(function (err, client) { |
|
|
|
if (err) { return void console.error(err); } |
|
|
|
var makeEdKeys = function () { |
|
|
|
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 () { |
|
|
|
// make a drive
|
|
|
|
// pin it
|
|
|
|
@ -46,29 +229,9 @@ Client.create(function (err, client) { |
|
|
|
}).nThen(function () { |
|
|
|
|
|
|
|
}); |
|
|
|
}).nThen(function () { |
|
|
|
alice.shutdown(); |
|
|
|
bob.shutdown(); |
|
|
|
}); |
|
|
|
|
|
|
|
var channel = "d34ebe83931382fcad9fe2e2d0e2cb5f"; // channel
|
|
|
|
var recipient = "e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmw="; // curvePublic
|
|
|
|
|
|
|
|
// 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(); |
|
|
|
}); |
|
|
|
}); |