git ssb

0+

Dominic / ssb-peer-invites



Tree: 0d533f2e86c275fe20ee7d30ad22e15f5e6c944c

Files: 0d533f2e86c275fe20ee7d30ad22e15f5e6c944c / valid.js

5165 bytesRaw
1var ssbKeys = require('ssb-keys')
2var isMsg = require('ssb-ref').isMsg
3var u = require('./util')
4
5var invite_key = require('./cap')
6
7function code(err, c) {
8 err.code = 'user-invites:'+c
9 return err
10}
11
12function isObject (o) {
13 return o && 'object' === typeof o
14}
15
16exports.createInvite = function (seed, host, reveal, private, caps) {
17 if(!isObject(caps)) throw new Error('caps *must* be provided')
18
19 var keys = ssbKeys.generate(null, seed) //K
20 if(keys.id === host)
21 throw code(new Error('do not create invite with own public key'), 'user-invites:no-own-goal')
22 return ssbKeys.signObj(keys, caps.userInvite, {
23 type: 'user-invite',
24 invite: keys.id,
25 host: host, //sign our own key, to prove we created K
26 reveal: reveal ? u.box(reveal, u.hash(u.hash(seed))) : undefined,
27 private: private ? u.box(private, u.hash(seed)) : undefined
28 })
29}
30
31exports.verifyInvitePublic = function (msg, caps) {
32 if(!isObject(caps)) throw new Error('caps *must* be provided')
33
34 if(msg.content.host != msg.author)
35 throw code(new Error('host did not match author'), 'host-must-match-author')
36
37 if(!ssbKeys.verifyObj(msg.content.invite, caps.userInvite, msg.content))
38 throw code(new Error('invalid invite signature'), 'invite-signature-failed')
39
40 //an ordinary message so doesn't use special hmac_key, unless configed to.
41 if(!ssbKeys.verifyObj(msg.author, caps.sign, msg))
42 throw code(new Error('invalid host signature'), 'host-signature-failed')
43 return true
44}
45
46exports.verifyInvitePrivate = function (msg, seed, caps) {
47 if(!isObject(caps)) throw new Error('caps *must* be provided')
48
49 exports.verifyInvitePublic(msg, caps)
50 if(msg.content.reveal) {
51 var reveal = u.unbox(msg.content.reveal, u.hash(u.hash(seed)))
52 if(!reveal) throw code(new Error('could not decrypt reveal field'), 'decrypt-reveal-failed')
53 }
54 if(msg.content.private) {
55 var private = u.unbox(msg.content.private, u.hash(seed))
56 if(!private) throw code(new Error('could not decrypt private field'), 'decrypt-private-failed')
57 }
58
59 return {reveal: reveal, private: private}
60}
61
62exports.createAccept = function (msg, seed, id, caps) {
63 if(!isObject(caps)) throw new Error('caps *must* be provided')
64
65 exports.verifyInvitePrivate(msg, seed, caps)
66 var keys = ssbKeys.generate(null, seed) //K
67 if(keys.id != msg.content.invite)
68 throw code(new Error('seed does not match invite'), 'seed-must-match-invite')
69 var inviteId = '%'+ssbKeys.hash(JSON.stringify(msg, null, 2))
70 var content = {
71 type: 'user-invite/accept',
72 receipt: inviteId,
73 id: id
74 }
75 if(msg.content.reveal)
76 content.key = u.hash(u.hash(seed)).toString('base64')
77 return ssbKeys.signObj(keys, caps.userInvite, content)
78}
79
80exports.verifyAcceptOnly = function (accept, caps) {
81 if(!isObject(caps)) throw new Error('caps *must* be provided')
82 if(accept.content.type !== 'user-invite/accept')
83 throw code(new Error('accept must be type: "user-invite/accept", was:'+JSON.stringify(accept.content.type)), 'accept-message-type')
84 if(!isMsg(accept.content.receipt))
85 throw code(new Error('accept must reference invite message id'), 'accept-reference-invite')
86 //verify signed as ordinary message.
87 if(!ssbKeys.verifyObj(accept.content.id, caps.sign, accept))
88 throw code(new Error('acceptance must be signed by claimed key'), 'accept-signature-failed')
89}
90
91exports.verifyAccept = function (accept, invite, caps) {
92 if(!isObject(caps)) throw new Error('caps *must* be provided')
93 if(!invite) throw new Error('invite must be provided')
94
95 exports.verifyAcceptOnly(accept, caps)
96
97 if(invite.content.type !== 'user-invite')
98 throw code(new Error('accept must be type: invite, was:'+accept.content.type), 'user-invites:invite-message-type')
99
100 var invite_id = '%'+ssbKeys.hash(JSON.stringify(invite, null, 2))
101 var reveal
102
103 if(invite_id !== accept.content.receipt)
104 throw code(new Error('acceptance not matched to given invite, got:'+invite_id+' expected:'+accept.content.receipt), 'accept-wrong-invite')
105
106 if(accept.author === invite.content.id)
107 throw code(new Error('guest must use a new key, not the same seed'), 'guest-key-reuse')
108 if(invite.content.reveal) {
109 if(!accept.content.key)
110 throw code(new Error('accept missing reveal key, when invite has it'), 'accept-must-reveal-key')
111 reveal = u.unbox(invite.content.reveal, new Buffer(accept.content.key, 'base64'))
112 if(!reveal) throw code(new Error('accept did not correctly reveal invite'), 'decrypt-accept-reveal-failed')
113 }
114
115 if(!ssbKeys.verifyObj(invite.content.invite, caps.userInvite, accept.content))
116 throw code(new Error('did not verify invite-acceptance contents'), 'accept-invite-signature-failed')
117 //an ordinary message, so does not use hmac_key
118 return reveal || true
119}
120
121exports.createConfirm = function (accept) {
122 return {
123 type: 'user-invite/confirm',
124 embed: accept,
125 //second pointer back to receipt, so that links can find it
126 //(since it unfortunately does not handle links nested deeper
127 //inside objects. when we look up the message,
128 //confirm that content.embed.content.receipt is the same)
129 receipt: accept.content.receipt
130 }
131}
132
133
134
135

Built with git-ssb-web