Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disappearing Messages #603

Merged
merged 22 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/silly-foxes-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@xmtp/react-native-sdk": patch
---

Disappearing Messages
DM membership adds (increases message length by 1 for dm creators)
Bug fix key package issues
Bug fix rate limiting
Mark addAccount as a delicate API
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import expo.modules.xmtpreactnativesdk.wrappers.ConversationParamsWrapper
import expo.modules.xmtpreactnativesdk.wrappers.CreateGroupParamsWrapper
import expo.modules.xmtpreactnativesdk.wrappers.MessageWrapper
import expo.modules.xmtpreactnativesdk.wrappers.DecryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.DisappearingMessageSettingsWrapper
import expo.modules.xmtpreactnativesdk.wrappers.DmWrapper
import expo.modules.xmtpreactnativesdk.wrappers.EncryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.GroupWrapper
Expand Down Expand Up @@ -55,6 +56,7 @@ import org.xmtp.android.library.codecs.EncryptedEncodedContent
import org.xmtp.android.library.codecs.RemoteAttachment
import org.xmtp.android.library.codecs.decoded
import org.xmtp.android.library.hexToByteArray
import org.xmtp.android.library.libxmtp.DisappearingMessageSettings
import org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration
import org.xmtp.android.library.libxmtp.Message
import org.xmtp.android.library.libxmtp.PermissionOption
Expand Down Expand Up @@ -387,7 +389,7 @@ class XMTPModule : Module() {
}
}

AsyncFunction("addAccount") Coroutine { installationId: String, newAddress: String, walletParams: String ->
AsyncFunction("addAccount") Coroutine { installationId: String, newAddress: String, walletParams: String, allowReassignInboxId: Boolean ->
withContext(Dispatchers.IO) {
logV("addAccount")
val client = clients[installationId] ?: throw XMTPException("No client")
Expand All @@ -402,7 +404,7 @@ class XMTPModule : Module() {
)
signer = reactSigner

client.addAccount(reactSigner)
client.addAccount(reactSigner, allowReassignInboxId)
signer = null
}
}
Expand Down Expand Up @@ -783,20 +785,30 @@ class XMTPModule : Module() {
}
}

AsyncFunction("findOrCreateDm") Coroutine { installationId: String, peerAddress: String ->
AsyncFunction("findOrCreateDm") Coroutine { installationId: String, peerAddress: String, disappearStartingAtNs: Long?, retentionDurationInNs: Long? ->
withContext(Dispatchers.IO) {
logV("findOrCreateDm")
val client = clients[installationId] ?: throw XMTPException("No client")
val dm = client.conversations.findOrCreateDm(peerAddress)
val settings = if (disappearStartingAtNs != null && retentionDurationInNs != null) {
DisappearingMessageSettings(disappearStartingAtNs, retentionDurationInNs)
} else {
null
}
val dm = client.conversations.findOrCreateDm(peerAddress, settings)
DmWrapper.encode(client, dm)
}
}

AsyncFunction("findOrCreateDmWithInboxId") Coroutine { installationId: String, peerInboxId: String ->
AsyncFunction("findOrCreateDmWithInboxId") Coroutine { installationId: String, peerInboxId: String, disappearStartingAtNs: Long?, retentionDurationInNs: Long? ->
withContext(Dispatchers.IO) {
logV("findOrCreateDmWithInboxId")
val client = clients[installationId] ?: throw XMTPException("No client")
val dm = client.conversations.findOrCreateDmWithInboxId(peerInboxId)
val settings = if (disappearStartingAtNs != null && retentionDurationInNs != null) {
DisappearingMessageSettings(disappearStartingAtNs, retentionDurationInNs)
} else {
null
}
val dm = client.conversations.findOrCreateDmWithInboxId(peerInboxId, settings)
DmWrapper.encode(client, dm)
}
}
Expand All @@ -817,6 +829,7 @@ class XMTPModule : Module() {
createGroupParams.groupName,
createGroupParams.groupImageUrlSquare,
createGroupParams.groupDescription,
createGroupParams.disappearingMessageSettings
)
GroupWrapper.encode(client, group)
}
Expand All @@ -838,6 +851,7 @@ class XMTPModule : Module() {
createGroupParams.groupName,
createGroupParams.groupImageUrlSquare,
createGroupParams.groupDescription,
createGroupParams.disappearingMessageSettings
)
GroupWrapper.encode(client, group)
}
Expand All @@ -859,6 +873,7 @@ class XMTPModule : Module() {
createGroupParams.groupName,
createGroupParams.groupImageUrlSquare,
createGroupParams.groupDescription,
createGroupParams.disappearingMessageSettings
)
GroupWrapper.encode(client, group)
}
Expand All @@ -880,6 +895,7 @@ class XMTPModule : Module() {
createGroupParams.groupName,
createGroupParams.groupImageUrlSquare,
createGroupParams.groupDescription,
createGroupParams.disappearingMessageSettings
)
GroupWrapper.encode(client, group)
}
Expand Down Expand Up @@ -1045,6 +1061,52 @@ class XMTPModule : Module() {
}
}

