diff --git a/.gitignore b/.gitignore index a75bb20e2..996e55b97 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ messages.log www/scratch data npm-debug.log +pins/ diff --git a/rpc.js b/rpc.js index 3c4e3507b..2aa491cdb 100644 --- a/rpc.js +++ b/rpc.js @@ -3,11 +3,7 @@ var Nacl = require("tweetnacl"); var RPC = module.exports; -var pin = function (ctx, cb) { }; -var unpin = function (ctx, cb) { }; -var getHash = function (ctx, cb) { }; -var getTotalSize = function (ctx, cb) { }; -var getFileSize = function (ctx, cb) { }; +var Store = require("./storage/file"); var isValidChannel = function (chan) { return /^[a-fA-F0-9]/.test(chan); @@ -15,33 +11,38 @@ var isValidChannel = function (chan) { var makeCookie = function (seq) { return [ - Math.floor(new Date() / (1000*60*60*24)), + Math.floor((+new Date()) / (1000*60*60*24)), process.pid, // jshint ignore:line - seq - ].join('|'); + //seq + ]; + // .join('|'); }; var parseCookie = function (cookie) { if (!(cookie && cookie.split)) { return null; } var parts = cookie.split('|'); - if (parts.length !== 3) { return null; } + if (parts.length !== 2) { return null; } var c = {}; c.time = new Date(parts[0]); - c.pid = parts[1]; - c.seq = parts[2]; + c.pid = Number(parts[1]); + //c.seq = parts[2]; return c; }; var isValidCookie = function (ctx, cookie) { var now = +new Date(); + + if (!(cookie && cookie.time)) { return false; } + if (now - cookie.time > 300000) { // 5 minutes return false; } // different process. try harder if (process.pid !== cookie.pid) { // jshint ignore:line + console.log('pid does not match'); return false; } @@ -90,6 +91,84 @@ var checkSignature = function (signedMsg, signature, publicKey) { return Nacl.sign.detached.verify(signedBuffer, signatureBuffer, pubBuffer); }; +var storeMessage = function (store, publicKey, msg, cb) { + store.message(publicKey, JSON.stringify(msg), cb); +}; + +var pinChannel = function (store, publicKey, channel, cb) { + store.message(store, publicKey, ['PIN', channel], cb); +}; + +var unpinChannel = function (store, publicKey, channel, cb) { + store.message(store, publicKey, ['UNPIN', channel], cb); +}; + +var getChannelList = function (store, publicKey, cb) { + // to accumulate pinned channels + var pins = {}; + + store.getMessages(publicKey, function (msg) { + // handle messages... + var parsed; + try { + parsed = JSON.parse(msg); + + switch (parsed[0]) { + case 'PIN': + pins[parsed[1]] = true; + break; + case 'UNPIN': + pins[parsed[1]] = false; + break; + case 'RESET': + Object.keys(pins).forEach(function (pin) { + pins[pin] = false; + }); + break; + default: + console.error('invalid message read from store'); + } + } catch (e) { + console.log('invalid message read from store'); + console.error(e); + } + }, function () { + // no more messages + var pinned = Object.keys(pins).filter(function (pin) { + return pins[pin]; + }); + + cb(pinned); + }); + +}; + +var hashChannelList = function (A) { + var uniques = []; + + A.forEach(function (a) { + if (uniques.indexOf(a) === -1) { uniques.push(a); } + }); + uniques.sort(); + + var hash = Nacl.util.encodeBase64(Nacl.hash(Nacl + .util.decodeUTF8(JSON.stringify(uniques)))); + + return hash; +}; + + +var getHash = function (store, publicKey, cb) { + getChannelList(store, publicKey, function (channels) { + cb(hashChannelList(channels)); + }); +}; + +var resetUserPins = function (store, publicKey, channelList, cb) { + // TODO + cb('NOT_IMPLEMENTED'); +}; + RPC.create = function (config, cb) { // load pin-store... @@ -97,7 +176,7 @@ RPC.create = function (config, cb) { var Cookies = {}; - + var store; var rpc = function (ctx, data, respond) { if (!data.length) { @@ -107,6 +186,7 @@ RPC.create = function (config, cb) { } var msg = data[0].slice(0); + var signature = msg.shift(); var publicKey = msg.shift(); var cookie = parseCookie(msg.shift()); @@ -116,7 +196,7 @@ RPC.create = function (config, cb) { if (msg[0] !== 'COOKIE') { return void respond('NO_COOKIE'); } - } else if (!isValidCookie(cookie)) { // is it a valid cookie? + } else if (!isValidCookie(Cookies, cookie)) { // is it a valid cookie? return void respond('INVALID_COOKIE'); } @@ -144,13 +224,21 @@ RPC.create = function (config, cb) { case 'ECHO': return void respond(void 0, msg); case 'RESET': - return void respond('NOT_IMPLEMENTED', msg); + return resetUserPins(store, publicKey, [], function (e) { + return void respond('NOT_IMPLEMENTED', msg); + }); case 'PIN': - return void respond('NOT_IMPLEMENTED', msg); + return pinChannel(store, publicKey, msg[1], function (e) { + respond(e); + }); case 'UNPIN': - return void respond('NOT_IMPLEMENTED', msg); + return unpinChannel(store, publicKey, msg[1], function (e) { + respond(e); + }); case 'GET_HASH': - return void respond('NOT_IMPLEMENTED', msg); + return void getHash(store, publicKey, function (hash) { + respond(void 0, hash); + }); case 'GET_TOTAL_SIZE': return void respond('NOT_IMPLEMENTED', msg); case 'GET_FILE_SIZE': @@ -167,6 +255,11 @@ RPC.create = function (config, cb) { } }; - cb(void 0, rpc); + Store.create({ + filePath: './pins' + }, function (s) { + store = s; + cb(void 0, rpc); + }); }; diff --git a/www/common/rpc.js b/www/common/rpc.js index 5c176963a..5fc252fda 100644 --- a/www/common/rpc.js +++ b/www/common/rpc.js @@ -66,7 +66,7 @@ types of messages: } }; - var create = function (network, edPrivateKey, edPublicKey) { + var create = function (network, edPrivateKey, edPublicKey, cb) { var signKey; try { @@ -74,15 +74,19 @@ types of messages: if (signKey.length !== 64) { throw new Error('private key did not match expected length of 64'); } - } catch (err) { throw err; } + } catch (err) { + return void cb(err); + } var pubBuffer; try { pubBuffer = Nacl.util.decodeBase64(edPublicKey); if (pubBuffer.length !== 32) { - throw new Error('expected public key to be 32 uint'); + return void cb('expected public key to be 32 uint'); } - } catch (err) { throw err; } + } catch (err) { + return void cb(err); + } var ctx = { seq: new Date().getTime(), @@ -97,7 +101,12 @@ types of messages: var data = [type, msg]; var sig = signMsg(data, signKey); - data.unshift(ctx.cookie); // + if (ctx.cookie && ctx.cookie.join) { + data.unshift(ctx.cookie.join('|')); // + } else { + data.unshift(ctx.cookie); + } + data.unshift(edPublicKey); data.unshift(sig); @@ -105,20 +114,21 @@ types of messages: 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, - }; + + send('COOKIE', "", function (e, msg) { + if (e) { return void cb(e); } + + console.log(msg); // DO something with the returned cookie + ctx.cookie = msg; + + cb(void 0, { + send: send, + }); + }); + }; return { create: create }; diff --git a/www/examples/rpc/main.js b/www/examples/rpc/main.js index 5802885c8..5ddccb2d7 100644 --- a/www/examples/rpc/main.js +++ b/www/examples/rpc/main.js @@ -17,15 +17,12 @@ define([ var edPrivate = proxy.edPrivate; var edPublic = proxy.edPublic; - var rpc = RPC.create(network, edPrivate, edPublic); - var payload = { a: Math.floor(Math.random() * 1000), b: 7, }; - rpc.ready(function () { - + RPC.create(network, edPrivate, edPublic, function (e, rpc) { // console.log(payload); rpc.send('ECHO', payload, function (e, msg) { if (e) { return void console.error(e); } @@ -68,6 +65,25 @@ define([ console.log(msg); }); + (function () { + // compute what you think the hash should be + + // then ask the server if what it has matches your records + rpc.send('GET_HASH', edPublic, function (e, hash) { + if (e) { return void console.error(e); } + + + console.log("user pins hash is [%s]", hash); + // if it does, awesome! + // you should be able to pin and unpin things easily + + // if it doesn't, send a reset, and start re-pinning + + + + }); + }()); + if (false) { (function () { var bytes = 0;