Skip to content

Commit 213d776

Browse files
committed
refactor invite
1 parent 1104fa2 commit 213d776

File tree

9 files changed

+181
-103
lines changed

9 files changed

+181
-103
lines changed

examples/pingpong.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ proc main() {.async.} =
7777

7878
# Perform OOB Introduction: Raya -> Saro
7979
let raya_bundle = raya.createIntroBundle()
80-
discard await saro.newPrivateConversation(raya_bundle)
80+
discard await saro.newPrivateConversation(raya_bundle, initTextFrame("Init").toContentFrame())
8181

8282
await sleepAsync(20.seconds) # Run for some time
8383

examples/tui/tui.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ proc drawStatusBar(app: ChatApp, layout: Pane , fg: ForegroundColor, bg: Backgro
207207

208208
var i = layout.yStart + 1
209209
var chunk = layout.width - 9
210-
tb.write(1, i, "Name: " & app.client.getId())
210+
tb.write(1, i, "Name: " & app.client.getName())
211211
inc i
212212
tb.write(1, i, fmt"PeerCount: {app.peerCount}")
213213
inc i

protos/invite.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ syntax = "proto3";
22

33
package wap.invite;
44

5+
import "encryption.proto";
6+
57
message InvitePrivateV1 {
68
bytes initiator = 1;
79
bytes initiator_ephemeral = 2;
810
bytes participant = 3;
911
int32 participant_ephemeral_id= 4;
1012
string discriminator = 5;
13+
encryption.EncryptedPayload initial_message = 6;
1114
}

src/chat/client.nim

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type Client* = ref object
5454
conversations: Table[string, Conversation] # Keyed by conversation ID
5555
inboundQueue: QueueRef
5656
isRunning: bool
57+
inbox: Inbox
5758

5859
newMessageCallbacks: seq[MessageCallback]
5960
newConvoCallbacks: seq[NewConvoCallback]
@@ -71,21 +72,23 @@ proc newClient*(cfg: WakuConfig, ident: Identity): Client {.raises: [IOError,
7172
let rm = newReliabilityManager().valueOr:
7273
raise newException(ValueError, fmt"SDS InitializationError")
7374

75+
let defaultInbox = initInbox(ident)
76+
7477
var q = QueueRef(queue: newAsyncQueue[ChatPayload](10))
7578
var c = Client(ident: ident,
7679
ds: waku,
7780
keyStore: initTable[string, KeyEntry](),
7881
conversations: initTable[string, Conversation](),
7982
inboundQueue: q,
8083
isRunning: false,
84+
inbox: defaultInbox,
8185
newMessageCallbacks: @[],
8286
newConvoCallbacks: @[])
8387

84-
let defaultInbox = initInbox(c.ident.getPubkey())
8588
c.conversations[defaultInbox.id()] = defaultInbox
8689

87-
notice "Client started", client = c.ident.getId(),
88-
defaultInbox = defaultInbox
90+
notice "Client started", client = c.ident.getName(),
91+
defaultInbox = defaultInbox, inTopic= topic_inbox(c.ident.get_addr())
8992
result = c
9093
except Exception as e:
9194
error "newCLient", err = e.msg
@@ -95,7 +98,7 @@ proc newClient*(cfg: WakuConfig, ident: Identity): Client {.raises: [IOError,
9598
#################################################
9699

97100
proc getId*(client: Client): string =
98-
result = client.ident.getId()
101+
result = client.ident.getName()
99102

100103
proc identity*(client: Client): Identity =
101104
result = client.ident
@@ -174,7 +177,7 @@ proc createIntroBundle*(self: var Client): IntroBundle =
174177
#################################################
175178

176179
proc addConversation*(client: Client, convo: Conversation) =
177-
notice "Creating conversation", client = client.getId(), topic = convo.id()
180+
notice "Creating conversation", client = client.getId(), convoId = convo.id()
178181
client.conversations[convo.id()] = convo
179182
client.notifyNewConversation(convo)
180183

@@ -183,47 +186,15 @@ proc getConversation*(client: Client, convoId: string): Conversation =
183186
result = client.conversations[convoId]
184187

185188
proc newPrivateConversation*(client: Client,
186-
introBundle: IntroBundle): Future[Option[ChatError]] {.async.} =
189+
introBundle: IntroBundle, content: ContentFrame): Future[Option[ChatError]] {.async.} =
187190
## Creates a private conversation with the given `IntroBundle`.
188191
## `IntroBundles` are provided out-of-band.
192+
let remote_pubkey = loadPublicKeyFromBytes(introBundle.ident).get()
193+
let remote_ephemeralkey = loadPublicKeyFromBytes(introBundle.ephemeral).get()
189194

190-
notice "New PRIVATE Convo ", client = client.getId(),
191-
fromm = introBundle.ident.mapIt(it.toHex(2)).join("")
192-
193-
let destPubkey = loadPublicKeyFromBytes(introBundle.ident).valueOr:
194-
raise newException(ValueError, "Invalid public key in intro bundle.")
195-
196-
let convoId = conversationIdFor(destPubkey)
197-
let destConvoTopic = topicInbox(destPubkey.getAddr())
198-
199-
let invite = InvitePrivateV1(
200-
initiator: @(client.ident.getPubkey().bytes()),
201-
initiatorEphemeral: @[0, 0], # TODO: Add ephemeral
202-
participant: @(destPubkey.bytes()),
203-
participantEphemeralId: introBundle.ephemeralId,
204-
discriminator: "test"
205-
)
206-
207-
208-
209-
let env = wrapEnv(encrypt(InboxV1Frame(invitePrivateV1: invite,
210-
recipient: "")), convoId)
211-
212-
let deliveryAckCb = proc(
213-
conversation: Conversation,
214-
msgId: string): Future[void] {.async.} =
215-
client.notifyDeliveryAck(conversation, msgId)
216-
217-
# TODO: remove placeholder key
218-
var key : array[32, byte]
219-
key[2]=2
220-
221-
var convo = initPrivateV1Sender(client.identity(), client.ds, destPubkey, key, deliveryAckCb)
222-
client.addConversation(convo)
223-
224-
# TODO: Subscribe to new content topic
195+
let convo = await client.inbox.inviteToPrivateConversation(client.ds,remote_pubkey, remote_ephemeralkey, content )
196+
client.addConversation(convo) # TODO: Fix re-entrantancy bug. Convo needs to be saved before payload is sent.
225197

226-
await client.ds.sendPayload(destConvoTopic, env)
227198
return none(ChatError)
228199

229200

src/chat/conversations/private_v1.nim

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,21 @@ type
3737
ds: WakuClient
3838
sdsClient: ReliabilityManager
3939
owner: Identity
40-
topic: string
4140
participant: PublicKey
4241
discriminator: string
4342
doubleratchet: naxolotl.Doubleratchet
4443

45-
proc getTopic*(self: PrivateV1): string =
46-
## Returns the topic for the PrivateV1 conversation.
47-
return self.topic
44+
proc derive_topic(participant: PublicKey): string =
45+
## Derives a topic from the participants' public keys.
46+
return "/convo/private/" & participant.get_addr()
47+
48+
proc getTopicInbound*(self: PrivateV1): string =
49+
## Returns the topic where the local client is listening for messages
50+
return derive_topic(self.owner.getPubkey())
51+
52+
proc getTopicOutbound*(self: PrivateV1): string =
53+
## Returns the topic where the remote recipient is listening for messages
54+
return derive_topic(self.participant)
4855

4956
proc allParticipants(self: PrivateV1): seq[PublicKey] =
5057
return @[self.owner.getPubkey(), self.participant]
@@ -61,9 +68,6 @@ proc getConvoIdRaw(participants: seq[PublicKey],
6168
proc getConvoId*(self: PrivateV1): string =
6269
return getConvoIdRaw(@[self.owner.getPubkey(), self.participant], self.discriminator)
6370

64-
proc derive_topic(participants: seq[PublicKey], discriminator: string): string =
65-
## Derives a topic from the participants' public keys.
66-
return "/convo/private/" & getConvoIdRaw(participants, discriminator)
6771

6872
proc calcMsgId(self: PrivateV1, msgBytes: seq[byte]): string =
6973
let s = fmt"{self.getConvoId()}|{msgBytes}"
@@ -93,6 +97,7 @@ proc decrypt*(convo: PrivateV1, enc: EncryptedPayload): Result[seq[byte], ChatEr
9397
prevChainLen: dr.prevChainLen
9498
)
9599
copyMem(addr header.dhPublic[0], unsafeAddr dr.dh[0], dr.dh.len) # TODO: Avoid this copy
100+
debug "DECR WRAP", who=convo.owner.getName(), cipher = shrink(dr.ciphertext[0..8])
96101

97102
convo.doubleratchet.decrypt(header, dr.ciphertext, @[]).mapErr(proc(e: NaxolotlError): ChatError = ChatError(code: errWrapped, context: repr(e) ))
98103

@@ -110,7 +115,7 @@ proc wireCallbacks(convo: PrivateV1, deliveryAckCb: proc(
110115
let funcDeliveryAck = proc(messageId: SdsMessageID,
111116
channelId: SdsChannelID) {.gcsafe.} =
112117
debug "sds message ack", messageId = messageId,
113-
channelId = channelId, cb = repr(deliveryAckCb)
118+
channelId = channelId
114119

115120
if deliveryAckCb != nil:
116121
asyncSpawn deliveryAckCb(convo, messageId)
@@ -132,48 +137,43 @@ proc initPrivateV1*(owner: Identity, ds:WakuClient, participant: PublicKey, seed
132137
msgId: string): Future[void] {.async.} = nil):
133138
PrivateV1 =
134139

135-
var participants = @[owner.getPubkey(), participant];
136-
137140
var rm = newReliabilityManager().valueOr:
138141
raise newException(ValueError, fmt"sds initialization: {repr(error)}")
139142

143+
let dr = if isSender:
144+
initDoubleratchetSender(seedKey, participant.bytes)
145+
else:
146+
initDoubleratchetRecipient(seedKey, owner.privateKey.bytes)
147+
140148
result = PrivateV1(
141149
ds: ds,
142150
sdsClient: rm,
143151
owner: owner,
144-
topic: derive_topic(participants, discriminator),
145152
participant: participant,
146153
discriminator: discriminator,
147-
doubleratchet: initDoubleratchet(seedKey, owner.privateKey.bytes, participant.bytes, isSender)
154+
doubleratchet: dr
148155
)
149156

150157
result.wireCallbacks(deliveryAckCb)
151158

152159
result.sdsClient.ensureChannel(result.getConvoId()).isOkOr:
153160
raise newException(ValueError, "bad sds channel")
154161

155-
156-
proc initPrivateV1Sender*(owner:Identity, ds: WakuClient, participant: PublicKey, seedKey: array[32, byte], deliveryAckCb: proc(
157-
conversation: Conversation, msgId: string): Future[void] {.async.} = nil): PrivateV1 =
158-
initPrivateV1(owner, ds, participant, seedKey, "default", true, deliveryAckCb)
159-
160-
proc initPrivateV1Recipient*(owner:Identity,ds: WakuClient, participant: PublicKey, seedKey: array[32, byte], deliveryAckCb: proc(
161-
conversation: Conversation, msgId: string): Future[void] {.async.} = nil): PrivateV1 =
162-
initPrivateV1(owner,ds, participant, seedKey, "default", false, deliveryAckCb)
163-
164-
165-
proc sendFrame(self: PrivateV1, ds: WakuClient,
166-
msg: PrivateV1Frame): Future[MessageId]{.async.} =
162+
proc encodeFrame*(self: PrivateV1, msg: PrivateV1Frame): (MessageId, EncryptedPayload) =
167163

168164
let frameBytes = encode(msg)
169165
let msgId = self.calcMsgId(frameBytes)
170166
var sdsPayload = self.sdsClient.wrapOutgoingMessage(frameBytes, msgId,
171167
self.getConvoId()).valueOr:
172168
raise newException(ValueError, fmt"sds wrapOutgoingMessage failed: {repr(error)}")
173169

174-
let encryptedPayload = self.encrypt(sdsPayload)
170+
result = (msgId, self.encrypt(sdsPayload))
171+
175172

176-
discard ds.sendPayload(self.getTopic(), encryptedPayload.toEnvelope(
173+
proc sendFrame(self: PrivateV1, ds: WakuClient,
174+
msg: PrivateV1Frame): Future[MessageId]{.async.} =
175+
let (msgId, encryptedPayload) = self.encodeFrame(msg)
176+
discard ds.sendPayload(self.getTopicOutbound(), encryptedPayload.toEnvelope(
177177
self.getConvoId()))
178178

179179
result = msgId
@@ -182,19 +182,19 @@ proc sendFrame(self: PrivateV1, ds: WakuClient,
182182
method id*(self: PrivateV1): string =
183183
return getConvoIdRaw(self.allParticipants(), self.discriminator)
184184

185+
186+
187+
185188
proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T,
186-
bytes: seq[byte]) =
189+
encPayload: EncryptedPayload) =
187190
## Dispatcher for Incoming `PrivateV1Frames`.
188191
## Calls further processing depending on the kind of frame.
189192

190-
let enc = decode(bytes, EncryptedPayload).valueOr:
191-
raise newException(ValueError, fmt"Failed to decode EncryptedPayload: {repr(error)}")
192-
193-
if convo.doubleratchet.dhSelfPublic() == enc.doubleratchet.dh:
193+
if convo.doubleratchet.dhSelfPublic() == encPayload.doubleratchet.dh:
194194
info "outgoing message, no need to handle", convo = convo.id()
195195
return
196196

197-
let plaintext = convo.decrypt(enc).valueOr:
197+
let plaintext = convo.decrypt(encPayload).valueOr:
198198
error "decryption failed", error = error
199199
return
200200

@@ -220,6 +220,15 @@ proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T,
220220
of typePlaceholder:
221221
notice "Got Placeholder", text = frame.placeholder.counter
222222

223+
proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T,
224+
bytes: seq[byte]) =
225+
## Dispatcher for Incoming `PrivateV1Frames`.
226+
## Calls further processing depending on the kind of frame.
227+
let encPayload = decode(bytes, EncryptedPayload).valueOr:
228+
raise newException(ValueError, fmt"Failed to decode EncryptedPayload: {repr(error)}")
229+
230+
convo.handleFrame(client,encPayload)
231+
223232

224233
method sendMessage*(convo: PrivateV1, content_frame: ContentFrame) : Future[MessageId] {.async.} =
225234

@@ -231,3 +240,36 @@ method sendMessage*(convo: PrivateV1, content_frame: ContentFrame) : Future[Mess
231240
except Exception as e:
232241
error "Unknown error in PrivateV1:SendMessage"
233242

243+
244+
## Encrypts content without sending it.
245+
proc encryptMessage*(self: PrivateV1, content_frame: ContentFrame) : (MessageId, EncryptedPayload) =
246+
247+
try:
248+
let frame = PrivateV1Frame(
249+
sender: @(self.owner.getPubkey().bytes()),
250+
timestamp: getCurrentTimestamp(),
251+
content: content_frame
252+
)
253+
254+
result = self.encodeFrame(frame)
255+
256+
except Exception as e:
257+
error "Unknown error in PrivateV1:SendMessage"
258+
259+
proc initPrivateV1Sender*(sender:Identity,
260+
ds: WakuClient,
261+
participant: PublicKey,
262+
seedKey: array[32, byte],
263+
content: ContentFrame,
264+
deliveryAckCb: proc(conversation: Conversation, msgId: string): Future[void] {.async.} = nil): (PrivateV1, EncryptedPayload) =
265+
let convo = initPrivateV1(sender, ds, participant, seedKey, "default", true, deliveryAckCb)
266+
267+
# Encrypt Content with Convo
268+
let contentFrame = PrivateV1Frame(sender: @(sender.getPubkey().bytes()), timestamp: getCurrentTimestamp(), content: content)
269+
let (msg_id, encPayload) = convo.encryptMessage(content)
270+
result = (convo, encPayload)
271+
272+
273+
proc initPrivateV1Recipient*(owner:Identity,ds: WakuClient, participant: PublicKey, seedKey: array[32, byte], deliveryAckCb: proc(
274+
conversation: Conversation, msgId: string): Future[void] {.async.} = nil): PrivateV1 =
275+
initPrivateV1(owner,ds, participant, seedKey, "default", false, deliveryAckCb)

src/chat/identity.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ proc getAddr*(self: Identity): string =
2929
result = get_addr(self.getPubKey())
3030

3131

32-
proc getId*(self: Identity): string =
32+
proc getName*(self: Identity): string =
3333
result = self.name

0 commit comments

Comments
 (0)