git ssb

0+

Dominic / ssb-peer-invites



Tree: 20b51aaa1b5233eec015a9a8bb8d391dc58b207e

Files: 20b51aaa1b5233eec015a9a8bb8d391dc58b207e / index.js

4439 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 invites.getInvite = function (invite_id, cb) {
106 var self = this
107 invites.get(function (err, v) {
108 var invite = v.invites[invite_id]
109 if(err) return cb(err)
110 if(!invite)
111 cb(code(
112 new Error('unknown invite:'+invite_id),
113 'unknown-invite'
114 ))
115 else if(invite === true)
116 //TODO just retrive all confirmations we know about
117 //via links.
118 cb(code(
119 new Error('invite already used:'+invite_id),
120 'invite-already-used'
121 ))
122 //only allow the guest to request their own invite.
123 else if(self.id !== invite.content.invite)
124 cb(code(
125 new Error('invite did not match client id'),
126 'invite-mismatch'
127 ))
128 else
129 cb(null, v.invites[invite_id])
130 })
131 }
132
133 var accepted = {}
134
135 invites.accept = function (accept, cb) {
136 //check if the invite in question hasn't already been accepted.
137 invites.get(function (err, v) {
138 var invite_id = accept.content.receipt
139 var invite = v.invites[invite_id]
140 if(invite === true || accepted[invite_id])
141 //TODO: this should return the confirmation, not an error.
142 return cb(code(
143 new Error('invite already used:'+invite_id),
144 'invite-already-used'
145 ))
146
147 try {
148 I.validateAccept(accept, invite)
149 } catch (err) {
150 return cb(err)
151 }
152 //there is a little race condition here
153 accepted[invite_id] = true
154 sbot.publish({type: 'invite/confirm', embed: accept}, function (err, msg) {
155 delete accepted[invite_id]
156 cb(err, msg)
157 })
158 })
159 }
160
161 return invites
162
163}
164
165
166

Built with git-ssb-web