AsyncFunction("disappearingMessageSettings") Coroutine { installationId: String, conversationId: String ->
withContext(Dispatchers.IO) {
logV("disappearingMessageSettings")
val client = clients[installationId] ?: throw XMTPException("No client")
val conversation = client.findConversation(conversationId)
?: throw XMTPException("no conversation found for $conversationId")
val settings = conversation.disappearingMessageSettings
settings?.let { DisappearingMessageSettingsWrapper.encode(it) }
}
}

AsyncFunction("isDisappearingMessagesEnabled") Coroutine { installationId: String, conversationId: String ->
withContext(Dispatchers.IO) {
logV("isDisappearingMessagesEnabled")
val client = clients[installationId] ?: throw XMTPException("No client")
val conversation = client.findConversation(conversationId)
?: throw XMTPException("no conversation found for $conversationId")
conversation.isDisappearingMessagesEnabled
}
}

AsyncFunction("clearDisappearingMessageSettings") Coroutine { installationId: String, conversationId: String ->
withContext(Dispatchers.IO) {
logV("clearDisappearingMessageSettings")
val client = clients[installationId] ?: throw XMTPException("No client")
val conversation = client.findConversation(conversationId)
?: throw XMTPException("no conversation found for $conversationId")
conversation.clearDisappearingMessageSettings()
}
}

AsyncFunction("updateDisappearingMessageSettings") Coroutine { installationId: String, conversationId: String, startAtNs: Long, durationInNs: Long ->
withContext(Dispatchers.IO) {
logV("updateDisappearingMessageSettings")
val client = clients[installationId] ?: throw XMTPException("No client")
val conversation = client.findConversation(conversationId)
?: throw XMTPException("no conversation found for $conversationId")
conversation.updateDisappearingMessageSettings(
DisappearingMessageSettings(
startAtNs,
durationInNs
)
)
}
}

