Files: 39b9c70c0e6cbb27bccacdc189c8a2f197e9959d / index.js
3289 bytesRaw
1 | var ssbKeys = require('ssb-keys') |
2 | |
3 | var chloride = require('chloride') |
4 | |
5 | function box (data, key) { |
6 | if(!data) return |
7 | var b = new Buffer(JSON.stringify(data)) |
8 | return chloride.crypto_secretbox_easy(b, key.slice(0, 24), key).toString('base64') |
9 | } |
10 | |
11 | function unbox (ctxt, key) { |
12 | //var b = new Buffer(JSON.stringify(data)) |
13 | var b = new Buffer(ctxt, 'base64') |
14 | var ptxt = chloride.crypto_secretbox_open_easy(b, key.slice(0, 24), key) |
15 | if(!ptxt) return |
16 | try { |
17 | return JSON.parse(ptxt) |
18 | } catch(err) { |
19 | console.error(err) |
20 | } |
21 | } |
22 | |
23 | |
24 | function hash(s) { |
25 | return chloride.crypto_hash_sha256( |
26 | 'string' == typeof s ? new Buffer(s, 'utf8') : s |
27 | ) |
28 | } |
29 | |
30 | var invite_key = hash("user-invites:development") |
31 | |
32 | exports.createInvite = function (seed, host, reveal, private) { |
33 | var keys = ssbKeys.generate(null, seed) //K |
34 | if(keys.id === host) |
35 | throw new Error('do not create invite with own public key') |
36 | return ssbKeys.signObj(keys, invite_key, { |
37 | type: 'invite', |
38 | invite: keys.id, |
39 | host: host, //sign our own key, to prove we created K |
40 | reveal: box(reveal, hash(hash(seed))), |
41 | private: box(private, hash(seed)) |
42 | }) |
43 | } |
44 | |
45 | exports.verifyInvitePublic = function (msg) { |
46 | if(!ssbKeys.verifyObj(msg.content.invite, invite_key, msg.content)) |
47 | throw new Error('invalid guest signature') |
48 | if(msg.content.host != msg.author) |
49 | throw new Error('host did not match author') |
50 | |
51 | //an ordinary message so doesn't use special hmac_key |
52 | if(!ssbKeys.verifyObj(msg.author, msg)) |
53 | throw new Error('invalid host signature') |
54 | return true |
55 | } |
56 | |
57 | exports.verifyInvitePrivate = function (msg, seed) { |
58 | exports.verifyInvitePublic(msg) |
59 | if(msg.content.reveal) { |
60 | var reveal = unbox(msg.content.reveal, hash(hash(seed))) |
61 | if(!reveal) throw new Error('could not decrypt message to be revealed') |
62 | } |
63 | if(msg.content.private) { |
64 | var private = unbox(msg.content.private, hash(seed)) |
65 | if(!reveal) throw new Error('could not decrypt private message') |
66 | } |
67 | |
68 | return {reveal: reveal, private: private} |
69 | } |
70 | |
71 | exports.createAccept = function (msg, seed, id) { |
72 | var keys = ssbKeys.generate(null, seed) //K |
73 | if(keys.id != msg.content.invite) throw new Error('seed does not match invite') |
74 | var inviteId = '%'+ssbKeys.hash(JSON.stringify(msg, null, 2)) |
75 | return ssbKeys.signObj(keys, invite_key, { |
76 | type: 'invite/accept', |
77 | reciept: inviteId, |
78 | id: id, |
79 | key: msg.content.reveal ? hash(hash(seed)).toString('base64') : undefined |
80 | }) |
81 | } |
82 | |
83 | exports.verifyAccept = function (accept, invite) { |
84 | var reveal |
85 | if('%'+ssbKeys.hash(JSON.stringify(invite, null, 2)) !== accept.content.reciept) |
86 | throw new Error('acceptance not matched to given invite') |
87 | if(accept.author === invite.content.id) |
88 | throw new Error('invitee must use a new key, not the same seed') |
89 | if(invite.content.reveal) { |
90 | reveal = unbox(invite.content.reveal, new Buffer(accept.content.key, 'base64')) |
91 | if(!reveal) throw new Error('accept did not correctly reveal invite') |
92 | } |
93 | |
94 | if(!ssbKeys.verifyObj(invite.content.invite, invite_key, accept.content)) |
95 | throw new Error('did not verify invite-acceptance contents') |
96 | //an ordinary message, so does not use hmac_key |
97 | if(!ssbKeys.verifyObj(accept.content.id, accept)) |
98 | throw new Error('acceptance must be signed by claimed key') |
99 | return reveal || true |
100 | } |
101 | |
102 |
Built with git-ssb-web