Skip to content

Commit

Permalink
get the first test passing
Browse files Browse the repository at this point in the history
  • Loading branch information
nplasterer committed Sep 20, 2024
1 parent 3931d15 commit e0d5091
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 137 deletions.
2 changes: 1 addition & 1 deletion Sources/XMTPTestHelpers/TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public struct Fixtures {

public func publishLegacyContact(client: Client) async throws {
var contactBundle = ContactBundle()
contactBundle.v1.keyBundle = client.privateKeyBundleV1.toPublicKeyBundle()
contactBundle.v1.keyBundle = try client.v1keys.toPublicKeyBundle()

var envelope = Envelope()
envelope.contentTopic = Topic.contact(client.address).description
Expand Down
5 changes: 3 additions & 2 deletions Sources/XMTPiOS/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ public struct ClientOptions {
public final class Client {
/// The wallet address of the ``SigningKey`` used to create this Client.
public let address: String
let privateKeyBundleV1: PrivateKeyBundleV1?
let apiClient: ApiClient?
var privateKeyBundleV1: PrivateKeyBundleV1? = nil
var apiClient: ApiClient? = nil
public let v3Client: LibXMTP.FfiXmtpClient?
public let libXMTPVersion: String = getVersionInfo()
public let dbPath: String
Expand Down Expand Up @@ -191,6 +191,7 @@ public final class Client {
for codec in (options.codecs) {
client.register(codec: codec)
}
return client
}

static func initV3Client(
Expand Down
193 changes: 99 additions & 94 deletions Sources/XMTPiOS/Contacts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,120 +58,125 @@ public actor EntriesManager {

public class ConsentList {
public let entriesManager = EntriesManager()
var publicKey: Data
var privateKey: Data
var identifier: String?
var lastFetched: Date?
var client: Client

init(client: Client) {
self.client = client
privateKey = client.privateKeyBundleV1.identityKey.secp256K1.bytes
publicKey = client.privateKeyBundleV1.identityKey.publicKey.secp256K1Uncompressed.bytes
identifier = try? LibXMTP.generatePrivatePreferencesTopicIdentifier(privateKey: privateKey)
}

func load() async throws -> [ConsentListEntry] {
guard let identifier = identifier else {
throw ContactError.invalidIdentifier
}
let newDate = Date()

let pagination = Pagination(
limit: 500,
after: lastFetched,
direction: .ascending
)
let envelopes = try await client.apiClient.envelopes(topic: Topic.preferenceList(identifier).description, pagination: pagination)
lastFetched = newDate

var preferences: [PrivatePreferencesAction] = []

for envelope in envelopes {
let payload = try LibXMTP.userPreferencesDecrypt(publicKey: publicKey, privateKey: privateKey, message: envelope.message)

try preferences.append(PrivatePreferencesAction(serializedData: Data(payload)))
}
for preference in preferences {
for address in preference.allowAddress.walletAddresses {
_ = await allow(address: address)
}

for address in preference.denyAddress.walletAddresses {
_ = await deny(address: address)
}

for groupId in preference.allowGroup.groupIds {
_ = await allowGroup(groupId: groupId)
}

for groupId in preference.denyGroup.groupIds {
_ = await denyGroup(groupId: groupId)
if (client.hasV2Client) {
let privateKey = try client.v1keys.identityKey.secp256K1.bytes
let publicKey = try client.v1keys.identityKey.publicKey.secp256K1Uncompressed.bytes
let identifier = try? LibXMTP.generatePrivatePreferencesTopicIdentifier(privateKey: privateKey)

guard let identifier = identifier else {
throw ContactError.invalidIdentifier
}
let newDate = Date()

let pagination = Pagination(
limit: 500,
after: lastFetched,
direction: .ascending
)
let envelopes = try await client.apiClient!.envelopes(topic: Topic.preferenceList(identifier).description, pagination: pagination)
lastFetched = newDate

for inboxId in preference.allowInboxID.inboxIds {
_ = await allowInboxId(inboxId: inboxId)
var preferences: [PrivatePreferencesAction] = []

for envelope in envelopes {
let payload = try LibXMTP.userPreferencesDecrypt(publicKey: publicKey, privateKey: privateKey, message: envelope.message)

try preferences.append(PrivatePreferencesAction(serializedData: Data(payload)))
}

for inboxId in preference.denyInboxID.inboxIds {
_ = await denyInboxId(inboxId: inboxId)
for preference in preferences {
for address in preference.allowAddress.walletAddresses {
_ = await allow(address: address)
}

for address in preference.denyAddress.walletAddresses {
_ = await deny(address: address)
}

for groupId in preference.allowGroup.groupIds {
_ = await allowGroup(groupId: groupId)
}

for groupId in preference.denyGroup.groupIds {
_ = await denyGroup(groupId: groupId)
}

for inboxId in preference.allowInboxID.inboxIds {
_ = await allowInboxId(inboxId: inboxId)
}

for inboxId in preference.denyInboxID.inboxIds {
_ = await denyInboxId(inboxId: inboxId)
}
}
}

return await Array(entriesManager.map.values)
}

func publish(entries: [ConsentListEntry]) async throws {
guard let identifier = identifier else {
throw ContactError.invalidIdentifier
}
var payload = PrivatePreferencesAction()

for entry in entries {
switch entry.entryType {
case .address:
switch entry.consentType {
case .allowed:
payload.allowAddress.walletAddresses.append(entry.value)
case .denied:
payload.denyAddress.walletAddresses.append(entry.value)
case .unknown:
payload.messageType = nil
}
case .group_id:
switch entry.consentType {
case .allowed:
payload.allowGroup.groupIds.append(entry.value)
case .denied:
payload.denyGroup.groupIds.append(entry.value)
case .unknown:
payload.messageType = nil
}
case .inbox_id:
switch entry.consentType {
case .allowed:
payload.allowInboxID.inboxIds.append(entry.value)
case .denied:
payload.denyInboxID.inboxIds.append(entry.value)
case .unknown:
payload.messageType = nil
if (client.hasV2Client) {
let privateKey = try client.v1keys.identityKey.secp256K1.bytes
let publicKey = try client.v1keys.identityKey.publicKey.secp256K1Uncompressed.bytes
let identifier = try? LibXMTP.generatePrivatePreferencesTopicIdentifier(privateKey: privateKey)
guard let identifier = identifier else {
throw ContactError.invalidIdentifier
}
var payload = PrivatePreferencesAction()

for entry in entries {
switch entry.entryType {
case .address:
switch entry.consentType {
case .allowed:
payload.allowAddress.walletAddresses.append(entry.value)
case .denied:
payload.denyAddress.walletAddresses.append(entry.value)
case .unknown:
payload.messageType = nil
}
case .group_id:
switch entry.consentType {
case .allowed:
payload.allowGroup.groupIds.append(entry.value)
case .denied:
payload.denyGroup.groupIds.append(entry.value)
case .unknown:
payload.messageType = nil
}
case .inbox_id:
switch entry.consentType {
case .allowed:
payload.allowInboxID.inboxIds.append(entry.value)
case .denied:
payload.denyInboxID.inboxIds.append(entry.value)
case .unknown:
payload.messageType = nil
}
}
}

let message = try LibXMTP.userPreferencesEncrypt(
publicKey: publicKey,
privateKey: privateKey,
message: payload.serializedData()
)

let envelope = Envelope(
topic: Topic.preferenceList(identifier),
timestamp: Date(),
message: Data(message)
)

try await client.publish(envelopes: [envelope])
}
}

let message = try LibXMTP.userPreferencesEncrypt(
publicKey: publicKey,
privateKey: privateKey,
message: payload.serializedData()
)

let envelope = Envelope(
topic: Topic.preferenceList(identifier),
timestamp: Date(),
message: Data(message)
)

try await client.publish(envelopes: [envelope])
}

func allow(address: String) async -> ConsentListEntry {
Expand Down
15 changes: 10 additions & 5 deletions Sources/XMTPiOS/ConversationV1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public struct ConversationV1 {
let date = sentAt

let message = try MessageV1.encode(
sender: client.privateKeyBundleV1,
sender: client.v1keys,
recipient: recipient,
message: try encodedContent.serializedData(),
timestamp: date
Expand Down Expand Up @@ -217,8 +217,10 @@ public struct ConversationV1 {

func decryptedMessages(limit: Int? = nil, before: Date? = nil, after: Date? = nil, direction: PagingInfoSortDirection? = .descending) async throws -> [DecryptedMessage] {
let pagination = Pagination(limit: limit, before: before, after: after, direction: direction)

let envelopes = try await client.apiClient.envelopes(
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
let envelopes = try await apiClient.envelopes(
topic: Topic.directMessageV1(client.address, peerAddress).description,
pagination: pagination
)
Expand All @@ -229,7 +231,10 @@ public struct ConversationV1 {
func messages(limit: Int? = nil, before: Date? = nil, after: Date? = nil, direction: PagingInfoSortDirection? = .descending) async throws -> [DecodedMessage] {
let pagination = Pagination(limit: limit, before: before, after: after, direction: direction)

let envelopes = try await client.apiClient.envelopes(
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
let envelopes = try await apiClient.envelopes(
topic: Topic.directMessageV1(client.address, peerAddress).description,
pagination: pagination
)
Expand All @@ -246,7 +251,7 @@ public struct ConversationV1 {

func decrypt(envelope: Envelope) throws -> DecryptedMessage {
let message = try Message(serializedData: envelope.message)
let decrypted = try message.v1.decrypt(with: client.privateKeyBundleV1)
let decrypted = try message.v1.decrypt(with: client.v1keys)

let encodedMessage = try EncodedContent(serializedData: decrypted)
let header = try message.v1.header
Expand Down
12 changes: 9 additions & 3 deletions Sources/XMTPiOS/ConversationV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public struct ConversationV2 {
private var header: SealedInvitationHeaderV1

static func create(client: Client, invitation: InvitationV1, header: SealedInvitationHeaderV1) throws -> ConversationV2 {
let myKeys = client.keys.getPublicKeyBundle()
let myKeys = try client.keys.getPublicKeyBundle()

let peer = try myKeys.walletAddress == (try header.sender.walletAddress) ? header.recipient : header.sender
let peerAddress = try peer.walletAddress
Expand Down Expand Up @@ -133,7 +133,10 @@ public struct ConversationV2 {

func messages(limit: Int? = nil, before: Date? = nil, after: Date? = nil, direction: PagingInfoSortDirection? = .descending) async throws -> [DecodedMessage] {
let pagination = Pagination(limit: limit, before: before, after: after, direction: direction)
let envelopes = try await client.apiClient.envelopes(topic: topic.description, pagination: pagination)
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
let envelopes = try await apiClient.envelopes(topic: topic.description, pagination: pagination)

return envelopes.compactMap { envelope in
do {
Expand All @@ -146,8 +149,11 @@ public struct ConversationV2 {
}

func decryptedMessages(limit: Int? = nil, before: Date? = nil, after: Date? = nil, direction: PagingInfoSortDirection? = .descending) async throws -> [DecryptedMessage] {
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
let pagination = Pagination(limit: limit, before: before, after: after, direction: direction)
let envelopes = try await client.apiClient.envelopes(topic: topic.description, pagination: pagination)
let envelopes = try await apiClient.envelopes(topic: topic.description, pagination: pagination)

return try envelopes.map { envelope in
try decrypt(envelope: envelope)
Expand Down
22 changes: 17 additions & 5 deletions Sources/XMTPiOS/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,11 @@ public actor Conversations {
.map { requests in BatchQueryRequest.with { $0.requests = requests } }
var messages: [DecodedMessage] = []
// TODO: consider using a task group here for parallel batch calls
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
for batch in batches {
messages += try await client.apiClient.batchQuery(request: batch)
messages += try await apiClient.batchQuery(request: batch)
.responses.flatMap { res in
res.envelopes.compactMap { envelope in
let conversation = conversationsByTopic[envelope.contentTopic]
Expand Down Expand Up @@ -327,8 +330,11 @@ public actor Conversations {
.map { requests in BatchQueryRequest.with { $0.requests = requests } }
var messages: [DecryptedMessage] = []
// TODO: consider using a task group here for parallel batch calls
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
for batch in batches {
messages += try await client.apiClient.batchQuery(request: batch)
messages += try await apiClient.batchQuery(request: batch)
.responses.flatMap { res in
res.envelopes.compactMap { envelope in
let conversation = conversationsByTopic[envelope.contentTopic]
Expand Down Expand Up @@ -833,15 +839,18 @@ public actor Conversations {
}

private func listIntroductionPeers(pagination: Pagination?) async throws -> [String: Date] {
let envelopes = try await client.apiClient.query(
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
let envelopes = try await apiClient.query(
topic: .userIntro(client.address),
pagination: pagination
).envelopes
let messages = envelopes.compactMap { envelope in
do {
let message = try MessageV1.fromBytes(envelope.message)
// Attempt to decrypt, just to make sure we can
_ = try message.decrypt(with: client.privateKeyBundleV1)
_ = try message.decrypt(with: client.v1keys)
return message
} catch {
return nil
Expand All @@ -867,7 +876,10 @@ public actor Conversations {
}

private func listInvitations(pagination: Pagination?) async throws -> [SealedInvitation] {
var envelopes = try await client.apiClient.envelopes(
guard let apiClient = client.apiClient else {
throw ClientError.noV2Client("Error no V2 client initialized")
}
var envelopes = try await apiClient.envelopes(
topic: Topic.userInvite(client.address).description,
pagination: pagination
)
Expand Down
Loading

0 comments on commit e0d5091

Please sign in to comment.