AsyncFunction("isGroupActive") Coroutine { installationId: String, groupId: String ->
withContext(Dispatchers.IO) {
logV("isGroupActive")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.JsonParser
import org.xmtp.android.library.libxmtp.DisappearingMessageSettings

class CreateGroupParamsWrapper(
val groupName: String,
val groupImageUrlSquare: String,
val groupDescription: String,
val disappearingMessageSettings: DisappearingMessageSettings,
) {
companion object {
fun createGroupParamsFromJson(authParams: String): CreateGroupParamsWrapper {
val jsonOptions = JsonParser.parseString(authParams).asJsonObject
val settings = DisappearingMessageSettings(
if (jsonOptions.has("disappearStartingAtNs")) jsonOptions.get("disappearStartingAtNs").asLong else 0,
if (jsonOptions.has("retentionDurationInNs")) jsonOptions.get("retentionDurationInNs").asLong else 0
)

return CreateGroupParamsWrapper(
if (jsonOptions.has("name")) jsonOptions.get("name").asString else "",
if (jsonOptions.has("imageUrlSquare")) jsonOptions.get("imageUrlSquare").asString else "",
if (jsonOptions.has("description")) jsonOptions.get("description").asString else "",
settings
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.GsonBuilder
import org.xmtp.android.library.libxmtp.DisappearingMessageSettings

class DisappearingMessageSettingsWrapper {

companion object {
fun encode(model: DisappearingMessageSettings): String {
val gson = GsonBuilder().create()
val message = encodeMap(model)
return gson.toJson(message)
}

fun encodeMap(model: DisappearingMessageSettings): Map<String, Any> = mapOf(
"disappearStartingAtNs" to model.disappearStartingAtNs,
"retentionDurationInNs" to model.retentionDurationInNs,
)
}
}
22 changes: 7 additions & 15 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ PODS:
- hermes-engine/Pre-built (= 0.71.14)
- hermes-engine/Pre-built (0.71.14)
- libevent (2.1.12)
- LibXMTP (3.0.26)
- LibXMTP (3.0.27)
- MessagePacker (0.4.7)
- MMKV (2.0.2):
- MMKVCore (~> 2.0.2)
Expand Down Expand Up @@ -452,7 +452,7 @@ PODS:
- Connect-Swift (= 1.0.0)
- CryptoSwift (= 1.8.3)
- CSecp256k1 (~> 0.2)
- LibXMTP (= 3.0.26)
- LibXMTP (= 3.0.27)
- SQLCipher (= 4.5.7)
- XMTPReactNative (3.1.12):
- CSecp256k1 (~> 0.2)
Expand Down Expand Up @@ -530,7 +530,6 @@ DEPENDENCIES:
- RNFS (from `../node_modules/react-native-fs`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
- XMTP (from `https://github.com/xmtp/xmtp-ios.git`, commit `77940ee4790390154248d0fed0a2d5316fd99b3b`)
- XMTPReactNative (from `../../ios`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)

Expand All @@ -549,6 +548,7 @@ SPEC REPOS:
- OpenSSL-Universal
- SQLCipher
- SwiftProtobuf
- XMTP

EXTERNAL SOURCES:
boost:
Expand Down Expand Up @@ -679,21 +679,13 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-screens"
RNSVG:
:path: "../node_modules/react-native-svg"
XMTP:
:commit: 77940ee4790390154248d0fed0a2d5316fd99b3b
:git: https://github.com/xmtp/xmtp-ios.git
XMTPReactNative:
:path: "../../ios"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"

CHECKOUT OPTIONS:
XMTP:
:commit: 77940ee4790390154248d0fed0a2d5316fd99b3b
:git: https://github.com/xmtp/xmtp-ios.git

SPEC CHECKSUMS:
boost: 7dcd2de282d72e344012f7d6564d024930a6a440
boost: 57d2868c099736d80fcd648bf211b4431e51a558
CoinbaseWalletSDK: ea1f37512bbc69ebe07416e3b29bf840f5cc3152
CoinbaseWalletSDKExpo: c79420eb009f482f768c23b6768fc5b2d7c98777
Connect-Swift: 84e043b904f63dc93a2c01c6c125da25e765b50d
Expand All @@ -719,7 +711,7 @@ SPEC CHECKSUMS:
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
LibXMTP: e80c8c226e67d8c820e81c5a2bfa1934ab5d263c
LibXMTP: 312922ac85f2b20983ba14beb08722b08002ded4
MessagePacker: ab2fe250e86ea7aedd1a9ee47a37083edd41fd02
MMKV: 3eacda84cd1c4fc95cf848d3ecb69d85ed56006c
MMKVCore: 508b4d3a8ce031f1b5c8bd235f0517fb3f4c73a9
Expand Down Expand Up @@ -770,10 +762,10 @@ SPEC CHECKSUMS:
RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396
SQLCipher: 5e6bfb47323635c8b657b1b27d25c5f1baf63bf5
SwiftProtobuf: 4dbaffec76a39a8dc5da23b40af1a5dc01a4c02d
XMTP: 5815a5886b5a698e910d7eb49c11681e9001c931
XMTP: 12cc7f309b993790a2a6c2a8bb2048c62fb4b788
XMTPReactNative: 68152197c8135a6e0fe03637e7cde6bdd896d75c
Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9

PODFILE CHECKSUM: bb988e1a087fa2d3c0bc34c187128b2c7c6b2e58
PODFILE CHECKSUM: 2d04c11c2661aeaad852cd3ada0b0f1b06e0cf24

COCOAPODS: 1.15.2
48 changes: 31 additions & 17 deletions ios/Wrappers/CreateGroupParamsWrapper.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import Foundation
import XMTP

struct CreateGroupParamsWrapper {
let groupName: String
let groupImageUrlSquare: String
let groupDescription: String
let groupName: String
let groupImageUrlSquare: String
let groupDescription: String
let disappearingMessageSettings: DisappearingMessageSettings

static func createGroupParamsFromJson(_ authParams: String) -> CreateGroupParamsWrapper {
let data = authParams.data(using: .utf8) ?? Data()
let jsonOptions = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] ?? [:]

let groupName = jsonOptions["name"] as? String ?? ""
let groupImageUrlSquare = jsonOptions["imageUrlSquare"] as? String ?? ""
let groupDescription = jsonOptions["description"] as? String ?? ""

return CreateGroupParamsWrapper(
groupName: groupName,
groupImageUrlSquare: groupImageUrlSquare,
groupDescription: groupDescription
)
}
static func createGroupParamsFromJson(_ authParams: String)
-> CreateGroupParamsWrapper
{
let data = authParams.data(using: .utf8) ?? Data()
let jsonOptions =
(try? JSONSerialization.jsonObject(with: data, options: []))
as? [String: Any] ?? [:]

let settings = DisappearingMessageSettings(
disappearStartingAtNs: jsonOptions["disappearStartingAtNs"]
as? Int64 ?? 0,
retentionDurationInNs: jsonOptions["retentionDurationInNs"]
as? Int64 ?? 0
)

let groupName = jsonOptions["name"] as? String ?? ""
let groupImageUrlSquare = jsonOptions["imageUrlSquare"] as? String ?? ""
let groupDescription = jsonOptions["description"] as? String ?? ""

return CreateGroupParamsWrapper(
groupName: groupName,
groupImageUrlSquare: groupImageUrlSquare,
groupDescription: groupDescription,
disappearingMessageSettings: settings
)
}
}
24 changes: 24 additions & 0 deletions ios/Wrappers/DisappearingMessageSettingsWrapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation
import XMTP

struct DisappearingMessageSettingsWrapper {
static func encodeToObj(_ settings: XMTP.DisappearingMessageSettings) throws
-> [String: Any]
{
return [
"disappearStartingAtNs": settings.disappearStartingAtNs,
"retentionDurationInNs": settings.retentionDurationInNs,
]
}

static func encode(_ entry: XMTP.DisappearingMessageSettings) throws
-> String
{
let obj = try encodeToObj(entry)
let data = try JSONSerialization.data(withJSONObject: obj)
guard let result = String(data: data, encoding: .utf8) else {
throw WrapperError.encodeError("could not encode expirations")
}
return result
}
}
Loading
Loading