git ssb

0+

Dominic / ssb-peer-invites



Tree: 6afc52277353751bfb6e030a550e931107cdd93b

Files: 6afc52277353751bfb6e030a550e931107cdd93b / index.js

4299 bytesRaw
1var I = require('./valid')
2
3/*
4uxer (someone who observes an invite, but not directly involved):
5
6if we see
7 someone post an invite I
8 someone else post a confirmation C that I has been accepted A
9 // OOO that A
10 emded that A inside a C(A)
11 match valid I->A's and interpret them like follows.
12
13 we only care about confirmations if it's of an invite we follow,
14 and it hasn't been confirmed already.
15
16{
17 invited: {
18 <alice>: { <bob>: true, ...}
19 }
20
21 invites: { <invites>, ...}
22 accepts: { <accepts>, ...}
23
24}
25
26---
27
28pub
29
30 someone connects, using key from an open invite I
31 they request that invite I (by it's id)
32 they send a message accepting A the invite.
33 the pub then posts confirmation (I,A)
34
35*/
36
37exports.name = 'invites'
38
39exports.version = '1.0.0'
40exports.manifest = {
41
42}
43
44// KNOWN BUG: it's possible to accept an invite more than once,
45// but peers will ignore subsequent acceptances. it's possible
46// that this could create confusion in certain situations.
47// (but you'd get a feed that some peers thought was invited by Alice
48// other peers would think a different feed accepted that invite)
49// I guess the answer is to let alice reject the second invite?)
50// that would be easier to do if this was a levelreduce? (keys: reduce, instead of a single reduce?)
51exports.init = function (sbot, config) {
52
53 var index = sbot._flumeUse('invites', Reduce(1, function (acc, data) {
54 if(!acc) acc = {invited: {}, invites:{}, accepts: {}}
55
56 var msg = data.value
57 var invite, accept
58 if(msg.content.type === 'invite') {
59 invite = msg
60 accept = acc.accepts[data.key]
61 }
62 else if(msg.content.type === 'invite/accept') {
63 accept = msg
64 invite = acc.invites[accept.content.receipt]
65 }
66 else if(msg.content.type === 'invite/confirm') {
67 accept = msg.content.embed
68 invite = acc.invites[accept.content.receipt]
69 }
70 if(invite && accept) {
71 if(invite === true)
72 return acc
73 try {
74 I.validateAccept(accept, invite)
75 //delete matched invites, but _only_ if they are valid.
76 delete acc.accepts[accept.receipt]
77 //but remember that this invite has been processed.
78 acc.invites[accept.receipt] = true
79 } catch (err) {
80 return acc //? or store something?
81 }
82 }
83 else if(invite)
84 acc.invites[data.key] = invite
85 else if(accept)
86 acc.accepts[accept.receipt] = accept
87
88 return acc
89
90 }))
91
92 sbot.auth.hook(function (fn, args) {
93 var id = args[0], cb = args[1]
94 index.get(function (err, v) {
95 if(err) return cb(err)
96 for(var k in v.invites)
97 if(v.invites[k].invite === id)
98 return cb(null, {
99 allow: ['invite.getInvite', 'invites.accept'],
100 deny: null
101 })
102 })
103 })
104
105 //first
106 invites.getInvite = function (invite_id, cb) {
107 var self = this
108 invites.get(function (err, v) {
109 var invite = v.invites[invite_id]
110 if(err) return cb(err)
111 if(!invite)
112 cb(code(
113 new Error('unknown invite:'+invite_id),
114 'unknown-invite'
115 ))
116 else if(invite === true)
117 cb(code(
118 new Error('invite already used:'+invite_id),
119 'invite-already-used'
120 ))
121 //only allow the guest to request their own invite.
122 else if(self.id !== invite.content.invite)
123 cb(code(
124 new Error('invite did not match client id'),
125 'invite-mismatch'
126 ))
127 else
128 cb(null, v.invites[invite_id])
129 })
130 }
131
132 var accepted = {}
133
134 invites.accept = function (accept, cb) {
135 //check if the invite in question hasn't already been accepted.
136 invites.get(function (err, v) {
137 var invite_id = accept.content.receipt
138 var invite = v.invites[invite_id]
139 if(invite === true || accepted[invite_id])
140 return cb(code(
141 new Error('invite already used:'+invite_id),
142 'invite-already-used'
143 ))
144 try {
145 I.validateAccept(accept, invite)
146 } catch (err) {
147 return cb(err)
148 }
149 //there is a little race condition here
150 accepted[invite_id] = true
151 sbot.publish({type: 'invite/confirm', embed: accept}, function (err, msg) {
152 delete accepted[invite_id]
153 cb(err, msg)
154 })
155 })
156 }
157
158 return invites
159
160}
161
162

Built with git-ssb-web