Commit 040389641134bf4080d6df213d990ebbb8a3a667
update everything to pass and use caps
Dominic Tarr committed on 12/16/2018, 12:34:41 AMParent: c42bd4ae81847e219235cbdc6c86571ff49fc410
Files changed
cap.js | changed |
index.js | changed |
types.js | changed |
valid.js | changed |
cap.js | ||
---|---|---|
@@ -5,6 +5,6 @@ | ||
5 | 5 … | 'string' == typeof s ? new Buffer(s, 'utf8') : s |
6 | 6 … | ) |
7 | 7 … | } |
8 | 8 … | |
9 | -module.exports = hash("user-invites:DEVELOPMENT") | |
9 … | +module.exports = hash("user-invites:DEVELOPMENT") //XXX DON'T publish without fixing this! | |
10 | 10 … |
index.js | |||
---|---|---|---|
@@ -48,22 +48,25 @@ | |||
48 | 48 … | exports.init = function (sbot, config) { | |
49 | 49 … | var init = false | |
50 | 50 … | var layer = sbot.friends.createLayer('user-invites') | |
51 | 51 … | ||
52 … | + var caps = config.caps || {} | ||
53 … | + caps.userInvite = caps.userInvite || require('./cap') | ||
54 … | + | ||
52 | 55 … | function reduce (acc, data, _seq) { | |
53 | 56 … | if(!acc) acc = {invited: {}, invites:{}, accepts: {}, hosts: {}} | |
54 | 57 … | var msg = data.value | |
55 | 58 … | var invite, accept | |
56 | - if(types.isInvite(msg)) { | ||
59 … | + if(types.isInvite(msg, caps)) { | ||
57 | 60 … | //TODO: validate that this is a msg we understand! | |
58 | 61 … | invite = msg | |
59 | 62 … | accept = acc.accepts[data.key] | |
60 | 63 … | } | |
61 | - else if(types.isAccept(msg)) { | ||
64 … | + else if(types.isAccept(msg, caps)) { | ||
62 | 65 … | accept = msg | |
63 | 66 … | invite = acc.invites[accept.content.receipt] | |
64 | 67 … | } | |
65 | - else if(types.isConfirm(msg)) { | ||
68 … | + else if(types.isConfirm(msg, caps)) { | ||
66 | 69 … | //TODO: just for when we are the guest, but we need to make sure at least one confirm exists. | |
67 | 70 … | accept = msg.content.embed | |
68 | 71 … | invite = acc.invites[accept.content.receipt] | |
69 | 72 … | } | |
@@ -71,9 +74,9 @@ | |||
71 | 74 … | if(invite && accept) { | |
72 | 75 … | if(invite === true) | |
73 | 76 … | return acc | |
74 | 77 … | var invite_id = accept.content.receipt | |
75 | - try { I.verifyAccept(accept, invite) } | ||
78 … | + try { I.verifyAccept(accept, invite, caps) } | ||
76 | 79 … | catch (err) { return acc } | |
77 | 80 … | //fall through from not throwing | |
78 | 81 … | ||
79 | 82 … | //delete matched invites, but _only_ if they are VALID. (returned in the catch if invalid) | |
@@ -210,9 +213,9 @@ | |||
210 | 213 … | if(confirm) return cb(null, confirm) | |
211 | 214 … | ||
212 | 215 … | sbot.get(invite_id, function (err, invite) { | |
213 | 216 … | try { | |
214 | - I.verifyAccept(accept, invite) | ||
217 … | + I.verifyAccept(accept, invite, caps) | ||
215 | 218 … | } catch (err) { | |
216 | 219 … | return cb(err) | |
217 | 220 … | } | |
218 | 221 … | //there is a little race condition here, if accept is called again | |
@@ -275,9 +278,9 @@ | |||
275 | 278 … | getNearbyPubs(opts, function (err, near) { | |
276 | 279 … | var seed = crypto.randomBytes(32) | |
277 | 280 … | sbot.identities.publishAs({ | |
278 | 281 … | id: opts.id || sbot.id, | |
279 | - content: I.createInvite(seed, opts.id || sbot.id, opts.reveal, opts.private) | ||
282 … | + content: I.createInvite(seed, opts.id || sbot.id, opts.reveal, opts.private, caps) | ||
280 | 283 … | }, function (err, data) { | |
281 | 284 … | cb(null, { | |
282 | 285 … | seed: seed, | |
283 | 286 … | invite: data.key, | |
@@ -293,9 +296,9 @@ | |||
293 | 296 … | pubs.forEach(function (addr) { | |
294 | 297 … | n++ | |
295 | 298 … | ssbClient(keys, { | |
296 | 299 … | remote: addr, | |
297 | - caps: require('ssb-config').caps, | ||
300 … | + caps: caps, | ||
298 | 301 … | manifest: { | |
299 | 302 … | userInvites: { | |
300 | 303 … | getInvite: 'async', | |
301 | 304 … | confirm: 'async' | |
@@ -321,9 +324,8 @@ | |||
321 | 324 … | next(msg) | |
322 | 325 … | else { | |
323 | 326 … | var pubs = invite.pubs | |
324 | 327 … | var keys = ssbKeys.generate(null, invite.seed) | |
325 | - console.log("CF", invite) | ||
326 | 328 … | connectFirst(keys, pubs, function (err, rpc) { | |
327 | 329 … | if(err) return cb(err) | |
328 | 330 … | rpc.userInvites.getInvite(invite.invite, function (err, msg) { | |
329 | 331 … | if(err) return cb(err) | |
@@ -338,14 +340,13 @@ | |||
338 | 340 … | return cb(new Error( | |
339 | 341 … | 'incorrect invite was returned! expected:'+invite.invite+', but got:'+inviteId | |
340 | 342 … | )) | |
341 | 343 … | var opened | |
342 | - try { opened = I.verifyInvitePrivate(msg, invite.seed) } | ||
344 … | + try { opened = I.verifyInvitePrivate(msg, invite.seed, caps) } | ||
343 | 345 … | catch (err) { return cb(err) } | |
344 | 346 … | //UPDATE REDUCE STATE. | |
345 | 347 … | // this is a wee bit naughty, because if you rebuild the index it might not have this invite | |
346 | 348 … | // (until you replicate it, but when you do the value won't change) | |
347 | - console.log("CURR REDUCE STATE", state.value) | ||
348 | 349 … | state.set(reduce(state.value, {key: invite_id, value:msg}, invites.since.value)) | |
349 | 350 … | cb(null, msg, opened) | |
350 | 351 … | } | |
351 | 352 … | }) | |
@@ -365,9 +366,9 @@ | |||
365 | 366 … | else { | |
366 | 367 … | invites.openInvite(invite, function (err, invite_msg, opened) { | |
367 | 368 … | sbot.identities.publishAs({ | |
368 | 369 … | id: id, | |
369 | - content: I.createAccept(invite_msg, invite.seed, id) | ||
370 … | + content: I.createAccept(invite_msg, invite.seed, id, caps) | ||
370 | 371 … | }, function (err, accept) { | |
371 | 372 … | if(err) cb(err) | |
372 | 373 … | else { | |
373 | 374 … | state.set(reduce(state.value, accept, invites.since.value)) | |
@@ -395,4 +396,5 @@ | |||
395 | 396 … | } | |
396 | 397 … | return invites | |
397 | 398 … | } | |
398 | 399 … | ||
400 … | + |
types.js | ||
---|---|---|
@@ -19,18 +19,19 @@ | ||
19 | 19 … | function isMaybeBase64(b) { |
20 | 20 … | return b === undefined || box_rx.test(b) |
21 | 21 … | } |
22 | 22 … | |
23 | -exports.isInvite = function (msg) { | |
23 … | +exports.isInvite = function (msg, caps) { | |
24 … | + if(!isObject(caps)) throw new Error('caps must be provided') | |
24 | 25 … | //return true |
25 | 26 … | return isObject(msg) && isObject(msg.content) && ( |
26 | 27 … | 'user-invite' === msg.content.type && |
27 | 28 … | ref.isFeed(msg.content.host) && |
28 | 29 … | ref.isFeed(msg.content.invite) && |
29 | 30 … | isMaybeBase64(msg.content.reveal) && |
30 | 31 … | isMaybeBase64(msg.content.public) && |
31 | 32 … | // signature must be valid !!! |
32 | - ssbKeys.verifyObj(msg.content.invite, caps.invite, msg.content) | |
33 … | + ssbKeys.verifyObj(msg.content.invite, caps.userInvite, msg.content) | |
33 | 34 … | ) |
34 | 35 … | } |
35 | 36 … | |
36 | 37 … | exports.isAccept = function (msg) { |
@@ -54,8 +55,4 @@ | ||
54 | 55 … | } |
55 | 56 … | |
56 | 57 … | |
57 | 58 … | |
58 | - | |
59 | - | |
60 | - | |
61 | - |
valid.js | ||
---|---|---|
@@ -8,37 +8,46 @@ | ||
8 | 8 … | err.code = 'user-invites:'+c |
9 | 9 … | return err |
10 | 10 … | } |
11 | 11 … | |
12 | -exports.createInvite = function (seed, host, reveal, private) { | |
12 … | +function isObject (o) { | |
13 … | + return o && 'object' === typeof o | |
14 … | +} | |
15 … | + | |
16 … | +exports.createInvite = function (seed, host, reveal, private, caps) { | |
17 … | + if(!isObject(caps)) throw new Error('caps *must* be provided') | |
18 … | + | |
13 | 19 … | var keys = ssbKeys.generate(null, seed) //K |
14 | 20 … | if(keys.id === host) |
15 | 21 … | throw code(new Error('do not create invite with own public key'), 'user-invites:no-own-goal') |
16 | - return ssbKeys.signObj(keys, invite_key, { | |
22 … | + return ssbKeys.signObj(keys, caps.userInvite, { | |
17 | 23 … | type: 'user-invite', |
18 | 24 … | invite: keys.id, |
19 | 25 … | host: host, //sign our own key, to prove we created K |
20 | 26 … | reveal: reveal ? u.box(reveal, u.hash(u.hash(seed))) : undefined, |
21 | 27 … | private: private ? u.box(private, u.hash(seed)) : undefined |
22 | 28 … | }) |
23 | 29 … | } |
24 | 30 … | |
25 | -exports.verifyInvitePublic = function (msg) { | |
31 … | +exports.verifyInvitePublic = function (msg, caps) { | |
32 … | + if(!isObject(caps)) throw new Error('caps *must* be provided') | |
33 … | + | |
26 | 34 … | if(msg.content.host != msg.author) |
27 | 35 … | throw code(new Error('host did not match author'), 'host-must-match-author') |
28 | 36 … | |
29 | - if(!ssbKeys.verifyObj(msg.content.invite, invite_key, msg.content)) | |
37 … | + if(!ssbKeys.verifyObj(msg.content.invite, caps.userInvite, msg.content)) | |
30 | 38 … | throw code(new Error('invalid invite signature'), 'invite-signature-failed') |
31 | 39 … | |
32 | 40 … | //an ordinary message so doesn't use special hmac_key, unless configed to. |
33 | - //TODO: import caps from config!!! | |
34 | - if(!ssbKeys.verifyObj(msg.author, msg)) | |
41 … | + if(!ssbKeys.verifyObj(msg.author, caps.sign, msg)) | |
35 | 42 … | throw code(new Error('invalid host signature'), 'host-signature-failed') |
36 | 43 … | return true |
37 | 44 … | } |
38 | 45 … | |
39 | -exports.verifyInvitePrivate = function (msg, seed) { | |
40 | - exports.verifyInvitePublic(msg) | |
46 … | +exports.verifyInvitePrivate = function (msg, seed, caps) { | |
47 … | + if(!isObject(caps)) throw new Error('caps *must* be provided') | |
48 … | + | |
49 … | + exports.verifyInvitePublic(msg, caps) | |
41 | 50 … | if(msg.content.reveal) { |
42 | 51 … | var reveal = u.unbox(msg.content.reveal, u.hash(u.hash(seed))) |
43 | 52 … | if(!reveal) throw code(new Error('could not decrypt reveal field'), 'decrypt-reveal-failed') |
44 | 53 … | } |
@@ -49,35 +58,40 @@ | ||
49 | 58 … | |
50 | 59 … | return {reveal: reveal, private: private} |
51 | 60 … | } |
52 | 61 … | |
53 | -exports.createAccept = function (msg, seed, id) { | |
54 | - exports.verifyInvitePrivate(msg, seed) | |
62 … | +exports.createAccept = function (msg, seed, id, caps) { | |
63 … | + if(!isObject(caps)) throw new Error('caps *must* be provided') | |
64 … | + | |
65 … | + exports.verifyInvitePrivate(msg, seed, caps) | |
55 | 66 … | var keys = ssbKeys.generate(null, seed) //K |
56 | 67 … | if(keys.id != msg.content.invite) |
57 | 68 … | throw code(new Error('seed does not match invite'), 'seed-must-match-invite') |
58 | 69 … | var inviteId = '%'+ssbKeys.hash(JSON.stringify(msg, null, 2)) |
59 | - return ssbKeys.signObj(keys, invite_key, { | |
70 … | + return ssbKeys.signObj(keys, caps.userInvite, { | |
60 | 71 … | type: 'user-invite/accept', |
61 | 72 … | receipt: inviteId, |
62 | 73 … | id: id, |
63 | 74 … | key: msg.content.reveal ? u.hash(u.hash(seed)).toString('base64') : undefined |
64 | 75 … | }) |
65 | 76 … | } |
66 | 77 … | |
67 | -exports.verifyAcceptOnly = function (accept) { | |
78 … | +exports.verifyAcceptOnly = function (accept, caps) { | |
79 … | + if(!isObject(caps)) throw new Error('caps *must* be provided') | |
68 | 80 … | if(accept.content.type !== 'user-invite/accept') |
69 | 81 … | throw code(new Error('accept must be type: "user-invite/accept", was:'+JSON.stringify(accept.content.type)), 'accept-message-type') |
70 | 82 … | if(!isMsg(accept.content.receipt)) |
71 | 83 … | throw code(new Error('accept must reference invite message id'), 'accept-reference-invite') |
72 | - if(!ssbKeys.verifyObj(accept.content.id, accept)) | |
84 … | + //verify signed as ordinary message. | |
85 … | + if(!ssbKeys.verifyObj(accept.content.id, caps.sign, accept)) | |
73 | 86 … | throw code(new Error('acceptance must be signed by claimed key'), 'accept-signature-failed') |
74 | 87 … | } |
75 | 88 … | |
76 | -exports.verifyAccept = function (accept, invite) { | |
89 … | +exports.verifyAccept = function (accept, invite, caps) { | |
90 … | + if(!isObject(caps)) throw new Error('caps *must* be provided') | |
77 | 91 … | if(!invite) throw new Error('invite must be provided') |
78 | 92 … | |
79 | - exports.verifyAcceptOnly(accept) | |
93 … | + exports.verifyAcceptOnly(accept, caps) | |
80 | 94 … | |
81 | 95 … | if(invite.content.type !== 'user-invite') |
82 | 96 … | throw code(new Error('accept must be type: invite, was:'+accept.content.type), 'user-invites:invite-message-type') |
83 | 97 … | |
@@ -95,10 +109,11 @@ | ||
95 | 109 … | reveal = u.unbox(invite.content.reveal, new Buffer(accept.content.key, 'base64')) |
96 | 110 … | if(!reveal) throw code(new Error('accept did not correctly reveal invite'), 'decrypt-accept-reveal-failed') |
97 | 111 … | } |
98 | 112 … | |
99 | - if(!ssbKeys.verifyObj(invite.content.invite, invite_key, accept.content)) | |
113 … | + if(!ssbKeys.verifyObj(invite.content.invite, caps.userInvite, accept.content)) | |
100 | 114 … | throw code(new Error('did not verify invite-acceptance contents'), 'accept-invite-signature-failed') |
101 | 115 … | //an ordinary message, so does not use hmac_key |
102 | 116 … | return reveal || true |
103 | 117 … | } |
104 | 118 … | |
119 … | + |
Built with git-ssb-web