From e7a938a7c257e76310be8257783517fc50bd34b2 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:42:25 -0800 Subject: [PATCH] Remove stale files --- src/chat/conversation_store.nim | 16 -- src/chat/conversations.nim | 5 - src/chat/conversations/convo_impl.nim | 28 --- src/chat/conversations/convo_type.nim | 29 --- src/chat/conversations/message.nim | 11 - src/chat/conversations/private_v1.nim | 282 -------------------------- src/chat/crypto.nim | 35 ---- src/chat/inbox.nim | 171 ---------------- src/chat/links.nim | 58 ------ src/chat/proto_types.nim | 104 ---------- 10 files changed, 739 deletions(-) delete mode 100644 src/chat/conversation_store.nim delete mode 100644 src/chat/conversations.nim delete mode 100644 src/chat/conversations/convo_impl.nim delete mode 100644 src/chat/conversations/convo_type.nim delete mode 100644 src/chat/conversations/message.nim delete mode 100644 src/chat/conversations/private_v1.nim delete mode 100644 src/chat/crypto.nim delete mode 100644 src/chat/inbox.nim delete mode 100644 src/chat/links.nim delete mode 100644 src/chat/proto_types.nim diff --git a/src/chat/conversation_store.nim b/src/chat/conversation_store.nim deleted file mode 100644 index e629ea7..0000000 --- a/src/chat/conversation_store.nim +++ /dev/null @@ -1,16 +0,0 @@ -import ./conversations/[convo_type, message] -import identity -import types - -type ConvoId = string - -type - ConversationStore* = concept - proc addConversation(self: Self, convo: Conversation) - proc getConversation(self: Self, convoId: string): Conversation - proc identity(self: Self): Identity - proc getId(self: Self): string - - proc notifyNewMessage(self: Self, convo: Conversation, msg: ReceivedMessage) - proc notifyDeliveryAck(self: Self, convo: Conversation, - msgId: MessageId) diff --git a/src/chat/conversations.nim b/src/chat/conversations.nim deleted file mode 100644 index eb426a7..0000000 --- a/src/chat/conversations.nim +++ /dev/null @@ -1,5 +0,0 @@ -import - ./conversations/[convo_type, private_v1, message] - - -export private_v1, convo_type, message diff --git a/src/chat/conversations/convo_impl.nim b/src/chat/conversations/convo_impl.nim deleted file mode 100644 index 60fb9e5..0000000 --- a/src/chat/conversations/convo_impl.nim +++ /dev/null @@ -1,28 +0,0 @@ -import ../conversation_store -import ../conversations -import ../inbox - - -proc getType(convo: Conversation): ConvoTypes = - if convo of Inbox: - return InboxV1Type - - elif convo of PrivateV1: - return PrivateV1Type - - else: - raise newException(Defect, "Conversation Type not processed") - -proc handleFrame*[T: ConversationStore](convo: Conversation, client: T, - bytes: seq[byte]) = - - case convo.getType(): - of InboxV1Type: - let inbox = Inbox(convo) - inbox.handleFrame(client, bytes) - - of PrivateV1Type: - let priv = PrivateV1(convo) - priv.handleFrame(client, bytes) - - diff --git a/src/chat/conversations/convo_type.nim b/src/chat/conversations/convo_type.nim deleted file mode 100644 index b810eed..0000000 --- a/src/chat/conversations/convo_type.nim +++ /dev/null @@ -1,29 +0,0 @@ -import chronos -import strformat -import strutils - -import ../proto_types -import ../utils -import ../types - -type - ConvoTypes* = enum - InboxV1Type, PrivateV1Type - -type - Conversation* = ref object of RootObj - name: string - -proc `$`(conv: Conversation): string = - fmt"Convo: {conv.name}" - -# TODO: Removing the raises clause and the exception raise causes this -# error --> ...src/chat_sdk/client.nim(166, 9) Error: addConversation(client, convo) can raise an unlisted exception: Exception -# Need better understanding of NIMs Exception model -method id*(self: Conversation): string {.raises: [Defect, ValueError].} = - # TODO: make this a compile time check - panic("ProgramError: Missing concrete implementation") - -method sendMessage*(convo: Conversation, content_frame: Content) : Future[MessageId] {.async, base, gcsafe.} = - # TODO: make this a compile time check - panic("ProgramError: Missing concrete implementation") diff --git a/src/chat/conversations/message.nim b/src/chat/conversations/message.nim deleted file mode 100644 index 6f82edf..0000000 --- a/src/chat/conversations/message.nim +++ /dev/null @@ -1,11 +0,0 @@ -import ../crypto - -# How to surface different verifability of properties across conversation types - - -type ReceivedMessage* = ref object of RootObj - sender*: PublicKey - timestamp*: int64 - content*: seq[byte] - - diff --git a/src/chat/conversations/private_v1.nim b/src/chat/conversations/private_v1.nim deleted file mode 100644 index 9e8b264..0000000 --- a/src/chat/conversations/private_v1.nim +++ /dev/null @@ -1,282 +0,0 @@ - -import blake2 -import chronicles -import chronos -import sds -import std/[sequtils, strutils, strformat] -import std/algorithm -import sugar -import tables - -import ../conversation_store -import ../crypto -import ../delivery/waku_client - -import ../[ - identity, - errors, - proto_types, - types, - utils -] -import convo_type -import message - -import ../../naxolotl as nax - -const TopicPrefixPrivateV1 = "/convo/private/" - -type - ReceivedPrivateV1Message* = ref object of ReceivedMessage - -proc initReceivedMessage(sender: PublicKey, timestamp: int64, content: Content) : ReceivedPrivateV1Message = - ReceivedPrivateV1Message(sender:sender, timestamp:timestamp, content:content) - - -type - PrivateV1* = ref object of Conversation - ds: WakuClient - sdsClient: ReliabilityManager - owner: Identity - participant: PublicKey - discriminator: string - doubleratchet: naxolotl.Doubleratchet - -proc derive_topic(participant: PublicKey): string = - ## Derives a topic from the participants' public keys. - return TopicPrefixPrivateV1 & participant.get_addr() - -proc getTopicInbound*(self: PrivateV1): string = - ## Returns the topic where the local client is listening for messages - return derive_topic(self.owner.getPubkey()) - -proc getTopicOutbound*(self: PrivateV1): string = - ## Returns the topic where the remote recipient is listening for messages - return derive_topic(self.participant) - -## Parses the topic to extract the conversation ID. -proc parseTopic*(topic: string): Result[string, ChatError] = - if not topic.startsWith(TopicPrefixPrivateV1): - return err(ChatError(code: errTopic, context: "Invalid topic prefix")) - - let id = topic.split('/')[^1] - if id == "": - return err(ChatError(code: errTopic, context: "Empty conversation ID")) - - return ok(id) - -proc allParticipants(self: PrivateV1): seq[PublicKey] = - return @[self.owner.getPubkey(), self.participant] - -proc getConvoIdRaw(participants: seq[PublicKey], - discriminator: string): string = - # This is a placeholder implementation. - var addrs = participants.map(x => x.get_addr()); - addrs.sort() - addrs.add(discriminator) - let raw = addrs.join("|") - return utils.hash_func(raw) - -proc getConvoId*(self: PrivateV1): string = - return getConvoIdRaw(@[self.owner.getPubkey(), self.participant], self.discriminator) - - -proc calcMsgId(self: PrivateV1, msgBytes: seq[byte]): string = - let s = fmt"{self.getConvoId()}|{msgBytes}" - result = getBlake2b(s, 16, "") - - -proc encrypt*(convo: PrivateV1, plaintext: var seq[byte]): EncryptedPayload = - - let (header, ciphertext) = convo.doubleratchet.encrypt(plaintext) #TODO: Associated Data - - result = EncryptedPayload(doubleratchet: proto_types.DoubleRatchet( - dh: toSeq(header.dhPublic), - msgNum: header.msgNumber, - prevChainLen: header.prevChainLen, - ciphertext: ciphertext) - ) - -proc decrypt*(convo: PrivateV1, enc: EncryptedPayload): Result[seq[byte], ChatError] = - # Ensure correct type as received - if enc.doubleratchet.ciphertext == @[]: - return err(ChatError(code: errTypeError, context: "Expected doubleratchet encrypted payload got ???")) - - let dr = enc.doubleratchet - - var header = DrHeader( - msgNumber: dr.msgNum, - prevChainLen: dr.prevChainLen - ) - copyMem(addr header.dhPublic[0], unsafeAddr dr.dh[0], dr.dh.len) # TODO: Avoid this copy - - convo.doubleratchet.decrypt(header, dr.ciphertext, @[]).mapErr(proc(e: NaxolotlError): ChatError = ChatError(code: errWrapped, context: repr(e) )) - - - -proc wireCallbacks(convo: PrivateV1, deliveryAckCb: proc( - conversation: Conversation, - msgId: string): Future[void] {.async.} = nil) = - ## Accepts lambdas/functions to be called from Reliability Manager callbacks. - let funcMsg = proc(messageId: SdsMessageID, - channelId: SdsChannelID) {.gcsafe.} = - debug "sds message ready", messageId = messageId, - channelId = channelId - - let funcDeliveryAck = proc(messageId: SdsMessageID, - channelId: SdsChannelID) {.gcsafe.} = - debug "sds message ack", messageId = messageId, - channelId = channelId - - if deliveryAckCb != nil: - asyncSpawn deliveryAckCb(convo, messageId) - - let funcDroppedMsg = proc(messageId: SdsMessageID, missingDeps: seq[ - SdsMessageID], channelId: SdsChannelID) {.gcsafe.} = - debug "sds message missing", messageId = messageId, - missingDeps = missingDeps, channelId = channelId - - convo.sdsClient.setCallbacks( - funcMsg, funcDeliveryAck, funcDroppedMsg - ) - - - -proc initPrivateV1*(owner: Identity, ds:WakuClient, participant: PublicKey, seedKey: array[32, byte], - discriminator: string = "default", isSender: bool, deliveryAckCb: proc( - conversation: Conversation, - msgId: string): Future[void] {.async.} = nil): - PrivateV1 = - - var rm = newReliabilityManager().valueOr: - raise newException(ValueError, fmt"sds initialization: {repr(error)}") - - let dr = if isSender: - initDoubleratchetSender(seedKey, participant.bytes) - else: - initDoubleratchetRecipient(seedKey, owner.privateKey.bytes) - - result = PrivateV1( - ds: ds, - sdsClient: rm, - owner: owner, - participant: participant, - discriminator: discriminator, - doubleratchet: dr - ) - - result.wireCallbacks(deliveryAckCb) - - result.sdsClient.ensureChannel(result.getConvoId()).isOkOr: - raise newException(ValueError, "bad sds channel") - -proc encodeFrame*(self: PrivateV1, msg: PrivateV1Frame): (MessageId, EncryptedPayload) = - - let frameBytes = encode(msg) - let msgId = self.calcMsgId(frameBytes) - var sdsPayload = self.sdsClient.wrapOutgoingMessage(frameBytes, msgId, - self.getConvoId()).valueOr: - raise newException(ValueError, fmt"sds wrapOutgoingMessage failed: {repr(error)}") - - result = (msgId, self.encrypt(sdsPayload)) - -proc sendFrame(self: PrivateV1, ds: WakuClient, - msg: PrivateV1Frame): Future[MessageId]{.async.} = - let (msgId, encryptedPayload) = self.encodeFrame(msg) - discard ds.sendPayload(self.getTopicOutbound(), encryptedPayload.toEnvelope( - self.getConvoId())) - - result = msgId - - -method id*(self: PrivateV1): string = - return getConvoIdRaw(self.allParticipants(), self.discriminator) - -proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T, - encPayload: EncryptedPayload) = - ## Dispatcher for Incoming `PrivateV1Frames`. - ## Calls further processing depending on the kind of frame. - - if convo.doubleratchet.dhSelfPublic() == encPayload.doubleratchet.dh: - info "outgoing message, no need to handle", convo = convo.id() - return - - let plaintext = convo.decrypt(encPayload).valueOr: - error "decryption failed", error = error - return - - let (frameData, missingDeps, channelId) = convo.sdsClient.unwrapReceivedMessage( - plaintext).valueOr: - raise newException(ValueError, fmt"Failed to unwrap SDS message:{repr(error)}") - - debug "sds unwrap", convo = convo.id(), missingDeps = missingDeps, - channelId = channelId - - let frame = decode(frameData, PrivateV1Frame).valueOr: - raise newException(ValueError, "Failed to decode SdsM: " & error) - - if frame.sender == @(convo.owner.getPubkey().bytes()): - notice "Self Message", convo = convo.id() - return - - case frame.getKind(): - of typeContent: - # TODO: Using client.getId() results in an error in this context - client.notifyNewMessage(convo, initReceivedMessage(convo.participant, frame.timestamp, frame.content)) - - of typePlaceholder: - notice "Got Placeholder", text = frame.placeholder.counter - -proc handleFrame*[T: ConversationStore](convo: PrivateV1, client: T, - bytes: seq[byte]) = - ## Dispatcher for Incoming `PrivateV1Frames`. - ## Calls further processing depending on the kind of frame. - let encPayload = decode(bytes, EncryptedPayload).valueOr: - raise newException(ValueError, fmt"Failed to decode EncryptedPayload: {repr(error)}") - - convo.handleFrame(client,encPayload) - - -method sendMessage*(convo: PrivateV1, content_frame: Content) : Future[MessageId] {.async.} = - - try: - let frame = PrivateV1Frame(sender: @(convo.owner.getPubkey().bytes()), - timestamp: getCurrentTimestamp(), content: content_frame) - - result = await convo.sendFrame(convo.ds, frame) - except Exception as e: - error "Unknown error in PrivateV1:SendMessage" - - -## Encrypts content without sending it. -proc encryptMessage*(self: PrivateV1, content_frame: Content) : (MessageId, EncryptedPayload) = - - try: - let frame = PrivateV1Frame( - sender: @(self.owner.getPubkey().bytes()), - timestamp: getCurrentTimestamp(), - content: content_frame - ) - - result = self.encodeFrame(frame) - - except Exception as e: - error "Unknown error in PrivateV1:EncryptMessage" - -proc initPrivateV1Sender*(sender:Identity, - ds: WakuClient, - participant: PublicKey, - seedKey: array[32, byte], - content: Content, - deliveryAckCb: proc(conversation: Conversation, msgId: string): Future[void] {.async.} = nil): (PrivateV1, EncryptedPayload) = - let convo = initPrivateV1(sender, ds, participant, seedKey, "default", true, deliveryAckCb) - - # Encrypt Content with Convo - let contentFrame = PrivateV1Frame(sender: @(sender.getPubkey().bytes()), timestamp: getCurrentTimestamp(), content: content) - let (msg_id, encPayload) = convo.encryptMessage(content) - result = (convo, encPayload) - - -proc initPrivateV1Recipient*(owner:Identity,ds: WakuClient, participant: PublicKey, seedKey: array[32, byte], deliveryAckCb: proc( - conversation: Conversation, msgId: string): Future[void] {.async.} = nil): PrivateV1 = - initPrivateV1(owner,ds, participant, seedKey, "default", false, deliveryAckCb) diff --git a/src/chat/crypto.nim b/src/chat/crypto.nim deleted file mode 100644 index 1aa4cc5..0000000 --- a/src/chat/crypto.nim +++ /dev/null @@ -1,35 +0,0 @@ -import proto_types - -import strformat -import crypto/ecdh -import std/[sysrand] -import results -import utils - -export PublicKey, PrivateKey, bytes, createRandomKey, loadPrivateKeyFromBytes, loadPublicKeyFromBytes, - getPublicKey, Dh, Result, get_addr, `$` - - -proc encrypt_plain*[T: EncryptableTypes](frame: T): EncryptedPayload = - return EncryptedPayload( - plaintext: Plaintext(payload: encode(frame)), - ) - -proc decrypt_plain*[T: EncryptableTypes](ciphertext: Plaintext, t: typedesc[ - T]): Result[T, string] = - - let obj = decode(ciphertext.payload, T) - if obj.isErr: - return err("Protobuf decode failed: " & obj.error) - result = ok(obj.get()) - -proc generate_key*(): PrivateKey = - createRandomKey().get() - - -proc toHex*(key: PublicKey): string = - bytesToHex(key.bytes()) - -proc `$`*(key: PublicKey): string = - let byteStr = toHex(key) - fmt"{byteStr[0..3]}..{byteStr[^4 .. ^1]}" diff --git a/src/chat/inbox.nim b/src/chat/inbox.nim deleted file mode 100644 index 7af319a..0000000 --- a/src/chat/inbox.nim +++ /dev/null @@ -1,171 +0,0 @@ -import std/[strutils] - -import - chronicles, - chronos, - results, - strformat - -import - conversations/convo_type, - conversations, - conversation_store, - crypto, - delivery/waku_client, - errors, - identity, - proto_types, - types - -logScope: - topics = "chat inbox" - -type - Inbox* = ref object of Conversation - identity: Identity - inbox_addr: string - -const - TopicPrefixInbox = "/inbox/" - -proc `$`*(conv: Inbox): string = - fmt"Inbox: addr->{conv.inbox_addr}" - - -proc initInbox*(ident: Identity): Inbox = - ## Initializes an Inbox object with the given address and invite callback. - return Inbox(identity: ident) - -proc encrypt*(frame: InboxV1Frame): EncryptedPayload = - return encrypt_plain(frame) - -proc decrypt*(inbox: Inbox, encbytes: EncryptedPayload): Result[InboxV1Frame, string] = - let res_frame = decrypt_plain(encbytes.plaintext, InboxV1Frame) - if res_frame.isErr: - error "Failed to decrypt frame: ", err = res_frame.error - return err("Failed to decrypt frame: " & res_frame.error) - result = res_frame - -proc wrap_env*(payload: EncryptedPayload, convo_id: string): WapEnvelopeV1 = - let bytes = encode(payload) - let salt = generateSalt() - - return WapEnvelopeV1( - payload: bytes, - salt: salt, - conversation_hint: convo_id, - ) - -proc conversation_id_for*(pubkey: PublicKey): string = - ## Generates a conversation ID based on the public key. - return "/convo/inbox/v1/" & pubkey.get_addr() - -# TODO derive this from instance of Inbox -proc topic_inbox*(client_addr: string): string = - return TopicPrefixInbox & client_addr - -proc parseTopic*(topic: string): Result[string, ChatError] = - if not topic.startsWith(TopicPrefixInbox): - return err(ChatError(code: errTopic, context: "Invalid inbox topic prefix")) - - let id = topic.split('/')[^1] - if id == "": - return err(ChatError(code: errTopic, context: "Empty inbox id")) - - return ok(id) - -method id*(convo: Inbox): string = - return conversation_id_for(convo.identity.getPubkey()) - -## Encrypt and Send a frame to the remote account -proc sendFrame(ds: WakuClient, remote: PublicKey, frame: InboxV1Frame ): Future[void] {.async.} = - let env = wrapEnv(encrypt(frame),conversation_id_for(remote) ) - await ds.sendPayload(topic_inbox(remote.get_addr()), env) - - -proc newPrivateInvite(initator_static: PublicKey, - initator_ephemeral: PublicKey, - recipient_static: PublicKey, - recipient_ephemeral: uint32, - payload: EncryptedPayload) : InboxV1Frame = - - let invite = InvitePrivateV1( - initiator: @(initator_static.bytes()), - initiatorEphemeral: @(initator_ephemeral.bytes()), - participant: @(recipient_static.bytes()), - participantEphemeralId: 0, - discriminator: "", - initial_message: payload - ) - result = InboxV1Frame(invitePrivateV1: invite, recipient: "") - -################################################# -# Conversation Creation -################################################# - -## Establish a PrivateConversation with a remote client -proc inviteToPrivateConversation*(self: Inbox, ds: Wakuclient, remote_static: PublicKey, remote_ephemeral: PublicKey, content: Content ) : Future[PrivateV1] {.async.} = - # Create SeedKey - # TODO: Update key derivations when noise is integrated - var local_ephemeral = generateKey() - var sk{.noInit.} : array[32, byte] = default(array[32, byte]) - - # Initialize PrivateConversation - let (convo, encPayload) = initPrivateV1Sender(self.identity, ds, remote_static, sk, content, nil) - result = convo - - # # Build Invite - let frame = newPrivateInvite(self.identity.getPubkey(), local_ephemeral.getPublicKey(), remote_static, 0, encPayload) - - # Send - await sendFrame(ds, remote_static, frame) - -## Receive am Invitation to create a new private conversation -proc createPrivateV1FromInvite*[T: ConversationStore](client: T, - invite: InvitePrivateV1) = - - let destPubkey = loadPublicKeyFromBytes(invite.initiator).valueOr: - raise newException(ValueError, "Invalid public key in intro bundle.") - - let deliveryAckCb = proc( - conversation: Conversation, - msgId: string): Future[void] {.async.} = - client.notifyDeliveryAck(conversation, msgId) - - # TODO: remove placeholder key - var key : array[32, byte] = default(array[32,byte]) - - let convo = initPrivateV1Recipient(client.identity(), client.ds, destPubkey, key, deliveryAckCb) - notice "Creating PrivateV1 conversation", client = client.getId(), - convoId = convo.getConvoId() - - convo.handleFrame(client, invite.initial_message) - - # Calling `addConversation` must only occur after the conversation is completely configured. - # The client calls the OnNewConversation callback, which returns execution to the application. - client.addConversation(convo) - -proc handleFrame*[T: ConversationStore](convo: Inbox, client: T, bytes: seq[ - byte]) = - ## Dispatcher for Incoming `InboxV1Frames`. - ## Calls further processing depending on the kind of frame. - - let enc = decode(bytes, EncryptedPayload).valueOr: - raise newException(ValueError, "Failed to decode payload") - - let frame = convo.decrypt(enc).valueOr: - error "Decrypt failed", client = client.getId(), error = error - raise newException(ValueError, "Failed to Decrypt MEssage: " & - error) - - case getKind(frame): - of typeInvitePrivateV1: - createPrivateV1FromInvite(client, frame.invitePrivateV1) - - of typeNote: - notice "Receive Note", client = client.getId(), text = frame.note.text - - -method sendMessage*(convo: Inbox, content_frame: Content) : Future[MessageId] {.async.} = - warn "Cannot send message to Inbox" - result = "program_error" diff --git a/src/chat/links.nim b/src/chat/links.nim deleted file mode 100644 index e877235..0000000 --- a/src/chat/links.nim +++ /dev/null @@ -1,58 +0,0 @@ -import base64 -import chronos -import strformat -import strutils - -import libp2p/crypto/crypto - -import ../content_types/all -import proto_types -import utils - - -################################################# -# Link Generation -################################################# - -proc toBundle*(link: string): Result[IntroBundle, string] = - # Check scheme - if not link.startsWith("wap://"): - return err("InvalidScheme") - - # Remove scheme - let path = link[6..^1] - - # Split by '/' - let parts = path.split('/') - - # Expected format: ident/{ident}/ephemeral/{ephemeral}/eid/{eid} - if parts.len != 6: - return err("InvalidFormat") - - # Validate structure - if parts[0] != "ident" or parts[2] != "ephemeral" or parts[4] != "eid": - return err("InvalidFormat") - - # Extract values - let ident = decode(parts[1]).toBytes() - let ephemeral = decode(parts[3]).toBytes() - - let eid = int32(parseInt(parts[5])) # TODO: catch parse error - - # Validate non-empty - if ident.len == 0: - return err("MissingIdent") - if ephemeral.len == 0: - return err("MissingEphemeral") - - return ok(IntroBundle( - ident: ident, - ephemeral: ephemeral, - ephemeral_id: eid - )) - - -proc toLink*(intro: IntroBundle): string = - let ident = encode(intro.ident, safe = true) - let ephemeral = intro.ephemeral.toHex() - result = fmt"wap://ident/{ident}/ephemeral/{ephemeral}/eid/{intro.ephemeral_id}" diff --git a/src/chat/proto_types.nim b/src/chat/proto_types.nim deleted file mode 100644 index a608046..0000000 --- a/src/chat/proto_types.nim +++ /dev/null @@ -1,104 +0,0 @@ -# Can this be an external package? It would be preferable to have these types -# easy to import and use. - -import protobuf_serialization # This import is needed or th macro will not work -import protobuf_serialization/proto_parser -import results -import std/random - -export protobuf_serialization - -import_proto3 "../../protos/inbox.proto" -# import_proto3 "../protos/invite.proto" // Import3 follows protobuf includes so this will result in a redefinition error -import_proto3 "../../protos/envelope.proto" - -import_proto3 "../../protos/private_v1.proto" - -type EncryptableTypes = InboxV1Frame | EncryptedPayload - -export EncryptedPayload -export InboxV1Frame -export PrivateV1Frame - -export EncryptableTypes - - - - -proc encode*(frame: object): seq[byte] = - ## Encodes the frame into a byte sequence using Protobuf serialization. - result = Protobuf.encode(frame) - - -proc decode*[T: object] (bytes: seq[byte], proto: typedesc[ - T]): Result[T, string] = - ## Encodes the frame into a byte sequence using Protobuf serialization. - - try: - result = ok(Protobuf.decode(bytes, proto)) - except ProtobufError as e: - result = err("Failed to decode payload: " & e.msg) - -type - IntroBundle {.proto3.} = object - ident* {.fieldNumber: 1.}: seq[byte] - ephemeral* {.fieldNumber: 2.}: seq[byte] - ephemeral_id* {.fieldNumber: 3.}: int32 - - -export IntroBundle - -proc generateSalt*(): uint64 = - randomize() - result = 0 - for i in 0 ..< 8: - result = result or (uint64(rand(255)) shl (i * 8)) - - -proc toEnvelope*(payload: EncryptedPayload, convo_id: string): WapEnvelopeV1 = - let bytes = encode(payload) - let salt = generateSalt() - - # TODO: Implement hinting - return WapEnvelopeV1( - payload: bytes, - salt: salt, - conversation_hint: convo_id, - ) - -########################################################### -# nim-serialize-protobuf does not support oneof fields. -# As a stop gap each object using oneof fields, needs -# a implementation to look up the type. -# -# The valid field is determined by the fields which -# is not set to the default value -########################################################### - -type - InboxV1FrameType* = enum - type_InvitePrivateV1, type_Note - -proc getKind*(obj: InboxV1Frame): InboxV1FrameType = - - if obj.invite_private_v1 != InvitePrivateV1(): - return type_InvitePrivateV1 - - if obj.note != Note(): - return type_Note - - raise newException(ValueError, "Un handled one of type") - -type - PrivateV1FrameType* = enum - type_Content, type_Placeholder - -proc getKind*(obj: PrivateV1Frame): PrivateV1FrameType = - - if obj.content != @[]: - return type_Content - - if obj.placeholder != Placeholder(): - return type_Placeholder - - raise newException(ValueError, "Un handled one of type")