From d9472ec19c0b54f4098f3a9c9e5709163ff4d0f3 Mon Sep 17 00:00:00 2001 From: ETL Date: Thu, 6 Oct 2022 02:03:25 -0400 Subject: [PATCH 001/713] Update user agent (#1023) Recent changes from Signal caused DeprecatedVersionException to occur. Changing the user agent debugged the receiving (sending still erroring) --- src/main/java/org/asamk/signal/BaseConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/asamk/signal/BaseConfig.java b/src/main/java/org/asamk/signal/BaseConfig.java index 04c1ac8a..696fc478 100644 --- a/src/main/java/org/asamk/signal/BaseConfig.java +++ b/src/main/java/org/asamk/signal/BaseConfig.java @@ -5,7 +5,7 @@ public class BaseConfig { public final static String PROJECT_NAME = BaseConfig.class.getPackage().getImplementationTitle(); public final static String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion(); - final static String USER_AGENT_SIGNAL_ANDROID = "Signal-Android/5.22.3"; + final static String USER_AGENT_SIGNAL_ANDROID = "Signal-Android/5.51.7"; final static String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null ? "signal-cli" : PROJECT_NAME + "/" + PROJECT_VERSION; From 76c400d2c3d38382103ba640f4bd3fd0d129062f Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 6 Oct 2022 17:52:06 +0200 Subject: [PATCH 002/713] Show better error message when signal-cli version is outdated --- .../java/org/asamk/signal/manager/SignalAccountFiles.java | 4 ++++ .../java/org/asamk/signal/manager/helper/AccountHelper.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java b/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java index 305b061d..9d0b344a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java +++ b/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java @@ -12,6 +12,7 @@ import org.asamk.signal.manager.util.KeyUtils; import org.signal.libsignal.protocol.util.KeyHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; import java.io.File; import java.io.IOException; @@ -114,6 +115,9 @@ public class SignalAccountFiles { try { manager.checkAccountState(); + } catch (DeprecatedVersionException e) { + manager.close(); + throw new AccountCheckException("signal-cli version is too old for the Signal-Server, please update."); } catch (IOException e) { manager.close(); throw new AccountCheckException("Error while checking account " + number + ": " + e.getMessage(), e); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java index 99a0834e..ce45dd2c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java @@ -18,6 +18,7 @@ import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; +import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; import org.whispersystems.signalservice.api.util.DeviceNameUtil; import org.whispersystems.signalservice.internal.push.OutgoingPushMessage; @@ -73,6 +74,9 @@ public class AccountHelper { && account.getRegistrationLockPin() != null) { migrateRegistrationPin(); } + } catch (DeprecatedVersionException e) { + logger.debug("Signal-Server returned deprecated version exception", e); + throw e; } catch (AuthorizationFailedException e) { account.setRegistered(false); throw e; From 1dd22132ffd15cc25fffa62aa765af979c7ae347 Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 6 Oct 2022 17:36:09 +0200 Subject: [PATCH 003/713] Update libsignal-service --- lib/build.gradle.kts | 2 +- .../signal/manager/SignalDependencies.java | 6 ++- .../signal/manager/helper/StorageHelper.java | 41 ++++++++++++++----- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 9674f296..2dde3b39 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -14,7 +14,7 @@ repositories { } dependencies { - implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_58") + implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_59") implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4") implementation("com.google.protobuf", "protobuf-javalite", "3.11.4") implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") diff --git a/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java b/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java index b892e935..6450f1f8 100644 --- a/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java +++ b/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java @@ -134,7 +134,8 @@ public class SignalDependencies { serviceEnvironmentConfig.getSignalServiceConfiguration(), Optional.of(credentialsProvider), userAgent, - healthMonitor); + healthMonitor, + true); } @Override @@ -143,7 +144,8 @@ public class SignalDependencies { serviceEnvironmentConfig.getSignalServiceConfiguration(), Optional.empty(), userAgent, - healthMonitor); + healthMonitor, + true); } }; signalWebSocket = new SignalWebSocket(webSocketFactory); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java index f3c3a091..15684da5 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java @@ -109,27 +109,48 @@ public class StorageHelper { final var blocked = contact != null && contact.isBlocked(); final var profileShared = contact != null && contact.isProfileSharingEnabled(); final var archived = contact != null && contact.isArchived(); + final var contactGivenName = contact == null ? null : contact.getGivenName(); + final var contactFamilyName = contact == null ? null : contact.getFamilyName(); if (blocked != contactRecord.isBlocked() || profileShared != contactRecord.isProfileSharingEnabled() - || archived != contactRecord.isArchived()) { + || archived != contactRecord.isArchived() + || ( + contactRecord.getSystemGivenName().isPresent() && !contactRecord.getSystemGivenName() + .get() + .equals(contactGivenName) + ) + || ( + contactRecord.getSystemFamilyName().isPresent() && !contactRecord.getSystemFamilyName() + .get() + .equals(contactFamilyName) + )) { logger.debug("Storing new or updated contact {}", recipientId); final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var newContact = contactBuilder.withBlocked(contactRecord.isBlocked()) .withProfileSharingEnabled(contactRecord.isProfileSharingEnabled()) - .withArchived(contactRecord.isArchived()) - .build(); - account.getContactStore().storeContact(recipientId, newContact); + .withArchived(contactRecord.isArchived()); + if (contactRecord.getSystemGivenName().isPresent() || contactRecord.getSystemFamilyName().isPresent()) { + newContact.withGivenName(contactRecord.getSystemGivenName().orElse(null)) + .withFamilyName(contactRecord.getSystemFamilyName().orElse(null)); + } + account.getContactStore().storeContact(recipientId, newContact.build()); } final var profile = account.getProfileStore().getProfile(recipientId); - final var givenName = profile == null ? null : profile.getGivenName(); - final var familyName = profile == null ? null : profile.getFamilyName(); - if ((contactRecord.getGivenName().isPresent() && !contactRecord.getGivenName().get().equals(givenName)) || ( - contactRecord.getFamilyName().isPresent() && !contactRecord.getFamilyName().get().equals(familyName) + final var profileGivenName = profile == null ? null : profile.getGivenName(); + final var profileFamilyName = profile == null ? null : profile.getFamilyName(); + if (( + contactRecord.getProfileGivenName().isPresent() && !contactRecord.getProfileGivenName() + .get() + .equals(profileGivenName) + ) || ( + contactRecord.getProfileFamilyName().isPresent() && !contactRecord.getProfileFamilyName() + .get() + .equals(profileFamilyName) )) { final var profileBuilder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile); - final var newProfile = profileBuilder.withGivenName(contactRecord.getGivenName().orElse(null)) - .withFamilyName(contactRecord.getFamilyName().orElse(null)) + final var newProfile = profileBuilder.withGivenName(contactRecord.getProfileGivenName().orElse(null)) + .withFamilyName(contactRecord.getProfileFamilyName().orElse(null)) .build(); account.getProfileStore().storeProfile(recipientId, newProfile); } From 0c74338c9caeb39cdb378eb61b5f0570e06684e0 Mon Sep 17 00:00:00 2001 From: technillogue Date: Thu, 6 Oct 2022 17:57:14 +0200 Subject: [PATCH 004/713] Bump user agent version Closes #1024 --- src/main/java/org/asamk/signal/BaseConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/asamk/signal/BaseConfig.java b/src/main/java/org/asamk/signal/BaseConfig.java index 696fc478..338873f2 100644 --- a/src/main/java/org/asamk/signal/BaseConfig.java +++ b/src/main/java/org/asamk/signal/BaseConfig.java @@ -5,7 +5,7 @@ public class BaseConfig { public final static String PROJECT_NAME = BaseConfig.class.getPackage().getImplementationTitle(); public final static String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion(); - final static String USER_AGENT_SIGNAL_ANDROID = "Signal-Android/5.51.7"; + final static String USER_AGENT_SIGNAL_ANDROID = "Signal-Android/5.52.1"; final static String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null ? "signal-cli" : PROJECT_NAME + "/" + PROJECT_VERSION; From abc5d5e863d1a324542e694abeb8a52de34275e8 Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 6 Oct 2022 17:59:59 +0200 Subject: [PATCH 005/713] Bump version --- CHANGELOG.md | 5 +++++ build.gradle.kts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efefc6e3..eb473c71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased] +## [0.11.2] - 2022-10-06 + +### Fixed +- Update user agent version to work with new Signal-Server check + ## [0.11.1] - 2022-10-05 ### Fixed diff --git a/build.gradle.kts b/build.gradle.kts index 07238b6f..b8bc9941 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("org.graalvm.buildtools.native") version "0.9.14" } -version = "0.11.1" +version = "0.11.2" java { sourceCompatibility = JavaVersion.VERSION_17 From cf0110ab95f3256e106cd948f4cfcc5b64e48d1a Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 6 Oct 2022 21:56:40 +0200 Subject: [PATCH 006/713] Update libsignal-service Fixes #1030 --- lib/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 2dde3b39..ae431ffb 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -14,9 +14,9 @@ repositories { } dependencies { - implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_59") + implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_61") implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4") - implementation("com.google.protobuf", "protobuf-javalite", "3.11.4") + implementation("com.google.protobuf", "protobuf-javalite", "3.21.6") implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") implementation("org.slf4j", "slf4j-api", "2.0.3") implementation("org.xerial", "sqlite-jdbc", "3.39.3.0") From 9a4693136d8030a55c62dbc5746ba9d1aac96de9 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 12:04:22 +0200 Subject: [PATCH 007/713] Fix update from old versions without PNI Fixes #1032 --- .../java/org/asamk/signal/manager/helper/AccountHelper.java | 4 ++++ .../java/org/asamk/signal/manager/storage/SignalAccount.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java index ce45dd2c..0b19a691 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java @@ -9,6 +9,7 @@ import org.asamk.signal.manager.api.NonNormalizedPhoneNumberException; import org.asamk.signal.manager.api.PinLockedException; import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.storage.SignalAccount; +import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.NumberVerificationUtils; import org.signal.libsignal.protocol.InvalidKeyException; import org.slf4j.Logger; @@ -99,6 +100,9 @@ public class AccountHelper { account.setNumber(number); account.setAci(aci); account.setPni(pni); + if (account.isPrimaryDevice() && account.getPniIdentityKeyPair() == null && account.getPni() != null) { + account.setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair()); + } account.getRecipientTrustedResolver().resolveSelfRecipientTrusted(account.getSelfRecipientAddress()); // TODO check and update remote storage context.getUnidentifiedAccessHelper().rotateSenderCertificates(); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 279f6ee8..ff75b22b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -402,7 +402,7 @@ public class SignalAccount implements Closeable { // Old config file, creating new profile key setProfileKey(KeyUtils.createProfileKey()); } - if (isPrimaryDevice() && getPniIdentityKeyPair() == null) { + if (isPrimaryDevice() && getPniIdentityKeyPair() == null && getPni() != null) { setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair()); } } From 8e717e00b1bde958be61c7d36f71cc82acd17309 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 12:09:43 +0200 Subject: [PATCH 008/713] Add missing urgent column to projection Fixes #1031 --- .../signal/manager/storage/sendLog/MessageSendLogStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/sendLog/MessageSendLogStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/sendLog/MessageSendLogStore.java index d0034d1b..f672667d 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/sendLog/MessageSendLogStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/sendLog/MessageSendLogStore.java @@ -86,7 +86,7 @@ public class MessageSendLogStore implements AutoCloseable { final ServiceId serviceId, final int deviceId, final long timestamp, final boolean isSenderKey ) { final var sql = """ - SELECT group_id, content, content_hint + SELECT group_id, content, content_hint, urgent FROM %s l INNER JOIN %s lc ON l.content_id = lc._id WHERE l.uuid = ? AND l.device_id = ? AND lc.timestamp = ? From 9c5235c273014a075ed57c317e84997a00d1f7a5 Mon Sep 17 00:00:00 2001 From: Benjamin Schmid Date: Fri, 7 Oct 2022 17:16:32 +0200 Subject: [PATCH 009/713] fix(GraalVM): explictly declare symbols causing GraalVM compiler failure (#1037) Fixes #1016 --- graalvm-config-dir/reflect-config.json | 103 +++++++++++++++++++++---- 1 file changed, 90 insertions(+), 13 deletions(-) diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index c520d678..16d4e025 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -1055,21 +1055,38 @@ "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.util.List"] }] + "methods":[ + {"name":"","parameterTypes":["java.util.List"] }, + {"name":"groups","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.groups.LegacyGroupStore$Storage$GroupV1", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","java.lang.String","int","boolean","boolean","java.util.List"] }] + "methods":[ + {"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","java.lang.String","int","boolean","boolean","java.util.List"] }, + {"name":"groupId","parameterTypes":[] }, + {"name":"expectedV2Id","parameterTypes":[] }, + {"name":"name","parameterTypes":[] }, + {"name":"color","parameterTypes":[] }, + {"name":"messageExpirationTime","parameterTypes":[] }, + {"name":"blocked","parameterTypes":[] }, + {"name":"archived","parameterTypes":[] }, + {"name":"members","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.groups.LegacyGroupStore$Storage$GroupV1$JsonRecipientAddress", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String"] }] + "methods":[ + {"name":"","parameterTypes":["java.lang.String","java.lang.String"] }, + {"name":"uuid","parameterTypes":[] }, + {"name":"number","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.groups.LegacyGroupStore$Storage$GroupV1$MembersDeserializer", @@ -1080,14 +1097,26 @@ "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","boolean","boolean"] }] + "methods":[ + {"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","boolean","boolean"] }, + {"name":"groupId","parameterTypes":[] }, + {"name":"masterKey","parameterTypes":[] }, + {"name":"distributionId","parameterTypes":[] }, + {"name":"blocked","parameterTypes":[] }, + {"name":"permissionDenied","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.identities.LegacyIdentityKeyStore$IdentityStorage", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.lang.String","int","long"] }] + "methods":[ + {"name":"","parameterTypes":["java.lang.String","int","long"] }, + {"name":"addedTimestamp","parameterTypes":[] }, + {"name":"trustLevel","parameterTypes":[] }, + {"name":"identityKey","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.profiles.LegacyProfileStore", @@ -1150,28 +1179,60 @@ "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.util.List","long"] }] + "methods":[ + {"name":"","parameterTypes":["java.util.List","long"] }, + {"name":"lastId","parameterTypes":[] }, + {"name":"recipients","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Contact","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Profile"] }] + "methods":[ + {"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Contact","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Profile"] }, + {"name":"id","parameterTypes":[] }, + {"name":"number","parameterTypes":[] }, + {"name":"uuid","parameterTypes":[] }, + {"name":"profileKey","parameterTypes":[] }, + {"name":"expiringProfileKeyCredential","parameterTypes":[] }, + {"name":"contact","parameterTypes":[] }, + {"name":"profile","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Contact", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String","int","boolean","boolean","boolean"] }] + "methods":[ + {"name":"","parameterTypes":["java.lang.String","java.lang.String","int","boolean","boolean","boolean"] }, + {"name":"name","parameterTypes":[] }, + {"name":"color","parameterTypes":[] }, + {"name":"messageExpirationTime","parameterTypes":[] }, + {"name":"blocked","parameterTypes":[] }, + {"name":"archived","parameterTypes":[] }, + {"name":"profileSharingEnabled","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Profile", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.util.Set"] }] + "methods":[ + {"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.util.Set"] }, + {"name":"lastUpdateTimestamp","parameterTypes":[] }, + {"name":"givenName","parameterTypes":[] }, + {"name":"familyName","parameterTypes":[] }, + {"name":"about","parameterTypes":[] }, + {"name":"aboutEmoji","parameterTypes":[] }, + {"name":"avatarUrlPath","parameterTypes":[] }, + {"name":"mobileCoinAddress","parameterTypes":[] }, + {"name":"unidentifiedAccessMode","parameterTypes":[] }, + {"name":"capabilities","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.recipients.RecipientAddress", @@ -1188,14 +1249,22 @@ "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.util.List"] }] + "methods":[ + {"name":"","parameterTypes":["java.util.List"] }, + {"name":"sharedSenderKeys","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.senderKeys.LegacySenderKeySharedStore$Storage$SharedSenderKey", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["long","int","java.lang.String"] }] + "methods":[ + {"name":"","parameterTypes":["long","int","java.lang.String"] }, + {"name":"recipientId","parameterTypes":[] }, + {"name":"deviceId","parameterTypes":[] }, + {"name":"distributionId","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack", @@ -1228,14 +1297,22 @@ "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.util.List"] }] + "methods":[ + {"name":"","parameterTypes":["java.util.List"] }, + {"name":"stickers","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.manager.storage.stickers.LegacyStickerStore$Storage$Sticker", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String","boolean"] }] + "methods":[ + {"name":"","parameterTypes":["java.lang.String","java.lang.String","boolean"] }, + {"name":"packId","parameterTypes":[] }, + {"name":"packKey","parameterTypes":[] }, + {"name":"installed","parameterTypes":[] } + ] }, { "name":"org.asamk.signal.util.SecurityProvider$DefaultRandom", From 31429b7fafefed3d3cf1dc327cbb7730cd5869c0 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 17:24:29 +0200 Subject: [PATCH 010/713] Bump version --- CHANGELOG.md | 8 ++++++++ build.gradle.kts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb473c71..a2dfae92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## [Unreleased] +## [0.11.3] - 2022-10-07 + +### Fixed +- Fix sending messages to groups (in non-daemon mode) +- Fix updating from older signal-cli version +- Fix issue with handling decryption error message +- Fix graalvm native build (Thanks @bentolor) + ## [0.11.2] - 2022-10-06 ### Fixed diff --git a/build.gradle.kts b/build.gradle.kts index b8bc9941..97f2109b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("org.graalvm.buildtools.native") version "0.9.14" } -version = "0.11.2" +version = "0.11.3" java { sourceCompatibility = JavaVersion.VERSION_17 From a708025a162e4a5a4c77b268813394528bfd1870 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 19:30:34 +0200 Subject: [PATCH 011/713] GraalVM agent formatting changes --- graalvm-config-dir/reflect-config.json | 118 ++++++++++++------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 16d4e025..4dc7e3e2 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -1056,7 +1056,7 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.util.List"] }, + {"name":"","parameterTypes":["java.util.List"] }, {"name":"groups","parameterTypes":[] } ] }, @@ -1066,15 +1066,15 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","java.lang.String","int","boolean","boolean","java.util.List"] }, - {"name":"groupId","parameterTypes":[] }, - {"name":"expectedV2Id","parameterTypes":[] }, - {"name":"name","parameterTypes":[] }, - {"name":"color","parameterTypes":[] }, - {"name":"messageExpirationTime","parameterTypes":[] }, - {"name":"blocked","parameterTypes":[] }, - {"name":"archived","parameterTypes":[] }, - {"name":"members","parameterTypes":[] } + {"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","java.lang.String","int","boolean","boolean","java.util.List"] }, + {"name":"archived","parameterTypes":[] }, + {"name":"blocked","parameterTypes":[] }, + {"name":"color","parameterTypes":[] }, + {"name":"expectedV2Id","parameterTypes":[] }, + {"name":"groupId","parameterTypes":[] }, + {"name":"members","parameterTypes":[] }, + {"name":"messageExpirationTime","parameterTypes":[] }, + {"name":"name","parameterTypes":[] } ] }, { @@ -1083,9 +1083,9 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.lang.String","java.lang.String"] }, - {"name":"uuid","parameterTypes":[] }, - {"name":"number","parameterTypes":[] } + {"name":"","parameterTypes":["java.lang.String","java.lang.String"] }, + {"name":"number","parameterTypes":[] }, + {"name":"uuid","parameterTypes":[] } ] }, { @@ -1098,11 +1098,11 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","boolean","boolean"] }, - {"name":"groupId","parameterTypes":[] }, - {"name":"masterKey","parameterTypes":[] }, - {"name":"distributionId","parameterTypes":[] }, - {"name":"blocked","parameterTypes":[] }, + {"name":"","parameterTypes":["java.lang.String","java.lang.String","java.lang.String","boolean","boolean"] }, + {"name":"blocked","parameterTypes":[] }, + {"name":"distributionId","parameterTypes":[] }, + {"name":"groupId","parameterTypes":[] }, + {"name":"masterKey","parameterTypes":[] }, {"name":"permissionDenied","parameterTypes":[] } ] }, @@ -1112,10 +1112,10 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.lang.String","int","long"] }, - {"name":"addedTimestamp","parameterTypes":[] }, - {"name":"trustLevel","parameterTypes":[] }, - {"name":"identityKey","parameterTypes":[] } + {"name":"","parameterTypes":["java.lang.String","int","long"] }, + {"name":"addedTimestamp","parameterTypes":[] }, + {"name":"identityKey","parameterTypes":[] }, + {"name":"trustLevel","parameterTypes":[] } ] }, { @@ -1180,10 +1180,10 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.util.List","long"] }, - {"name":"lastId","parameterTypes":[] }, + {"name":"","parameterTypes":["java.util.List","long"] }, + {"name":"lastId","parameterTypes":[] }, {"name":"recipients","parameterTypes":[] } - ] + ] }, { "name":"org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient", @@ -1191,14 +1191,14 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Contact","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Profile"] }, - {"name":"id","parameterTypes":[] }, - {"name":"number","parameterTypes":[] }, - {"name":"uuid","parameterTypes":[] }, - {"name":"profileKey","parameterTypes":[] }, - {"name":"expiringProfileKeyCredential","parameterTypes":[] }, - {"name":"contact","parameterTypes":[] }, - {"name":"profile","parameterTypes":[] } + {"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Contact","org.asamk.signal.manager.storage.recipients.LegacyRecipientStore2$Storage$Recipient$Profile"] }, + {"name":"contact","parameterTypes":[] }, + {"name":"expiringProfileKeyCredential","parameterTypes":[] }, + {"name":"id","parameterTypes":[] }, + {"name":"number","parameterTypes":[] }, + {"name":"profile","parameterTypes":[] }, + {"name":"profileKey","parameterTypes":[] }, + {"name":"uuid","parameterTypes":[] } ] }, { @@ -1207,12 +1207,12 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.lang.String","java.lang.String","int","boolean","boolean","boolean"] }, - {"name":"name","parameterTypes":[] }, - {"name":"color","parameterTypes":[] }, - {"name":"messageExpirationTime","parameterTypes":[] }, - {"name":"blocked","parameterTypes":[] }, - {"name":"archived","parameterTypes":[] }, + {"name":"","parameterTypes":["java.lang.String","java.lang.String","int","boolean","boolean","boolean"] }, + {"name":"archived","parameterTypes":[] }, + {"name":"blocked","parameterTypes":[] }, + {"name":"color","parameterTypes":[] }, + {"name":"messageExpirationTime","parameterTypes":[] }, + {"name":"name","parameterTypes":[] }, {"name":"profileSharingEnabled","parameterTypes":[] } ] }, @@ -1222,16 +1222,16 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.util.Set"] }, - {"name":"lastUpdateTimestamp","parameterTypes":[] }, - {"name":"givenName","parameterTypes":[] }, - {"name":"familyName","parameterTypes":[] }, - {"name":"about","parameterTypes":[] }, - {"name":"aboutEmoji","parameterTypes":[] }, - {"name":"avatarUrlPath","parameterTypes":[] }, - {"name":"mobileCoinAddress","parameterTypes":[] }, - {"name":"unidentifiedAccessMode","parameterTypes":[] }, - {"name":"capabilities","parameterTypes":[] } + {"name":"","parameterTypes":["long","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.lang.String","java.util.Set"] }, + {"name":"about","parameterTypes":[] }, + {"name":"aboutEmoji","parameterTypes":[] }, + {"name":"avatarUrlPath","parameterTypes":[] }, + {"name":"capabilities","parameterTypes":[] }, + {"name":"familyName","parameterTypes":[] }, + {"name":"givenName","parameterTypes":[] }, + {"name":"lastUpdateTimestamp","parameterTypes":[] }, + {"name":"mobileCoinAddress","parameterTypes":[] }, + {"name":"unidentifiedAccessMode","parameterTypes":[] } ] }, { @@ -1250,7 +1250,7 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.util.List"] }, + {"name":"","parameterTypes":["java.util.List"] }, {"name":"sharedSenderKeys","parameterTypes":[] } ] }, @@ -1260,10 +1260,10 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["long","int","java.lang.String"] }, - {"name":"recipientId","parameterTypes":[] }, - {"name":"deviceId","parameterTypes":[] }, - {"name":"distributionId","parameterTypes":[] } + {"name":"","parameterTypes":["long","int","java.lang.String"] }, + {"name":"deviceId","parameterTypes":[] }, + {"name":"distributionId","parameterTypes":[] }, + {"name":"recipientId","parameterTypes":[] } ] }, { @@ -1298,7 +1298,7 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.util.List"] }, + {"name":"","parameterTypes":["java.util.List"] }, {"name":"stickers","parameterTypes":[] } ] }, @@ -1308,10 +1308,10 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ - {"name":"","parameterTypes":["java.lang.String","java.lang.String","boolean"] }, - {"name":"packId","parameterTypes":[] }, - {"name":"packKey","parameterTypes":[] }, - {"name":"installed","parameterTypes":[] } + {"name":"","parameterTypes":["java.lang.String","java.lang.String","boolean"] }, + {"name":"installed","parameterTypes":[] }, + {"name":"packId","parameterTypes":[] }, + {"name":"packKey","parameterTypes":[] } ] }, { From 489fb2ac2272f2ca1b06c18d4a951e4d502fdd13 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 19:31:27 +0200 Subject: [PATCH 012/713] Improve error message when joining a group with already pending admin approval --- .../main/java/org/asamk/signal/manager/Manager.java | 3 ++- .../java/org/asamk/signal/manager/ManagerImpl.java | 3 ++- .../manager/api/PendingAdminApprovalException.java | 12 ++++++++++++ .../org/asamk/signal/manager/helper/GroupHelper.java | 6 +++++- .../org/asamk/signal/commands/JoinGroupCommand.java | 3 +++ .../java/org/asamk/signal/dbus/DbusSignalImpl.java | 3 +++ 6 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/api/PendingAdminApprovalException.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index 4bc4019c..eb62cb60 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -12,6 +12,7 @@ import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; +import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.ReceiveConfig; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; @@ -108,7 +109,7 @@ public interface Manager extends Closeable { Pair joinGroup( GroupInviteLinkUrl inviteLinkUrl - ) throws IOException, InactiveGroupLinkException; + ) throws IOException, InactiveGroupLinkException, PendingAdminApprovalException; SendMessageResults sendTypingMessage( TypingAction action, Set recipients diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index 386e6fbe..6dc7b9a6 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -27,6 +27,7 @@ import org.asamk.signal.manager.api.InvalidStickerException; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; +import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.ReceiveConfig; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; @@ -431,7 +432,7 @@ class ManagerImpl implements Manager { @Override public Pair joinGroup( GroupInviteLinkUrl inviteLinkUrl - ) throws IOException, InactiveGroupLinkException { + ) throws IOException, InactiveGroupLinkException, PendingAdminApprovalException { return context.getGroupHelper().joinGroup(inviteLinkUrl); } diff --git a/lib/src/main/java/org/asamk/signal/manager/api/PendingAdminApprovalException.java b/lib/src/main/java/org/asamk/signal/manager/api/PendingAdminApprovalException.java new file mode 100644 index 00000000..8da3ca51 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/PendingAdminApprovalException.java @@ -0,0 +1,12 @@ +package org.asamk.signal.manager.api; + +public class PendingAdminApprovalException extends Exception { + + public PendingAdminApprovalException(final String message) { + super(message); + } + + public PendingAdminApprovalException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index 5a262685..3f8740d9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -4,6 +4,7 @@ import org.asamk.signal.manager.SignalDependencies; import org.asamk.signal.manager.api.AttachmentInvalidException; import org.asamk.signal.manager.api.InactiveGroupLinkException; import org.asamk.signal.manager.api.Pair; +import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResult; import org.asamk.signal.manager.config.ServiceConfig; @@ -290,7 +291,7 @@ public class GroupHelper { public Pair joinGroup( GroupInviteLinkUrl inviteLinkUrl - ) throws IOException, InactiveGroupLinkException { + ) throws IOException, InactiveGroupLinkException, PendingAdminApprovalException { final DecryptedGroupJoinInfo groupJoinInfo; try { groupJoinInfo = context.getGroupV2Helper() @@ -298,6 +299,9 @@ public class GroupHelper { } catch (GroupLinkNotActiveException e) { throw new InactiveGroupLinkException("Group link inactive (reason: " + e.getReason() + ")", e); } + if (groupJoinInfo.getPendingAdminApproval()) { + throw new PendingAdminApprovalException("You have already requested to join the group."); + } final var groupChange = context.getGroupV2Helper() .joinGroup(inviteLinkUrl.getGroupMasterKey(), inviteLinkUrl.getPassword(), groupJoinInfo); final var group = getOrMigrateGroup(inviteLinkUrl.getGroupMasterKey(), diff --git a/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java b/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java index 31fc4caf..5e3461b7 100644 --- a/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java +++ b/src/main/java/org/asamk/signal/commands/JoinGroupCommand.java @@ -9,6 +9,7 @@ import org.asamk.signal.commands.exceptions.UnexpectedErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.InactiveGroupLinkException; +import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.groups.GroupInviteLinkUrl; import org.asamk.signal.output.JsonWriter; import org.asamk.signal.output.OutputWriter; @@ -94,6 +95,8 @@ public class JoinGroupCommand implements JsonRpcLocalCommand { .getSimpleName() + ")", e); } catch (InactiveGroupLinkException e) { throw new UserErrorException("Group link is not valid: " + e.getMessage()); + } catch (PendingAdminApprovalException e) { + throw new UserErrorException("Pending admin approval: " + e.getMessage()); } } } diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index a65c183b..4b5b3ba8 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -10,6 +10,7 @@ import org.asamk.signal.manager.api.InvalidNumberException; import org.asamk.signal.manager.api.InvalidStickerException; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.NotPrimaryDeviceException; +import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendMessageResult; import org.asamk.signal.manager.api.SendMessageResults; @@ -778,6 +779,8 @@ public class DbusSignalImpl implements Signal { } final var result = m.joinGroup(linkUrl); return result.first().serialize(); + } catch (PendingAdminApprovalException e) { + throw new Error.Failure("Pending admin approval: " + e.getMessage()); } catch (GroupInviteLinkUrl.InvalidGroupLinkException | InactiveGroupLinkException e) { throw new Error.Failure("Group link is invalid: " + e.getMessage()); } catch (GroupInviteLinkUrl.UnknownGroupLinkVersionException e) { From c9c8af42c25bc925e510c61742c7827008434676 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 19:49:43 +0200 Subject: [PATCH 013/713] Implement refuse group join requests --- .../signal/manager/helper/GroupHelper.java | 6 ++++++ .../signal/manager/helper/GroupV2Helper.java | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index 3f8740d9..be57d19b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -618,6 +618,12 @@ public class GroupHelper { var groupGroupChangePair = groupV2Helper.revokeInvitedMembers(group, pendingRemoveMembers); result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); } + var requestingRemoveMembers = new HashSet<>(removeMembers); + requestingRemoveMembers.retainAll(group.getRequestingMembers()); + if (requestingRemoveMembers.size() > 0) { + var groupGroupChangePair = groupV2Helper.refuseJoinRequestMembers(group, requestingRemoveMembers); + result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); + } } if (admins != null) { diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java index b59eddcc..dd75a8f2 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java @@ -287,6 +287,17 @@ class GroupV2Helper { return ejectMembers(groupInfoV2, memberUuids); } + Pair refuseJoinRequestMembers( + GroupInfoV2 groupInfoV2, Set members + ) throws IOException { + final var memberUuids = members.stream() + .map(context.getRecipientHelper()::resolveSignalServiceAddress) + .map(SignalServiceAddress::getServiceId) + .map(ServiceId::uuid) + .collect(Collectors.toSet()); + return refuseJoinRequest(groupInfoV2, memberUuids); + } + Pair revokeInvitedMembers( GroupInfoV2 groupInfoV2, Set members ) throws IOException { @@ -513,6 +524,13 @@ class GroupV2Helper { return commitChange(groupInfoV2, groupOperations.createRemoveInvitationChange(uuidCipherTexts)); } + private Pair refuseJoinRequest( + GroupInfoV2 groupInfoV2, Set uuids + ) throws IOException { + final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2); + return commitChange(groupInfoV2, groupOperations.createRefuseGroupJoinRequest(uuids, false, List.of())); + } + private Pair ejectMembers( GroupInfoV2 groupInfoV2, Set uuids ) throws IOException { From 01e1115806e9d5de92baae7848906adf7d9eae2d Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 19:49:52 +0200 Subject: [PATCH 014/713] Refresh group before updating --- .../java/org/asamk/signal/manager/helper/GroupHelper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index be57d19b..90d5d726 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -513,6 +513,10 @@ public class GroupHelper { if (!g.isMember(account.getSelfRecipientId()) && !g.isPendingMember(account.getSelfRecipientId())) { throw new NotAGroupMemberException(groupId, g.getTitle()); } + if (groupId instanceof GroupIdV2) { + // Refresh group before updating + return getGroup(groupId, true); + } return g; } From 1424a2980fcfcc9373fa4bb4611eff2e3fb18294 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 20:05:49 +0200 Subject: [PATCH 015/713] Approve join requests instead of just adding the member --- .../signal/manager/helper/GroupHelper.java | 7 +++++++ .../signal/manager/helper/GroupV2Helper.java | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index 90d5d726..a342064c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -593,8 +593,15 @@ public class GroupHelper { } if (members != null) { + final var requestingMembers = new HashSet<>(members); + requestingMembers.retainAll(group.getRequestingMembers()); + if (requestingMembers.size() > 0) { + var groupGroupChangePair = groupV2Helper.approveJoinRequestMembers(group, requestingMembers); + result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); + } final var newMembers = new HashSet<>(members); newMembers.removeAll(group.getMembers()); + newMembers.removeAll(group.getRequestingMembers()); if (newMembers.size() > 0) { var groupGroupChangePair = groupV2Helper.addMembers(group, newMembers); result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second()); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java index dd75a8f2..09e3ff95 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java @@ -287,6 +287,17 @@ class GroupV2Helper { return ejectMembers(groupInfoV2, memberUuids); } + Pair approveJoinRequestMembers( + GroupInfoV2 groupInfoV2, Set members + ) throws IOException { + final var memberUuids = members.stream() + .map(context.getRecipientHelper()::resolveSignalServiceAddress) + .map(SignalServiceAddress::getServiceId) + .map(ServiceId::uuid) + .collect(Collectors.toSet()); + return approveJoinRequest(groupInfoV2, memberUuids); + } + Pair refuseJoinRequestMembers( GroupInfoV2 groupInfoV2, Set members ) throws IOException { @@ -524,6 +535,13 @@ class GroupV2Helper { return commitChange(groupInfoV2, groupOperations.createRemoveInvitationChange(uuidCipherTexts)); } + private Pair approveJoinRequest( + GroupInfoV2 groupInfoV2, Set uuids + ) throws IOException { + final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2); + return commitChange(groupInfoV2, groupOperations.createApproveGroupJoinRequest(uuids)); + } + private Pair refuseJoinRequest( GroupInfoV2 groupInfoV2, Set uuids ) throws IOException { From a247b444e52108abdaab3c668fa6c8bd2f1cc9ed Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 20:05:58 +0200 Subject: [PATCH 016/713] Fix typo --- lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index 6dc7b9a6..afc290b7 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -546,7 +546,7 @@ class ManagerImpl implements Manager { final var selfProfile = context.getProfileHelper().getSelfProfile(); if (selfProfile == null || selfProfile.getDisplayName().isEmpty()) { logger.warn( - "No profile name set. When sending a message it's recommended to set a profile name wit the updateProfile command. This may become mandatory in the future."); + "No profile name set. When sending a message it's recommended to set a profile name with the updateProfile command. This may become mandatory in the future."); } final var messageBuilder = SignalServiceDataMessage.newBuilder(); applyMessage(messageBuilder, message); From 30167d81e68219298a01cb4f35e1e615bb4216be Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 20:36:50 +0200 Subject: [PATCH 017/713] Add missing check for story group context --- .../helper/IncomingMessageHandler.java | 64 +++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index 7f83caf5..4f696c92 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -42,6 +42,7 @@ import org.signal.libsignal.metadata.ProtocolInvalidMessageException; import org.signal.libsignal.metadata.ProtocolNoSessionException; import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException; import org.signal.libsignal.metadata.SelfSendException; +import org.signal.libsignal.protocol.InvalidMessageException; import org.signal.libsignal.protocol.message.DecryptionErrorMessage; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; @@ -51,6 +52,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceGroup; +import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext; import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2; import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage; import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage; @@ -505,6 +507,32 @@ public final class IncomingMessageHandler { return actions; } + private SignalServiceGroupContext getGroupContext(SignalServiceContent content) { + if (content == null) { + return null; + } + + if (content.getDataMessage().isPresent()) { + var message = content.getDataMessage().get(); + if (message.getGroupContext().isPresent()) { + return message.getGroupContext().get(); + } + } + + if (content.getStoryMessage().isPresent()) { + var message = content.getStoryMessage().get(); + if (message.getGroupContext().isPresent()) { + try { + return SignalServiceGroupContext.create(null, message.getGroupContext().get()); + } catch (InvalidMessageException e) { + throw new AssertionError(e); + } + } + } + + return null; + } + private boolean isMessageBlocked(SignalServiceEnvelope envelope, SignalServiceContent content) { SignalServiceAddress source; if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) { @@ -519,12 +547,10 @@ public final class IncomingMessageHandler { return true; } - if (content != null && content.getDataMessage().isPresent()) { - var message = content.getDataMessage().get(); - if (message.getGroupContext().isPresent()) { - var groupId = GroupUtils.getGroupId(message.getGroupContext().get()); - return context.getGroupHelper().isGroupBlocked(groupId); - } + final var groupContext = getGroupContext(content); + if (groupContext != null) { + var groupId = GroupUtils.getGroupId(groupContext); + return context.getGroupHelper().isGroupBlocked(groupId); } return false; @@ -540,38 +566,38 @@ public final class IncomingMessageHandler { return false; } - if (content == null || content.getDataMessage().isEmpty()) { + final var groupContext = getGroupContext(content); + if (groupContext == null) { return false; } - var message = content.getDataMessage().get(); - if (message.getGroupContext().isEmpty()) { - return false; - } - - if (message.getGroupContext().get().getGroupV1().isPresent()) { - var groupInfo = message.getGroupContext().get().getGroupV1().get(); + if (groupContext.getGroupV1().isPresent()) { + var groupInfo = groupContext.getGroupV1().get(); if (groupInfo.getType() == SignalServiceGroup.Type.QUIT) { return false; } } - var groupId = GroupUtils.getGroupId(message.getGroupContext().get()); + var groupId = GroupUtils.getGroupId(groupContext); var group = context.getGroupHelper().getGroup(groupId); if (group == null) { return false; } + final var message = content.getDataMessage().orElse(null); + final var recipientId = context.getRecipientHelper().resolveRecipient(source); - if (!group.isMember(recipientId) && !(group.isPendingMember(recipientId) && message.isGroupV2Update())) { + if (!group.isMember(recipientId) && !( + group.isPendingMember(recipientId) && message != null && message.isGroupV2Update() + )) { return true; } if (group.isAnnouncementGroup() && !group.isAdmin(recipientId)) { - return message.getBody().isPresent() + return message == null + || message.getBody().isPresent() || message.getAttachments().isPresent() - || message.getQuote() - .isPresent() + || message.getQuote().isPresent() || message.getPreviews().isPresent() || message.getMentions().isPresent() || message.getSticker().isPresent(); From 605f31d1ad7c445e2f05014cc6a8a977ed14e7b6 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 20:47:40 +0200 Subject: [PATCH 018/713] Improve handling of group join messages --- .../signal/manager/helper/IncomingMessageHandler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index 4f696c92..9a4a0af0 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -185,10 +185,18 @@ public final class IncomingMessageHandler { account.getMessageSendLogStore().deleteEntryForRecipient(envelope.getTimestamp(), sender, senderDeviceId); } + var notAllowedToSendToGroup = isNotAllowedToSendToGroup(envelope, content); + final var groupContext = getGroupContext(content); + if (groupContext != null && groupContext.getGroupV2().isPresent()) { + handleGroupV2Context(groupContext.getGroupV2().get()); + } + // Check again in case the user just joined the group + notAllowedToSendToGroup = notAllowedToSendToGroup && isNotAllowedToSendToGroup(envelope, content); + if (isMessageBlocked(envelope, content)) { logger.info("Ignoring a message from blocked user/group: {}", envelope.getTimestamp()); return List.of(); - } else if (isNotAllowedToSendToGroup(envelope, content)) { + } else if (notAllowedToSendToGroup) { logger.info("Ignoring a group message from an unauthorized sender (no member or admin): {} {}", (envelope.hasSourceUuid() ? envelope.getSourceAddress() : content.getSender()).getIdentifier(), envelope.getTimestamp()); From ca5951861acb790345648b426fe91b41cbcc5da7 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 21:50:07 +0200 Subject: [PATCH 019/713] Fix issue when receiving invalid message from invalid sender --- .../helper/IncomingMessageHandler.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index 9a4a0af0..569168de 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -139,17 +139,23 @@ public final class IncomingMessageHandler { } else { final var senderProfile = context.getProfileHelper().getRecipientProfile(sender); final var selfProfile = context.getProfileHelper().getSelfProfile(); - final var serviceId = ServiceId.parseOrThrow(e.getSender()); - if ((!sender.equals(account.getSelfRecipientId()) || e.getSenderDevice() != account.getDeviceId()) - && senderProfile != null - && senderProfile.getCapabilities().contains(Profile.Capability.senderKey) - && selfProfile != null - && selfProfile.getCapabilities().contains(Profile.Capability.senderKey)) { - logger.debug("Received invalid message, requesting message resend."); - actions.add(new SendRetryMessageRequestAction(sender, serviceId, e, envelope)); + final var serviceId = ServiceId.parseOrNull(e.getSender()); + if (serviceId != null) { + final var isSelf = sender.equals(account.getSelfRecipientId()) + && e.getSenderDevice() == account.getDeviceId(); + final var isSenderSenderKeyCapable = senderProfile != null && senderProfile.getCapabilities() + .contains(Profile.Capability.senderKey); + final var isSelfSenderKeyCapable = selfProfile != null && selfProfile.getCapabilities() + .contains(Profile.Capability.senderKey); + if (!isSelf && isSenderSenderKeyCapable && isSelfSenderKeyCapable) { + logger.debug("Received invalid message, requesting message resend."); + actions.add(new SendRetryMessageRequestAction(sender, serviceId, e, envelope)); + } else { + logger.debug("Received invalid message, queuing renew session action."); + actions.add(new RenewSessionAction(sender, serviceId)); + } } else { - logger.debug("Received invalid message, queuing renew session action."); - actions.add(new RenewSessionAction(sender, serviceId)); + logger.debug("Received invalid message from invalid sender: {}", e.getSender()); } } exception = e; From 34cc64f8ce97a63c859bd95faf6783422f14df61 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Oct 2022 21:51:01 +0200 Subject: [PATCH 020/713] Ensure self profile key is always stored in profile store Fixes #1040 --- .../java/org/asamk/signal/manager/storage/SignalAccount.java | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index ff75b22b..335aece5 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -402,6 +402,7 @@ public class SignalAccount implements Closeable { // Old config file, creating new profile key setProfileKey(KeyUtils.createProfileKey()); } + getProfileStore().storeProfileKey(getSelfRecipientId(), getProfileKey()); if (isPrimaryDevice() && getPniIdentityKeyPair() == null && getPni() != null) { setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair()); } From 7eb7ee44f2dd85431bf8077965f73cf14d477000 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 8 Oct 2022 12:40:00 +0200 Subject: [PATCH 021/713] Refactor RecipientAddress --- .../org/asamk/signal/manager/Manager.java | 2 +- .../org/asamk/signal/manager/ManagerImpl.java | 19 ++- .../org/asamk/signal/manager/api/Group.java | 6 +- .../asamk/signal/manager/api/Identity.java | 1 - .../signal/manager/api/MessageEnvelope.java | 38 +++-- .../asamk/signal/manager/api/Recipient.java | 153 ++++++++++++++++++ .../signal/manager/api/RecipientAddress.java | 71 ++++++++ .../manager/api/RecipientIdentifier.java | 1 - .../signal/manager/api/SendMessageResult.java | 3 +- .../api/UnregisteredRecipientException.java | 2 - .../api/UntrustedIdentityException.java | 2 - .../signal/manager/helper/IdentityHelper.java | 2 +- .../helper/IncomingMessageHandler.java | 6 +- .../signal/manager/helper/ReceiveHelper.java | 4 +- .../manager/helper/RecipientHelper.java | 7 +- .../signal/manager/helper/StorageHelper.java | 3 +- .../signal/manager/storage/SignalAccount.java | 8 +- .../asamk/signal/manager/storage/Utils.java | 3 +- .../storage/contacts/LegacyContactInfo.java | 3 +- .../storage/groups/LegacyGroupStore.java | 4 +- .../storage/profiles/LegacyProfileStore.java | 6 +- .../protocol/LegacyJsonIdentityKeyStore.java | 3 +- .../protocol/LegacyJsonSessionStore.java | 3 +- .../recipients/LegacyRecipientStore.java | 6 +- .../recipients/LegacyRecipientStore2.java | 4 +- .../storage/recipients/RecipientAddress.java | 68 +++++--- .../storage/recipients/RecipientResolver.java | 2 +- .../storage/recipients/RecipientStore.java | 46 +++--- .../LegacySenderKeyRecordStore.java | 9 +- .../LegacySenderKeySharedStore.java | 7 +- .../storage/sessions/LegacySessionStore.java | 7 +- .../org/asamk/signal/manager/util/Utils.java | 2 +- .../asamk/signal/ReceiveMessageHandler.java | 2 +- .../signal/commands/ListGroupsCommand.java | 2 +- .../asamk/signal/dbus/DbusManagerImpl.java | 4 +- .../dbus/DbusReceiveMessageHandler.java | 2 +- .../org/asamk/signal/dbus/DbusSignalImpl.java | 2 +- .../signal/json/JsonMessageEnvelope.java | 2 +- .../signal/json/JsonRecipientAddress.java | 2 +- .../asamk/signal/json/JsonSyncMessage.java | 2 +- 40 files changed, 392 insertions(+), 127 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/api/Recipient.java create mode 100644 lib/src/main/java/org/asamk/signal/manager/api/RecipientAddress.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index eb62cb60..007a783e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -14,6 +14,7 @@ import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.ReceiveConfig; +import org.asamk.signal.manager.api.Recipient; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; @@ -32,7 +33,6 @@ import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.storage.recipients.Profile; -import org.asamk.signal.manager.storage.recipients.Recipient; import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; import java.io.Closeable; diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index afc290b7..fc38c92a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -29,6 +29,7 @@ import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.PendingAdminApprovalException; import org.asamk.signal.manager.api.ReceiveConfig; +import org.asamk.signal.manager.api.Recipient; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResult; @@ -54,7 +55,6 @@ import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.groups.GroupInfo; import org.asamk.signal.manager.storage.identities.IdentityInfo; import org.asamk.signal.manager.storage.recipients.Profile; -import org.asamk.signal.manager.storage.recipients.Recipient; import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack; import org.asamk.signal.manager.storage.stickerPacks.StickerPackStore; @@ -707,13 +707,13 @@ class ManagerImpl implements Manager { @Override public void deleteRecipient(final RecipientIdentifier.Single recipient) { - account.removeRecipient(account.getRecipientResolver().resolveRecipient(recipient.toPartialRecipientAddress())); + account.removeRecipient(account.getRecipientResolver().resolveRecipient(recipient.getIdentifier())); } @Override public void deleteContact(final RecipientIdentifier.Single recipient) { account.getContactStore() - .deleteContact(account.getRecipientResolver().resolveRecipient(recipient.toPartialRecipientAddress())); + .deleteContact(account.getRecipientResolver().resolveRecipient(recipient.getIdentifier())); } @Override @@ -1005,7 +1005,16 @@ class ManagerImpl implements Manager { } // refresh profiles of explicitly given recipients context.getProfileHelper().refreshRecipientProfiles(recipientIds); - return account.getRecipientStore().getRecipients(onlyContacts, blocked, recipientIds, name); + return account.getRecipientStore() + .getRecipients(onlyContacts, blocked, recipientIds, name) + .stream() + .map(s -> new Recipient(s.getRecipientId(), + s.getAddress().toApiRecipientAddress(), + s.getContact(), + s.getProfileKey(), + s.getExpiringProfileKeyCredential(), + s.getProfile())) + .toList(); } @Override @@ -1049,7 +1058,7 @@ class ManagerImpl implements Manager { .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(identityInfo.getServiceId())); final var scannableFingerprint = context.getIdentityHelper() .computeSafetyNumberForScanning(identityInfo.getServiceId(), identityInfo.getIdentityKey()); - return new Identity(address, + return new Identity(address.toApiRecipientAddress(), identityInfo.getIdentityKey(), context.getIdentityHelper() .computeSafetyNumber(identityInfo.getServiceId(), identityInfo.getIdentityKey()), diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Group.java b/lib/src/main/java/org/asamk/signal/manager/api/Group.java index 9b2d988a..62f39290 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/Group.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/Group.java @@ -5,7 +5,6 @@ import org.asamk.signal.manager.groups.GroupInviteLinkUrl; import org.asamk.signal.manager.groups.GroupPermission; import org.asamk.signal.manager.helper.RecipientAddressResolver; import org.asamk.signal.manager.storage.groups.GroupInfo; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientId; import java.util.Set; @@ -40,22 +39,27 @@ public record Group( groupInfo.getMembers() .stream() .map(recipientStore::resolveRecipientAddress) + .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) .collect(Collectors.toSet()), groupInfo.getPendingMembers() .stream() .map(recipientStore::resolveRecipientAddress) + .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) .collect(Collectors.toSet()), groupInfo.getRequestingMembers() .stream() .map(recipientStore::resolveRecipientAddress) + .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) .collect(Collectors.toSet()), groupInfo.getAdminMembers() .stream() .map(recipientStore::resolveRecipientAddress) + .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) .collect(Collectors.toSet()), groupInfo.getBannedMembers() .stream() .map(recipientStore::resolveRecipientAddress) + .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) .collect(Collectors.toSet()), groupInfo.isBlocked(), groupInfo.getMessageExpirationTimer(), diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Identity.java b/lib/src/main/java/org/asamk/signal/manager/api/Identity.java index c4755576..5d43aacc 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/Identity.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/Identity.java @@ -1,6 +1,5 @@ package org.asamk.signal.manager.api; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.signal.libsignal.protocol.IdentityKey; public record Identity( diff --git a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java index 727e2eed..2140d413 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java @@ -3,7 +3,6 @@ package org.asamk.signal.manager.api; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupUtils; import org.asamk.signal.manager.helper.RecipientAddressResolver; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientResolver; import org.signal.libsignal.metadata.ProtocolException; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; @@ -184,7 +183,7 @@ public record MessageEnvelope( RecipientAddressResolver addressResolver ) { return new StoryContext(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient( - storyContext.getAuthorServiceId())), storyContext.getSentTimestamp()); + storyContext.getAuthorServiceId())).toApiRecipientAddress(), storyContext.getSentTimestamp()); } } @@ -205,7 +204,8 @@ public record MessageEnvelope( RecipientAddressResolver addressResolver ) { return new Reaction(reaction.getTargetSentTimestamp(), - addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(reaction.getTargetAuthor())), + addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(reaction.getTargetAuthor())) + .toApiRecipientAddress(), reaction.getEmoji(), reaction.isRemove()); } @@ -226,7 +226,8 @@ public record MessageEnvelope( final AttachmentFileProvider fileProvider ) { return new Quote(quote.getId(), - addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(quote.getAuthor())), + addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(quote.getAuthor())) + .toApiRecipientAddress(), Optional.ofNullable(quote.getText()), quote.getMentions() == null ? List.of() @@ -255,9 +256,8 @@ public record MessageEnvelope( RecipientResolver recipientResolver, RecipientAddressResolver addressResolver ) { - return new Mention(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(mention.getServiceId())), - mention.getStart(), - mention.getLength()); + return new Mention(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(mention.getServiceId())) + .toApiRecipientAddress(), mention.getStart(), mention.getLength()); } } @@ -552,10 +552,12 @@ public record MessageEnvelope( return new Sent(sentMessage.getTimestamp(), sentMessage.getExpirationStartTimestamp(), sentMessage.getDestination() - .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d))), + .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d)) + .toApiRecipientAddress()), sentMessage.getRecipients() .stream() - .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d))) + .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d)) + .toApiRecipientAddress()) .collect(Collectors.toSet()), sentMessage.getDataMessage() .map(message -> Data.from(message, recipientResolver, addressResolver, fileProvider)), @@ -572,7 +574,8 @@ public record MessageEnvelope( ) { return new Blocked(blockedListMessage.getAddresses() .stream() - .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d))) + .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d)) + .toApiRecipientAddress()) .toList(), blockedListMessage.getGroupIds().stream().map(GroupId::unknownVersion).toList()); } } @@ -584,8 +587,8 @@ public record MessageEnvelope( RecipientResolver recipientResolver, RecipientAddressResolver addressResolver ) { - return new Read(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(readMessage.getSender())), - readMessage.getTimestamp()); + return new Read(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(readMessage.getSender())) + .toApiRecipientAddress(), readMessage.getTimestamp()); } } @@ -596,8 +599,8 @@ public record MessageEnvelope( RecipientResolver recipientResolver, RecipientAddressResolver addressResolver ) { - return new Viewed(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(readMessage.getSender())), - readMessage.getTimestamp()); + return new Viewed(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(readMessage.getSender())) + .toApiRecipientAddress(), readMessage.getTimestamp()); } } @@ -609,7 +612,7 @@ public record MessageEnvelope( RecipientAddressResolver addressResolver ) { return new ViewOnceOpen(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient( - readMessage.getSender())), readMessage.getTimestamp()); + readMessage.getSender())).toApiRecipientAddress(), readMessage.getTimestamp()); } } @@ -637,7 +640,8 @@ public record MessageEnvelope( return new MessageRequestResponse(Type.from(messageRequestResponse.getType()), messageRequestResponse.getGroupId().map(GroupId::unknownVersion), messageRequestResponse.getPerson() - .map(p -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(p)))); + .map(p -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(p)) + .toApiRecipientAddress())); } public enum Type { @@ -898,7 +902,7 @@ public record MessageEnvelope( return new MessageEnvelope(source == null ? Optional.empty() - : Optional.of(addressResolver.resolveRecipientAddress(source)), + : Optional.of(addressResolver.resolveRecipientAddress(source).toApiRecipientAddress()), sourceDevice, envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Recipient.java b/lib/src/main/java/org/asamk/signal/manager/api/Recipient.java new file mode 100644 index 00000000..1aea3c45 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/Recipient.java @@ -0,0 +1,153 @@ +package org.asamk.signal.manager.api; + +import org.asamk.signal.manager.storage.recipients.Contact; +import org.asamk.signal.manager.storage.recipients.Profile; +import org.asamk.signal.manager.storage.recipients.RecipientId; +import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential; +import org.signal.libsignal.zkgroup.profiles.ProfileKey; + +import java.util.Objects; + +public class Recipient { + + private final RecipientId recipientId; + + private final RecipientAddress address; + + private final Contact contact; + + private final ProfileKey profileKey; + + private final ExpiringProfileKeyCredential expiringProfileKeyCredential; + + private final Profile profile; + + public Recipient( + final RecipientId recipientId, + final RecipientAddress address, + final Contact contact, + final ProfileKey profileKey, + final ExpiringProfileKeyCredential expiringProfileKeyCredential, + final Profile profile + ) { + this.recipientId = recipientId; + this.address = address; + this.contact = contact; + this.profileKey = profileKey; + this.expiringProfileKeyCredential = expiringProfileKeyCredential; + this.profile = profile; + } + + private Recipient(final Builder builder) { + recipientId = builder.recipientId; + address = builder.address; + contact = builder.contact; + profileKey = builder.profileKey; + expiringProfileKeyCredential = builder.expiringProfileKeyCredential1; + profile = builder.profile; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static Builder newBuilder(final Recipient copy) { + Builder builder = new Builder(); + builder.recipientId = copy.getRecipientId(); + builder.address = copy.getAddress(); + builder.contact = copy.getContact(); + builder.profileKey = copy.getProfileKey(); + builder.expiringProfileKeyCredential1 = copy.getExpiringProfileKeyCredential(); + builder.profile = copy.getProfile(); + return builder; + } + + public RecipientId getRecipientId() { + return recipientId; + } + + public RecipientAddress getAddress() { + return address; + } + + public Contact getContact() { + return contact; + } + + public ProfileKey getProfileKey() { + return profileKey; + } + + public ExpiringProfileKeyCredential getExpiringProfileKeyCredential() { + return expiringProfileKeyCredential; + } + + public Profile getProfile() { + return profile; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final Recipient recipient = (Recipient) o; + return Objects.equals(recipientId, recipient.recipientId) + && Objects.equals(address, recipient.address) + && Objects.equals(contact, recipient.contact) + && Objects.equals(profileKey, recipient.profileKey) + && Objects.equals(expiringProfileKeyCredential, recipient.expiringProfileKeyCredential) + && Objects.equals(profile, recipient.profile); + } + + @Override + public int hashCode() { + return Objects.hash(recipientId, address, contact, profileKey, expiringProfileKeyCredential, profile); + } + + public static final class Builder { + + private RecipientId recipientId; + private RecipientAddress address; + private Contact contact; + private ProfileKey profileKey; + private ExpiringProfileKeyCredential expiringProfileKeyCredential1; + private Profile profile; + + private Builder() { + } + + public Builder withRecipientId(final RecipientId val) { + recipientId = val; + return this; + } + + public Builder withAddress(final RecipientAddress val) { + address = val; + return this; + } + + public Builder withContact(final Contact val) { + contact = val; + return this; + } + + public Builder withProfileKey(final ProfileKey val) { + profileKey = val; + return this; + } + + public Builder withExpiringProfileKeyCredential(final ExpiringProfileKeyCredential val) { + expiringProfileKeyCredential1 = val; + return this; + } + + public Builder withProfile(final Profile val) { + profile = val; + return this; + } + + public Recipient build() { + return new Recipient(this); + } + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/api/RecipientAddress.java b/lib/src/main/java/org/asamk/signal/manager/api/RecipientAddress.java new file mode 100644 index 00000000..f477b9e9 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/RecipientAddress.java @@ -0,0 +1,71 @@ +package org.asamk.signal.manager.api; + +import org.whispersystems.signalservice.api.push.ServiceId; +import org.whispersystems.signalservice.api.push.SignalServiceAddress; + +import java.util.Optional; +import java.util.UUID; + +public record RecipientAddress(Optional uuid, Optional number) { + + public static final UUID UNKNOWN_UUID = ServiceId.UNKNOWN.uuid(); + + /** + * Construct a RecipientAddress. + * + * @param uuid The UUID of the user, if available. + * @param number The phone number of the user, if available. + */ + public RecipientAddress { + uuid = uuid.isPresent() && uuid.get().equals(UNKNOWN_UUID) ? Optional.empty() : uuid; + if (uuid.isEmpty() && number.isEmpty()) { + throw new AssertionError("Must have either a UUID or E164 number!"); + } + } + + public RecipientAddress(UUID uuid, String e164) { + this(Optional.ofNullable(uuid), Optional.ofNullable(e164)); + } + + public RecipientAddress(SignalServiceAddress address) { + this(Optional.of(address.getServiceId().uuid()), address.getNumber()); + } + + public RecipientAddress(UUID uuid) { + this(Optional.of(uuid), Optional.empty()); + } + + public ServiceId getServiceId() { + return ServiceId.from(uuid.orElse(UNKNOWN_UUID)); + } + + public String getIdentifier() { + if (uuid.isPresent()) { + return uuid.get().toString(); + } else if (number.isPresent()) { + return number.get(); + } else { + throw new AssertionError("Given the checks in the constructor, this should not be possible."); + } + } + + public String getLegacyIdentifier() { + if (number.isPresent()) { + return number.get(); + } else if (uuid.isPresent()) { + return uuid.get().toString(); + } else { + throw new AssertionError("Given the checks in the constructor, this should not be possible."); + } + } + + public boolean matches(RecipientAddress other) { + return (uuid.isPresent() && other.uuid.isPresent() && uuid.get().equals(other.uuid.get())) || ( + number.isPresent() && other.number.isPresent() && number.get().equals(other.number.get()) + ); + } + + public SignalServiceAddress toSignalServiceAddress() { + return new SignalServiceAddress(getServiceId(), number); + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java b/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java index 242d0f47..70a60d47 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/RecipientIdentifier.java @@ -1,7 +1,6 @@ package org.asamk.signal.manager.api; import org.asamk.signal.manager.groups.GroupId; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; diff --git a/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java b/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java index be5bf801..1507390b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/SendMessageResult.java @@ -1,7 +1,6 @@ package org.asamk.signal.manager.api; import org.asamk.signal.manager.helper.RecipientAddressResolver; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientResolver; import org.signal.libsignal.protocol.IdentityKey; @@ -43,7 +42,7 @@ public record SendMessageResult( RecipientAddressResolver addressResolver ) { return new SendMessageResult(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient( - sendMessageResult.getAddress())), + sendMessageResult.getAddress())).toApiRecipientAddress(), sendMessageResult.isSuccess(), sendMessageResult.isNetworkFailure(), sendMessageResult.isUnregisteredFailure(), diff --git a/lib/src/main/java/org/asamk/signal/manager/api/UnregisteredRecipientException.java b/lib/src/main/java/org/asamk/signal/manager/api/UnregisteredRecipientException.java index d37c7dc7..ef7d5b74 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/UnregisteredRecipientException.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/UnregisteredRecipientException.java @@ -1,7 +1,5 @@ package org.asamk.signal.manager.api; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; - public class UnregisteredRecipientException extends Exception { private final RecipientAddress sender; diff --git a/lib/src/main/java/org/asamk/signal/manager/api/UntrustedIdentityException.java b/lib/src/main/java/org/asamk/signal/manager/api/UntrustedIdentityException.java index 7328cf64..e91903a5 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/UntrustedIdentityException.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/UntrustedIdentityException.java @@ -1,7 +1,5 @@ package org.asamk.signal.manager.api; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; - public class UntrustedIdentityException extends Exception { private final RecipientAddress sender; diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IdentityHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/IdentityHelper.java index 0adeaf60..0efe90a4 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IdentityHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IdentityHelper.java @@ -85,7 +85,7 @@ public class IdentityHelper { account.getAciIdentityKeyPair().getPublicKey(), address.getServiceId().equals(serviceId) ? address - : new RecipientAddress(serviceId.uuid(), address.number().orElse(null)), + : new RecipientAddress(serviceId, address.number().orElse(null)), theirIdentityKey); } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index 569168de..a9c8fdae 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -97,7 +97,8 @@ public final class IncomingMessageHandler { } catch (ProtocolUntrustedIdentityException e) { final var recipientId = account.getRecipientResolver().resolveRecipient(e.getSender()); final var exception = new UntrustedIdentityException(account.getRecipientAddressResolver() - .resolveRecipientAddress(recipientId), e.getSenderDevice()); + .resolveRecipientAddress(recipientId) + .toApiRecipientAddress(), e.getSenderDevice()); return new Pair<>(List.of(), exception); } catch (Exception e) { return new Pair<>(List.of(), e); @@ -129,7 +130,8 @@ public final class IncomingMessageHandler { final var recipientId = account.getRecipientResolver().resolveRecipient(e.getSender()); actions.add(new RetrieveProfileAction(recipientId)); exception = new UntrustedIdentityException(account.getRecipientAddressResolver() - .resolveRecipientAddress(recipientId), e.getSenderDevice()); + .resolveRecipientAddress(recipientId) + .toApiRecipientAddress(), e.getSenderDevice()); } catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolNoSessionException | ProtocolInvalidMessageException e) { logger.debug("Failed to decrypt incoming message", e); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java index d3c1ef56..09ca1a40 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java @@ -212,7 +212,7 @@ public class ReceiveHelper { if (exception instanceof UntrustedIdentityException) { logger.debug("Keeping message with untrusted identity in message cache"); final var address = ((UntrustedIdentityException) exception).getSender(); - final var recipientId = account.getRecipientResolver().resolveRecipient(address); + final var recipientId = account.getRecipientResolver().resolveRecipient(address.getServiceId()); if (!envelope.hasSourceUuid()) { try { cachedMessage[0] = account.getMessageCache().replaceSender(cachedMessage[0], recipientId); @@ -260,7 +260,7 @@ public class ReceiveHelper { } if (!envelope.hasSourceUuid()) { final var identifier = ((UntrustedIdentityException) exception).getSender(); - final var recipientId = account.getRecipientResolver().resolveRecipient(identifier); + final var recipientId = account.getRecipientResolver().resolveRecipient(identifier.getServiceId()); try { account.getMessageCache().replaceSender(cachedMessage, recipientId); } catch (IOException ioException) { diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java index c8e5859a..d87b2c53 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java @@ -6,7 +6,6 @@ import org.asamk.signal.manager.api.UnregisteredRecipientException; import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.storage.SignalAccount; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientId; import org.signal.libsignal.protocol.InvalidKeyException; import org.slf4j.Logger; @@ -44,7 +43,7 @@ public class RecipientHelper { public SignalServiceAddress resolveSignalServiceAddress(RecipientId recipientId) { final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId); - if (address.number().isEmpty() || address.uuid().isPresent()) { + if (address.number().isEmpty() || address.serviceId().isPresent()) { return address.toSignalServiceAddress(); } @@ -127,11 +126,11 @@ public class RecipientHelper { try { aciMap = getRegisteredUsers(Set.of(number)); } catch (NumberFormatException e) { - throw new UnregisteredRecipientException(new RecipientAddress(null, number)); + throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } final var uuid = aciMap.get(number); if (uuid == null) { - throw new UnregisteredRecipientException(new RecipientAddress(null, number)); + throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } return uuid; } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java index 15684da5..257cea83 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/StorageHelper.java @@ -101,8 +101,7 @@ public class StorageHelper { } final var contactRecord = record.getContact().get(); - final var address = new RecipientAddress(contactRecord.getServiceId().uuid(), - contactRecord.getNumber().orElse(null)); + final var address = new RecipientAddress(contactRecord.getServiceId(), contactRecord.getNumber().orElse(null)); final var recipientId = account.getRecipientResolver().resolveRecipient(address); final var contact = account.getContactStore().getContact(recipientId); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 335aece5..6c179b6d 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -417,8 +417,8 @@ public class SignalAccount implements Closeable { getRecipientStore().deleteRecipientData(recipientId); getMessageCache().deleteMessages(recipientId); final var recipientAddress = getRecipientStore().resolveRecipientAddress(recipientId); - if (recipientAddress.uuid().isPresent()) { - final var serviceId = ServiceId.from(recipientAddress.uuid().get()); + if (recipientAddress.serviceId().isPresent()) { + final var serviceId = recipientAddress.serviceId().get(); getAciSessionStore().deleteAllSessions(serviceId); getPniSessionStore().deleteAllSessions(serviceId); getIdentityKeyStore().deleteIdentity(serviceId); @@ -791,7 +791,7 @@ public class SignalAccount implements Closeable { if (legacySignalProtocolStore != null && legacySignalProtocolStore.getLegacyIdentityKeyStore() != null) { logger.debug("Migrating legacy identity session store."); for (var identity : legacySignalProtocolStore.getLegacyIdentityKeyStore().getIdentities()) { - if (identity.getAddress().uuid().isEmpty()) { + if (identity.getAddress().serviceId().isEmpty()) { continue; } final var serviceId = identity.getAddress().getServiceId(); @@ -1324,7 +1324,7 @@ public class SignalAccount implements Closeable { } public RecipientAddress getSelfRecipientAddress() { - return new RecipientAddress(aci == null ? null : aci.uuid(), number); + return new RecipientAddress(aci, pni, number); } public RecipientId getSelfRecipientId() { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/Utils.java b/lib/src/main/java/org/asamk/signal/manager/storage/Utils.java index 10a45051..1c75d9cc 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/Utils.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/Utils.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceIdType; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -57,7 +58,7 @@ public class Utils { public static RecipientAddress getRecipientAddressFromIdentifier(final String identifier) { if (UuidUtil.isUuid(identifier)) { - return new RecipientAddress(UuidUtil.parseOrThrow(identifier)); + return new RecipientAddress(ServiceId.parseOrThrow(identifier)); } else { return new RecipientAddress(Optional.empty(), Optional.of(identifier)); } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/contacts/LegacyContactInfo.java b/lib/src/main/java/org/asamk/signal/manager/storage/contacts/LegacyContactInfo.java index 6c6bd7ea..0d297e7f 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/contacts/LegacyContactInfo.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/contacts/LegacyContactInfo.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import org.asamk.signal.manager.storage.recipients.RecipientAddress; +import org.whispersystems.signalservice.api.push.ServiceId; import java.util.UUID; @@ -43,6 +44,6 @@ public class LegacyContactInfo { @JsonIgnore public RecipientAddress getAddress() { - return new RecipientAddress(uuid, number); + return new RecipientAddress(uuid == null ? null : ServiceId.from(uuid), number); } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/LegacyGroupStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/LegacyGroupStore.java index 0b5a7d4b..ad42984f 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/LegacyGroupStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/LegacyGroupStore.java @@ -18,7 +18,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.DistributionId; -import org.whispersystems.signalservice.api.util.UuidUtil; +import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.internal.util.Hex; import java.io.File; @@ -45,7 +45,7 @@ public class LegacyGroupStore { if (g instanceof Storage.GroupV1 g1) { final var members = g1.members.stream().map(m -> { if (m.recipientId == null) { - return recipientResolver.resolveRecipient(new RecipientAddress(UuidUtil.parseOrNull(m.uuid), + return recipientResolver.resolveRecipient(new RecipientAddress(ServiceId.parseOrNull(m.uuid), m.number)); } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/profiles/LegacyProfileStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/profiles/LegacyProfileStore.java index 99e2980e..cf100257 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/profiles/LegacyProfileStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/profiles/LegacyProfileStore.java @@ -11,7 +11,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; -import org.whispersystems.signalservice.api.util.UuidUtil; +import org.whispersystems.signalservice.api.push.ServiceId; import java.io.IOException; import java.util.ArrayList; @@ -43,8 +43,8 @@ public class LegacyProfileStore { if (node.isArray()) { for (var entry : node) { var name = entry.hasNonNull("name") ? entry.get("name").asText() : null; - var uuid = entry.hasNonNull("uuid") ? UuidUtil.parseOrNull(entry.get("uuid").asText()) : null; - final var address = new RecipientAddress(uuid, name); + var serviceId = entry.hasNonNull("uuid") ? ServiceId.parseOrNull(entry.get("uuid").asText()) : null; + final var address = new RecipientAddress(serviceId, name); ProfileKey profileKey = null; try { profileKey = new ProfileKey(Base64.getDecoder().decode(entry.get("profileKey").asText())); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonIdentityKeyStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonIdentityKeyStore.java index de5062e4..4d94b455 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonIdentityKeyStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonIdentityKeyStore.java @@ -13,6 +13,7 @@ import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.InvalidKeyException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.util.UuidUtil; import java.io.IOException; @@ -100,7 +101,7 @@ public class LegacyJsonIdentityKeyStore { : null; final var address = uuid == null ? Utils.getRecipientAddressFromIdentifier(trustedKeyName) - : new RecipientAddress(uuid, trustedKeyName); + : new RecipientAddress(ServiceId.from(uuid), trustedKeyName); try { var id = new IdentityKey(Base64.getDecoder().decode(trustedKey.get("identityKey").asText()), 0); var trustLevel = trustedKey.hasNonNull("trustLevel") ? TrustLevel.fromInt(trustedKey.get( diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonSessionStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonSessionStore.java index 9ee0cf87..df8f5cda 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonSessionStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/protocol/LegacyJsonSessionStore.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.JsonNode; import org.asamk.signal.manager.storage.Utils; import org.asamk.signal.manager.storage.recipients.RecipientAddress; +import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.util.UuidUtil; import java.io.IOException; @@ -47,7 +48,7 @@ public class LegacyJsonSessionStore { var uuid = session.hasNonNull("uuid") ? UuidUtil.parseOrNull(session.get("uuid").asText()) : null; final var address = uuid == null ? Utils.getRecipientAddressFromIdentifier(sessionName) - : new RecipientAddress(uuid, sessionName); + : new RecipientAddress(ServiceId.from(uuid), sessionName); final var deviceId = session.get("deviceId").asInt(); final var record = Base64.getDecoder().decode(session.get("record").asText()); var sessionInfo = new LegacySessionInfo(address, deviceId, record); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore.java index 2aeb349f..039e8471 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore.java @@ -7,7 +7,7 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.whispersystems.signalservice.api.util.UuidUtil; +import org.whispersystems.signalservice.api.push.ServiceId; import java.io.IOException; import java.util.ArrayList; @@ -36,8 +36,8 @@ public class LegacyRecipientStore { if (node.isArray()) { for (var recipient : node) { var recipientName = recipient.get("name").asText(); - var uuid = UuidUtil.parseOrThrow(recipient.get("uuid").asText()); - addresses.add(new RecipientAddress(uuid, recipientName)); + var serviceId = ServiceId.parseOrThrow(recipient.get("uuid").asText()); + addresses.add(new RecipientAddress(serviceId, recipientName)); } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore2.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore2.java index 0c05e0c0..57a60674 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore2.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/LegacyRecipientStore2.java @@ -6,7 +6,7 @@ import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.signalservice.api.util.UuidUtil; +import org.whispersystems.signalservice.api.push.ServiceId; import java.io.File; import java.io.FileInputStream; @@ -31,7 +31,7 @@ public class LegacyRecipientStore2 { final var recipients = storage.recipients.stream().map(r -> { final var recipientId = new RecipientId(r.id, recipientStore); - final var address = new RecipientAddress(Optional.ofNullable(r.uuid).map(UuidUtil::parseOrThrow), + final var address = new RecipientAddress(Optional.ofNullable(r.uuid).map(ServiceId::parseOrThrow), Optional.ofNullable(r.number)); Contact contact = null; diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java index c5f0ccbc..c3b18299 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java @@ -1,47 +1,61 @@ package org.asamk.signal.manager.storage.recipients; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.util.Optional; -import java.util.UUID; -public record RecipientAddress(Optional uuid, Optional number) { - - public static final UUID UNKNOWN_UUID = ServiceId.UNKNOWN.uuid(); +public record RecipientAddress(Optional serviceId, Optional pni, Optional number) { /** * Construct a RecipientAddress. * - * @param uuid The UUID of the user, if available. - * @param number The phone number of the user, if available. + * @param serviceId The ACI or PNI of the user, if available. + * @param number The phone number of the user, if available. */ public RecipientAddress { - uuid = uuid.isPresent() && uuid.get().equals(UNKNOWN_UUID) ? Optional.empty() : uuid; - if (uuid.isEmpty() && number.isEmpty()) { - throw new AssertionError("Must have either a UUID or E164 number!"); + if (serviceId.isPresent() && serviceId.get().equals(ServiceId.UNKNOWN)) { + serviceId = Optional.empty(); + } + if (pni.isPresent() && pni.get().equals(ServiceId.UNKNOWN)) { + pni = Optional.empty(); + } + if (serviceId.isEmpty() && pni.isPresent()) { + serviceId = Optional.of(pni.get()); + } + if (serviceId.isEmpty() && number.isEmpty()) { + throw new AssertionError("Must have either a ServiceId or E164 number!"); } } - public RecipientAddress(UUID uuid, String e164) { - this(Optional.ofNullable(uuid), Optional.ofNullable(e164)); + public RecipientAddress(Optional serviceId, Optional number) { + this(serviceId, Optional.empty(), number); + } + + public RecipientAddress(ServiceId serviceId, String e164) { + this(Optional.ofNullable(serviceId), Optional.empty(), Optional.ofNullable(e164)); + } + + public RecipientAddress(ServiceId serviceId, PNI pni, String e164) { + this(Optional.ofNullable(serviceId), Optional.ofNullable(pni), Optional.ofNullable(e164)); } public RecipientAddress(SignalServiceAddress address) { - this(Optional.of(address.getServiceId().uuid()), address.getNumber()); + this(Optional.of(address.getServiceId()), Optional.empty(), address.getNumber()); } - public RecipientAddress(UUID uuid) { - this(Optional.of(uuid), Optional.empty()); + public RecipientAddress(ServiceId serviceId) { + this(Optional.of(serviceId), Optional.empty()); } public ServiceId getServiceId() { - return ServiceId.from(uuid.orElse(UNKNOWN_UUID)); + return serviceId.orElse(ServiceId.UNKNOWN); } public String getIdentifier() { - if (uuid.isPresent()) { - return uuid.get().toString(); + if (serviceId.isPresent()) { + return serviceId.get().toString(); } else if (number.isPresent()) { return number.get(); } else { @@ -52,15 +66,25 @@ public record RecipientAddress(Optional uuid, Optional number) { public String getLegacyIdentifier() { if (number.isPresent()) { return number.get(); - } else if (uuid.isPresent()) { - return uuid.get().toString(); + } else if (serviceId.isPresent()) { + return serviceId.get().toString(); } else { throw new AssertionError("Given the checks in the constructor, this should not be possible."); } } public boolean matches(RecipientAddress other) { - return (uuid.isPresent() && other.uuid.isPresent() && uuid.get().equals(other.uuid.get())) || ( + return (serviceId.isPresent() && other.serviceId.isPresent() && serviceId.get().equals(other.serviceId.get())) + || ( + pni.isPresent() && other.serviceId.isPresent() && pni.get().equals(other.serviceId.get()) + ) + || ( + serviceId.isPresent() && other.pni.isPresent() && serviceId.get().equals(other.pni.get()) + ) + || ( + pni.isPresent() && other.pni.isPresent() && pni.get().equals(other.pni.get()) + ) + || ( number.isPresent() && other.number.isPresent() && number.get().equals(other.number.get()) ); } @@ -68,4 +92,8 @@ public record RecipientAddress(Optional uuid, Optional number) { public SignalServiceAddress toSignalServiceAddress() { return new SignalServiceAddress(getServiceId(), number); } + + public org.asamk.signal.manager.api.RecipientAddress toApiRecipientAddress() { + return new org.asamk.signal.manager.api.RecipientAddress(serviceId().map(ServiceId::uuid), number()); + } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java index f20e4bbb..85ece822 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java @@ -19,6 +19,6 @@ public interface RecipientResolver { } default RecipientId resolveRecipient(ServiceId serviceId) { - return resolveRecipient(new RecipientAddress(serviceId.uuid())); + return resolveRecipient(new RecipientAddress(serviceId)); } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index 1a428467..7b57f2c9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -28,7 +28,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.UUID; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -163,13 +162,13 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } catch (SQLException e) { throw new RuntimeException("Failed read from recipient store", e); } - if (byNumber.isEmpty() || byNumber.get().address().uuid().isEmpty()) { + if (byNumber.isEmpty() || byNumber.get().address().serviceId().isEmpty()) { final var aci = aciSupplier.get(); if (aci == null) { - throw new UnregisteredRecipientException(new RecipientAddress(null, number)); + throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } - return resolveRecipient(new RecipientAddress(aci.uuid(), number), false, false); + return resolveRecipient(new RecipientAddress(aci, number), false, false); } return byNumber.get().id(); } @@ -399,7 +398,12 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re for (final var recipient : recipients.values()) { statement.setLong(1, recipient.getRecipientId().id()); statement.setString(2, recipient.getAddress().number().orElse(null)); - statement.setBytes(3, recipient.getAddress().uuid().map(UuidUtil::toByteArray).orElse(null)); + statement.setBytes(3, + recipient.getAddress() + .serviceId() + .map(ServiceId::uuid) + .map(UuidUtil::toByteArray) + .orElse(null)); statement.executeUpdate(); } } @@ -576,22 +580,22 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re final var byNumber = address.number().isEmpty() ? Optional.empty() : findByNumber(connection, address.number().get()); - final var byUuid = address.uuid().isEmpty() + final var byUuid = address.serviceId().isEmpty() ? Optional.empty() - : findByUuid(connection, address.uuid().get()); + : findByServiceId(connection, address.serviceId().get()); if (byNumber.isEmpty() && byUuid.isEmpty()) { logger.debug("Got new recipient, both uuid and number are unknown"); - if (isHighTrust || address.uuid().isEmpty() || address.number().isEmpty()) { + if (isHighTrust || address.serviceId().isEmpty() || address.number().isEmpty()) { return new Pair<>(addNewRecipient(connection, address), Optional.empty()); } - return new Pair<>(addNewRecipient(connection, new RecipientAddress(address.uuid().get())), + return new Pair<>(addNewRecipient(connection, new RecipientAddress(address.serviceId().get())), Optional.empty()); } - if (!isHighTrust || address.uuid().isEmpty() || address.number().isEmpty() || byNumber.equals(byUuid)) { + if (!isHighTrust || address.serviceId().isEmpty() || address.number().isEmpty() || byNumber.equals(byUuid)) { return new Pair<>(byUuid.or(() -> byNumber).map(RecipientWithAddress::id).get(), Optional.empty()); } @@ -604,14 +608,14 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re final var byNumberRecipient = byNumber.get(); if (byUuid.isEmpty()) { - if (byNumberRecipient.address().uuid().isPresent()) { + if (byNumberRecipient.address().serviceId().isPresent()) { logger.debug( "Got recipient {} existing with number, but different uuid, so stripping its number and adding new recipient", byNumberRecipient.id()); updateRecipientAddress(connection, byNumberRecipient.id(), - new RecipientAddress(byNumberRecipient.address().uuid().get())); + new RecipientAddress(byNumberRecipient.address().serviceId().get())); return new Pair<>(addNewRecipient(connection, address), Optional.empty()); } @@ -623,7 +627,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re final var byUuidRecipient = byUuid.get(); - if (byNumberRecipient.address().uuid().isPresent()) { + if (byNumberRecipient.address().serviceId().isPresent()) { logger.debug( "Got separate recipients for high trust number {} and uuid {}, recipient for number has different uuid, so stripping its number", byNumberRecipient.id(), @@ -631,7 +635,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re updateRecipientAddress(connection, byNumberRecipient.id(), - new RecipientAddress(byNumberRecipient.address().uuid().get())); + new RecipientAddress(byNumberRecipient.address().serviceId().get())); updateRecipientAddress(connection, byUuidRecipient.id(), address); return new Pair<>(byUuidRecipient.id(), Optional.empty()); } @@ -658,7 +662,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re ).formatted(TABLE_RECIPIENT); try (final var statement = connection.prepareStatement(sql)) { statement.setString(1, address.number().orElse(null)); - statement.setBytes(2, address.uuid().map(UuidUtil::toByteArray).orElse(null)); + statement.setBytes(2, address.serviceId().map(ServiceId::uuid).map(UuidUtil::toByteArray).orElse(null)); statement.executeUpdate(); final var generatedKeys = statement.getGeneratedKeys(); if (generatedKeys.next()) { @@ -697,7 +701,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re ).formatted(TABLE_RECIPIENT); try (final var statement = connection.prepareStatement(sql)) { statement.setString(1, address.number().orElse(null)); - statement.setBytes(2, address.uuid().map(UuidUtil::toByteArray).orElse(null)); + statement.setBytes(2, address.serviceId().map(ServiceId::uuid).map(UuidUtil::toByteArray).orElse(null)); statement.setLong(3, recipientId.id()); statement.executeUpdate(); } @@ -761,8 +765,8 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } } - private Optional findByUuid( - final Connection connection, final UUID uuid + private Optional findByServiceId( + final Connection connection, final ServiceId serviceId ) throws SQLException { final var sql = """ SELECT r._id, r.number, r.uuid @@ -770,7 +774,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re WHERE r.uuid = ? """.formatted(TABLE_RECIPIENT); try (final var statement = connection.prepareStatement(sql)) { - statement.setBytes(1, UuidUtil.toByteArray(uuid)); + statement.setBytes(1, UuidUtil.toByteArray(serviceId.uuid())); return Utils.executeQueryForOptional(statement, this::getRecipientWithAddressFromResultSet); } } @@ -835,9 +839,9 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } private RecipientAddress getRecipientAddressFromResultSet(ResultSet resultSet) throws SQLException { - final var uuid = Optional.ofNullable(resultSet.getBytes("uuid")).map(UuidUtil::parseOrNull); + final var serviceId = Optional.ofNullable(resultSet.getBytes("uuid")).map(ServiceId::parseOrNull); final var number = Optional.ofNullable(resultSet.getString("number")); - return new RecipientAddress(uuid, number); + return new RecipientAddress(serviceId, Optional.empty(), number); } private RecipientId getRecipientIdFromResultSet(ResultSet resultSet) throws SQLException { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeyRecordStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeyRecordStore.java index f5a1fc53..d1794156 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeyRecordStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeyRecordStore.java @@ -8,7 +8,6 @@ import org.signal.libsignal.protocol.InvalidMessageException; import org.signal.libsignal.protocol.groups.state.SenderKeyRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.signalservice.api.push.ServiceId; import java.io.File; import java.io.FileInputStream; @@ -38,13 +37,11 @@ public class LegacySenderKeyRecordStore { final var senderKeys = parseFileNames(files, resolver).stream().map(key -> { final var record = loadSenderKeyLocked(key, senderKeysPath); - final var uuid = addressResolver.resolveRecipientAddress(key.recipientId).uuid(); - if (record == null || uuid.isEmpty()) { + final var serviceId = addressResolver.resolveRecipientAddress(key.recipientId).serviceId(); + if (record == null || serviceId.isEmpty()) { return null; } - return new Pair<>(new SenderKeyRecordStore.Key(ServiceId.from(uuid.get()), - key.deviceId, - key.distributionId), record); + return new Pair<>(new SenderKeyRecordStore.Key(serviceId.get(), key.deviceId, key.distributionId), record); }).filter(Objects::nonNull).toList(); senderKeyStore.addLegacySenderKeys(senderKeys); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeySharedStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeySharedStore.java index dfbc2ff9..cfc36539 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeySharedStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/senderKeys/LegacySenderKeySharedStore.java @@ -7,7 +7,6 @@ import org.asamk.signal.manager.storage.senderKeys.SenderKeySharedStore.SenderKe import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.DistributionId; -import org.whispersystems.signalservice.api.push.ServiceId; import java.io.File; import java.io.FileInputStream; @@ -37,11 +36,11 @@ public class LegacySenderKeySharedStore { if (recipientId == null) { continue; } - final var uuid = addressResolver.resolveRecipientAddress(recipientId).uuid(); - if (uuid.isEmpty()) { + final var serviceId = addressResolver.resolveRecipientAddress(recipientId).serviceId(); + if (serviceId.isEmpty()) { continue; } - final var entry = new SenderKeySharedEntry(ServiceId.from(uuid.get()), senderKey.deviceId); + final var entry = new SenderKeySharedEntry(serviceId.get(), senderKey.deviceId); final var distributionId = DistributionId.from(senderKey.distributionId); var entries = sharedSenderKeys.get(distributionId); if (entries == null) { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/sessions/LegacySessionStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/sessions/LegacySessionStore.java index 1682b714..71cd9231 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/sessions/LegacySessionStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/sessions/LegacySessionStore.java @@ -8,7 +8,6 @@ import org.asamk.signal.manager.util.IOUtils; import org.signal.libsignal.protocol.state.SessionRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.signalservice.api.push.ServiceId; import java.io.File; import java.io.FileInputStream; @@ -34,11 +33,11 @@ public class LegacySessionStore { final var keys = getKeysLocked(sessionsPath, resolver); final var sessions = keys.stream().map(key -> { final var record = loadSessionLocked(key, sessionsPath); - final var uuid = addressResolver.resolveRecipientAddress(key.recipientId).uuid(); - if (record == null || uuid.isEmpty()) { + final var serviceId = addressResolver.resolveRecipientAddress(key.recipientId).serviceId(); + if (record == null || serviceId.isEmpty()) { return null; } - return new Pair<>(new SessionStore.Key(ServiceId.from(uuid.get()), key.deviceId()), record); + return new Pair<>(new SessionStore.Key(serviceId.get(), key.deviceId()), record); }).filter(Objects::nonNull).toList(); sessionStore.addLegacySessions(sessions); deleteAllSessions(sessionsPath); diff --git a/lib/src/main/java/org/asamk/signal/manager/util/Utils.java b/lib/src/main/java/org/asamk/signal/manager/util/Utils.java index 97adb69d..c50988a1 100644 --- a/lib/src/main/java/org/asamk/signal/manager/util/Utils.java +++ b/lib/src/main/java/org/asamk/signal/manager/util/Utils.java @@ -87,7 +87,7 @@ public class Utils { version = 1; ownId = ownAddress.number().get().getBytes(); theirId = theirAddress.number().get().getBytes(); - } else if (isUuidCapable && theirAddress.uuid().isPresent()) { + } else if (isUuidCapable && theirAddress.serviceId().isPresent()) { // Version 2: UUID user version = 2; ownId = ownAddress.getServiceId().toByteArray(); diff --git a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java index 10f73706..f46a76f2 100644 --- a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java @@ -2,10 +2,10 @@ package org.asamk.signal; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.UntrustedIdentityException; import org.asamk.signal.manager.groups.GroupId; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.output.PlainTextWriter; import org.asamk.signal.util.DateUtils; import org.asamk.signal.util.Hex; diff --git a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java index c08571f7..91272da5 100644 --- a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java @@ -7,7 +7,7 @@ import net.sourceforge.argparse4j.inf.Subparser; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.Group; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.output.JsonWriter; import org.asamk.signal.output.OutputWriter; import org.asamk.signal.output.PlainTextWriter; diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index b78f8022..bbfa4f1c 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -15,6 +15,8 @@ import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.ReceiveConfig; +import org.asamk.signal.manager.api.Recipient; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; import org.asamk.signal.manager.api.SendMessageResults; @@ -34,8 +36,6 @@ import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.storage.recipients.Contact; import org.asamk.signal.manager.storage.recipients.Profile; -import org.asamk.signal.manager.storage.recipients.Recipient; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.freedesktop.dbus.DBusMap; import org.freedesktop.dbus.DBusPath; import org.freedesktop.dbus.connections.impl.DBusConnection; diff --git a/src/main/java/org/asamk/signal/dbus/DbusReceiveMessageHandler.java b/src/main/java/org/asamk/signal/dbus/DbusReceiveMessageHandler.java index dcea2bf1..66c1fd65 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/dbus/DbusReceiveMessageHandler.java @@ -3,8 +3,8 @@ package org.asamk.signal.dbus; import org.asamk.Signal; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.groups.GroupId; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.freedesktop.dbus.connections.impl.DBusConnection; import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.types.Variant; diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 4b5b3ba8..92e92157 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -11,6 +11,7 @@ import org.asamk.signal.manager.api.InvalidStickerException; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.NotPrimaryDeviceException; import org.asamk.signal.manager.api.PendingAdminApprovalException; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendMessageResult; import org.asamk.signal.manager.api.SendMessageResults; @@ -28,7 +29,6 @@ import org.asamk.signal.manager.groups.GroupPermission; import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.util.SendMessageResultUtils; import org.freedesktop.dbus.DBusPath; import org.freedesktop.dbus.connections.impl.DBusConnection; diff --git a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java index adc7a251..c32de61a 100644 --- a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java +++ b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java @@ -4,9 +4,9 @@ import com.fasterxml.jackson.annotation.JsonInclude; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.UntrustedIdentityException; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import java.util.UUID; diff --git a/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java b/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java index 1bd09e83..e25385b6 100644 --- a/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java +++ b/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java @@ -1,6 +1,6 @@ package org.asamk.signal.json; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; +import org.asamk.signal.manager.api.RecipientAddress; import java.util.UUID; diff --git a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java index a251d007..802c07d5 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java @@ -3,8 +3,8 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; import org.asamk.signal.manager.api.MessageEnvelope; +import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.manager.groups.GroupId; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import java.util.List; From f2b334b57adef638f5156e39b9cb7bb9542e6458 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 8 Oct 2022 14:06:36 +0200 Subject: [PATCH 022/713] Refactor check for registered users --- .../org/asamk/signal/manager/ManagerImpl.java | 9 +-- .../manager/helper/RecipientHelper.java | 68 ++++++++++++------- .../signal/manager/storage/SignalAccount.java | 7 ++ .../storage/recipients/RecipientStore.java | 20 ++++-- .../recipients/RecipientTrustedResolver.java | 6 ++ 5 files changed, 77 insertions(+), 33 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index fc38c92a..3e463edf 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -217,13 +217,14 @@ class ManagerImpl implements Manager { return numbers.stream().collect(Collectors.toMap(n -> n, n -> { final var number = canonicalizedNumbers.get(n); - final var aci = registeredUsers.get(number); - final var profile = aci == null + final var user = registeredUsers.get(number); + final var serviceId = user == null ? null : user.getServiceId(); + final var profile = serviceId == null ? null : context.getProfileHelper() - .getRecipientProfile(account.getRecipientResolver().resolveRecipient(aci)); + .getRecipientProfile(account.getRecipientResolver().resolveRecipient(serviceId)); return new UserStatus(number.isEmpty() ? null : number, - aci == null ? null : aci.uuid(), + serviceId == null ? null : serviceId.uuid(), profile != null && profile.getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.UNRESTRICTED); })); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java index d87b2c53..3a82cf8a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java @@ -11,6 +11,7 @@ import org.signal.libsignal.protocol.InvalidKeyException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.services.CdsiV2Service; @@ -50,9 +51,9 @@ public class RecipientHelper { // Address in recipient store doesn't have a uuid, this shouldn't happen // Try to retrieve the uuid from the server final var number = address.number().get(); - final ACI aci; + final ServiceId serviceId; try { - aci = getRegisteredUser(number); + serviceId = getRegisteredUser(number); } catch (UnregisteredRecipientException e) { logger.warn("Failed to get uuid for e164 number: {}", number); // Return SignalServiceAddress with unknown UUID @@ -63,7 +64,7 @@ public class RecipientHelper { return address.toSignalServiceAddress(); } return account.getRecipientAddressResolver() - .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(aci)) + .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(serviceId)) .toSignalServiceAddress(); } @@ -101,12 +102,13 @@ public class RecipientHelper { return recipientId; } final var number = address.getNumber().get(); - final var uuid = getRegisteredUser(number); - return account.getRecipientTrustedResolver().resolveRecipientTrusted(new SignalServiceAddress(uuid, number)); + final var serviceId = getRegisteredUser(number); + return account.getRecipientTrustedResolver() + .resolveRecipientTrusted(new SignalServiceAddress(serviceId, number)); } - public Map getRegisteredUsers(final Set numbers) throws IOException { - Map registeredUsers; + public Map getRegisteredUsers(final Set numbers) throws IOException { + Map registeredUsers; try { registeredUsers = getRegisteredUsersV2(numbers, true); } catch (IOException e) { @@ -115,30 +117,30 @@ public class RecipientHelper { } // Store numbers as recipients, so we have the number/uuid association - registeredUsers.forEach((number, aci) -> account.getRecipientTrustedResolver() - .resolveRecipientTrusted(new SignalServiceAddress(aci, number))); + registeredUsers.forEach((number, u) -> account.getRecipientTrustedResolver() + .resolveRecipientTrusted(u.aci, u.pni, Optional.of(number))); return registeredUsers; } - private ACI getRegisteredUser(final String number) throws IOException, UnregisteredRecipientException { - final Map aciMap; + private ServiceId getRegisteredUser(final String number) throws IOException, UnregisteredRecipientException { + final Map aciMap; try { aciMap = getRegisteredUsers(Set.of(number)); } catch (NumberFormatException e) { throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } - final var uuid = aciMap.get(number); - if (uuid == null) { + final var user = aciMap.get(number); + if (user == null) { throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } - return uuid; + return user.getServiceId(); } - private Map getRegisteredUsersV1(final Set numbers) throws IOException { - final Map registeredUsers; + private Map getRegisteredUsersV1(final Set numbers) throws IOException { + final Map response; try { - registeredUsers = dependencies.getAccountManager() + response = dependencies.getAccountManager() .getRegisteredUsers(ServiceConfig.getIasKeyStore(), numbers, serviceEnvironmentConfig.getCdsMrenclave()); @@ -146,10 +148,15 @@ public class RecipientHelper { UnauthenticatedResponseException | InvalidKeyException | NumberFormatException e) { throw new IOException(e); } + final var registeredUsers = new HashMap(); + response.forEach((key, value) -> registeredUsers.put(key, + new RegisteredUser(Optional.of(value), Optional.empty()))); return registeredUsers; } - private Map getRegisteredUsersV2(final Set numbers, boolean useCompat) throws IOException { + private Map getRegisteredUsersV2( + final Set numbers, boolean useCompat + ) throws IOException { // Only partial refresh is implemented here final CdsiV2Service.Response response; try { @@ -168,16 +175,29 @@ public class RecipientHelper { } logger.debug("CDSI request successful, quota used by this request: {}", response.getQuotaUsedDebugOnly()); - final var registeredUsers = new HashMap(); - response.getResults().forEach((key, value) -> { - if (value.getAci().isPresent()) { - registeredUsers.put(key, value.getAci().get()); - } - }); + final var registeredUsers = new HashMap(); + response.getResults() + .forEach((key, value) -> registeredUsers.put(key, + new RegisteredUser(value.getAci(), Optional.of(value.getPni())))); return registeredUsers; } private ACI getRegisteredUserByUsername(String username) throws IOException { return dependencies.getAccountManager().getAciByUsername(username); } + + public record RegisteredUser(Optional aci, Optional pni) { + + public RegisteredUser { + aci = aci.isPresent() && aci.get().equals(ServiceId.UNKNOWN) ? Optional.empty() : aci; + pni = pni.isPresent() && pni.get().equals(ServiceId.UNKNOWN) ? Optional.empty() : pni; + if (aci.isEmpty() && pni.isEmpty()) { + throw new AssertionError("Must have either a ACI or PNI!"); + } + } + + public ServiceId getServiceId() { + return aci.map(a -> (ServiceId) a).or(this::pni).orElse(null); + } + } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 6c179b6d..547607b3 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -1200,6 +1200,13 @@ public class SignalAccount implements Closeable { public RecipientId resolveRecipientTrusted(final SignalServiceAddress address) { return getRecipientStore().resolveRecipientTrusted(address); } + + @Override + public RecipientId resolveRecipientTrusted( + final Optional aci, final Optional pni, final Optional number + ) { + return getRecipientStore().resolveRecipientTrusted(aci, pni, number); + } }; } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index 7b57f2c9..247a71eb 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -12,6 +12,7 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -154,7 +155,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } public RecipientId resolveRecipient( - final String number, Supplier aciSupplier + final String number, Supplier serviceIdSupplier ) throws UnregisteredRecipientException { final Optional byNumber; try (final var connection = database.getConnection()) { @@ -163,12 +164,13 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re throw new RuntimeException("Failed read from recipient store", e); } if (byNumber.isEmpty() || byNumber.get().address().serviceId().isEmpty()) { - final var aci = aciSupplier.get(); - if (aci == null) { - throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); + final var serviceId = serviceIdSupplier.get(); + if (serviceId == null) { + throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, + number)); } - return resolveRecipient(new RecipientAddress(aci, number), false, false); + return resolveRecipient(new RecipientAddress(serviceId, number), false, false); } return byNumber.get().id(); } @@ -191,6 +193,14 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re return resolveRecipient(new RecipientAddress(address), true, false); } + @Override + public RecipientId resolveRecipientTrusted( + final Optional aci, final Optional pni, final Optional number + ) { + final var serviceId = aci.map(a -> (ServiceId) a).or(() -> pni); + return resolveRecipient(new RecipientAddress(serviceId, number), true, false); + } + @Override public void storeContact(RecipientId recipientId, final Contact contact) { try (final var connection = database.getConnection()) { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java index 0bc522e3..5020caf3 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java @@ -1,10 +1,16 @@ package org.asamk.signal.manager.storage.recipients; +import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import java.util.Optional; + public interface RecipientTrustedResolver { RecipientId resolveSelfRecipientTrusted(RecipientAddress address); RecipientId resolveRecipientTrusted(SignalServiceAddress address); + + RecipientId resolveRecipientTrusted(Optional aci, Optional pni, Optional number); } From 7ab013cee96600cf46836c562648f1cc4cdb6732 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 8 Oct 2022 16:21:29 +0200 Subject: [PATCH 023/713] Do recipient merge in one transaction --- .../signal/manager/storage/SignalAccount.java | 7 +++++-- .../manager/storage/groups/GroupStore.java | 20 +++++++++---------- .../storage/recipients/RecipientStore.java | 6 ++++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 547607b3..880089e7 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -88,6 +88,7 @@ import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.file.Files; import java.security.SecureRandom; +import java.sql.Connection; import java.sql.SQLException; import java.util.Base64; import java.util.Comparator; @@ -408,9 +409,11 @@ public class SignalAccount implements Closeable { } } - private void mergeRecipients(RecipientId recipientId, RecipientId toBeMergedRecipientId) { + private void mergeRecipients( + final Connection connection, RecipientId recipientId, RecipientId toBeMergedRecipientId + ) throws SQLException { getMessageCache().mergeRecipients(recipientId, toBeMergedRecipientId); - getGroupStore().mergeRecipients(recipientId, toBeMergedRecipientId); + getGroupStore().mergeRecipients(connection, recipientId, toBeMergedRecipientId); } public void removeRecipient(final RecipientId recipientId) { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java index 538ff294..ece7cde2 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java @@ -192,7 +192,9 @@ public class GroupStore { return Stream.concat(getGroupsV2().stream(), getGroupsV1().stream()).toList(); } - public void mergeRecipients(final RecipientId recipientId, final RecipientId toBeMergedRecipientId) { + public void mergeRecipients( + final Connection connection, final RecipientId recipientId, final RecipientId toBeMergedRecipientId + ) throws SQLException { final var sql = ( """ UPDATE OR REPLACE %s @@ -200,17 +202,13 @@ public class GroupStore { WHERE recipient_id = ? """ ).formatted(TABLE_GROUP_V1_MEMBER); - try (final var connection = database.getConnection()) { - try (final var statement = connection.prepareStatement(sql)) { - statement.setLong(1, recipientId.id()); - statement.setLong(2, toBeMergedRecipientId.id()); - final var updatedRows = statement.executeUpdate(); - if (updatedRows > 0) { - logger.info("Updated {} group members when merging recipients", updatedRows); - } + try (final var statement = connection.prepareStatement(sql)) { + statement.setLong(1, recipientId.id()); + statement.setLong(2, toBeMergedRecipientId.id()); + final var updatedRows = statement.executeUpdate(); + if (updatedRows > 0) { + logger.info("Updated {} group members when merging recipients", updatedRows); } - } catch (SQLException e) { - throw new RuntimeException("Failed update group store", e); } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index 247a71eb..f932d497 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -569,8 +569,8 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } if (pair.second().isPresent()) { - recipientMergeHandler.mergeRecipients(pair.first(), pair.second().get()); try (final var connection = database.getConnection()) { + recipientMergeHandler.mergeRecipients(connection, pair.first(), pair.second().get()); deleteRecipient(connection, pair.second().get()); } catch (SQLException e) { throw new RuntimeException("Failed update recipient store", e); @@ -931,7 +931,9 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re public interface RecipientMergeHandler { - void mergeRecipients(RecipientId recipientId, RecipientId toBeMergedRecipientId); + void mergeRecipients( + final Connection connection, RecipientId recipientId, RecipientId toBeMergedRecipientId + ) throws SQLException; } private record RecipientWithAddress(RecipientId id, RecipientAddress address) {} From 51fef480164562c0225285eea9cd3ede29d2505e Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 8 Oct 2022 17:41:42 +0200 Subject: [PATCH 024/713] Refactor resolve recipient --- .../signal/manager/storage/SignalAccount.java | 31 +--- .../storage/recipients/RecipientResolver.java | 38 ++++- .../storage/recipients/RecipientStore.java | 144 +++++++++++++++--- .../recipients/RecipientTrustedResolver.java | 27 ++++ 4 files changed, 181 insertions(+), 59 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 880089e7..85e5cadd 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -1179,38 +1179,11 @@ public class SignalAccount implements Closeable { } public RecipientResolver getRecipientResolver() { - return new RecipientResolver() { - @Override - public RecipientId resolveRecipient(final RecipientAddress address) { - return getRecipientStore().resolveRecipient(address); - } - - @Override - public RecipientId resolveRecipient(final long recipientId) { - return getRecipientStore().resolveRecipient(recipientId); - } - }; + return new RecipientResolver.RecipientResolverWrapper(this::getRecipientStore); } public RecipientTrustedResolver getRecipientTrustedResolver() { - return new RecipientTrustedResolver() { - @Override - public RecipientId resolveSelfRecipientTrusted(final RecipientAddress address) { - return getRecipientStore().resolveSelfRecipientTrusted(address); - } - - @Override - public RecipientId resolveRecipientTrusted(final SignalServiceAddress address) { - return getRecipientStore().resolveRecipientTrusted(address); - } - - @Override - public RecipientId resolveRecipientTrusted( - final Optional aci, final Optional pni, final Optional number - ) { - return getRecipientStore().resolveRecipientTrusted(aci, pni, number); - } - }; + return new RecipientTrustedResolver.RecipientTrustedResolverWrapper(this::getRecipientStore); } public RecipientAddressResolver getRecipientAddressResolver() { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java index 85ece822..00c532f2 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientResolver.java @@ -1,24 +1,50 @@ package org.asamk.signal.manager.storage.recipients; -import org.asamk.signal.manager.storage.Utils; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import java.util.function.Supplier; + public interface RecipientResolver { RecipientId resolveRecipient(RecipientAddress address); RecipientId resolveRecipient(long recipientId); - default RecipientId resolveRecipient(String identifier) { - return resolveRecipient(Utils.getRecipientAddressFromIdentifier(identifier)); - } + RecipientId resolveRecipient(String identifier); default RecipientId resolveRecipient(SignalServiceAddress address) { return resolveRecipient(new RecipientAddress(address)); } - default RecipientId resolveRecipient(ServiceId serviceId) { - return resolveRecipient(new RecipientAddress(serviceId)); + RecipientId resolveRecipient(ServiceId serviceId); + + class RecipientResolverWrapper implements RecipientResolver { + + private final Supplier recipientResolverSupplier; + + public RecipientResolverWrapper(final Supplier recipientResolverSupplier) { + this.recipientResolverSupplier = recipientResolverSupplier; + } + + @Override + public RecipientId resolveRecipient(final RecipientAddress address) { + return recipientResolverSupplier.get().resolveRecipient(address); + } + + @Override + public RecipientId resolveRecipient(final long recipientId) { + return recipientResolverSupplier.get().resolveRecipient(recipientId); + } + + @Override + public RecipientId resolveRecipient(final String identifier) { + return recipientResolverSupplier.get().resolveRecipient(identifier); + } + + @Override + public RecipientId resolveRecipient(final ServiceId serviceId) { + return recipientResolverSupplier.get().resolveRecipient(serviceId); + } } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index f932d497..1b601980 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -145,6 +145,44 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } } + @Override + public RecipientId resolveRecipient(final String identifier) { + if (UuidUtil.isUuid(identifier)) { + return resolveRecipient(ServiceId.parseOrThrow(identifier)); + } else { + return resolveRecipientByNumber(identifier); + } + } + + private RecipientId resolveRecipientByNumber(final String number) { + synchronized (recipientsLock) { + final RecipientId recipientId; + try (final var connection = database.getConnection()) { + connection.setAutoCommit(false); + recipientId = resolveRecipientLocked(connection, number); + connection.commit(); + } catch (SQLException e) { + throw new RuntimeException("Failed read recipient store", e); + } + return recipientId; + } + } + + @Override + public RecipientId resolveRecipient(final ServiceId serviceId) { + synchronized (recipientsLock) { + final RecipientId recipientId; + try (final var connection = database.getConnection()) { + connection.setAutoCommit(false); + recipientId = resolveRecipientLocked(connection, serviceId); + connection.commit(); + } catch (SQLException e) { + throw new RuntimeException("Failed read recipient store", e); + } + return recipientId; + } + } + /** * Should only be used for recipientIds from the database. * Where the foreign key relations ensure a valid recipientId. @@ -170,27 +208,37 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re number)); } - return resolveRecipient(new RecipientAddress(serviceId, number), false, false); + return resolveRecipient(serviceId); } return byNumber.get().id(); } public RecipientId resolveRecipient(RecipientAddress address) { - return resolveRecipient(address, false, false); + synchronized (recipientsLock) { + final RecipientId recipientId; + try (final var connection = database.getConnection()) { + connection.setAutoCommit(false); + recipientId = resolveRecipientLocked(connection, address); + connection.commit(); + } catch (SQLException e) { + throw new RuntimeException("Failed read recipient store", e); + } + return recipientId; + } } @Override public RecipientId resolveSelfRecipientTrusted(RecipientAddress address) { - return resolveRecipient(address, true, true); + return resolveRecipientTrusted(address, true); } public RecipientId resolveRecipientTrusted(RecipientAddress address) { - return resolveRecipient(address, true, false); + return resolveRecipientTrusted(address, false); } @Override public RecipientId resolveRecipientTrusted(SignalServiceAddress address) { - return resolveRecipient(new RecipientAddress(address), true, false); + return resolveRecipientTrusted(new RecipientAddress(address), false); } @Override @@ -198,7 +246,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re final Optional aci, final Optional pni, final Optional number ) { final var serviceId = aci.map(a -> (ServiceId) a).or(() -> pni); - return resolveRecipient(new RecipientAddress(serviceId, number), true, false); + return resolveRecipientTrusted(new RecipientAddress(serviceId, number), false); } @Override @@ -552,16 +600,12 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } } - /** - * @param isHighTrust true, if the number/uuid connection was obtained from a trusted source. - * Has no effect, if the address contains only a number or a uuid. - */ - private RecipientId resolveRecipient(RecipientAddress address, boolean isHighTrust, boolean isSelf) { + private RecipientId resolveRecipientTrusted(RecipientAddress address, boolean isSelf) { final Pair> pair; synchronized (recipientsLock) { try (final var connection = database.getConnection()) { connection.setAutoCommit(false); - pair = resolveRecipientLocked(connection, address, isHighTrust, isSelf); + pair = resolveRecipientTrustedLocked(connection, address, isSelf); connection.commit(); } catch (SQLException e) { throw new RuntimeException("Failed update recipient store", e); @@ -579,12 +623,12 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re return pair.first(); } - private Pair> resolveRecipientLocked( - Connection connection, RecipientAddress address, boolean isHighTrust, boolean isSelf + private Pair> resolveRecipientTrustedLocked( + Connection connection, RecipientAddress address, boolean isSelf ) throws SQLException { - if (isHighTrust && !isSelf) { + if (!isSelf) { if (selfAddressProvider.getSelfAddress().matches(address)) { - isHighTrust = false; + return new Pair<>(resolveRecipientLocked(connection, address), Optional.empty()); } } final var byNumber = address.number().isEmpty() @@ -596,16 +640,10 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re if (byNumber.isEmpty() && byUuid.isEmpty()) { logger.debug("Got new recipient, both uuid and number are unknown"); - - if (isHighTrust || address.serviceId().isEmpty() || address.number().isEmpty()) { - return new Pair<>(addNewRecipient(connection, address), Optional.empty()); - } - - return new Pair<>(addNewRecipient(connection, new RecipientAddress(address.serviceId().get())), - Optional.empty()); + return new Pair<>(addNewRecipient(connection, address), Optional.empty()); } - if (!isHighTrust || address.serviceId().isEmpty() || address.number().isEmpty() || byNumber.equals(byUuid)) { + if (address.serviceId().isEmpty() || address.number().isEmpty() || byNumber.equals(byUuid)) { return new Pair<>(byUuid.or(() -> byNumber).map(RecipientWithAddress::id).get(), Optional.empty()); } @@ -661,6 +699,64 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re return new Pair<>(byUuidRecipient.id(), Optional.of(toBeMergedRecipientId)); } + private RecipientId resolveRecipientLocked( + Connection connection, RecipientAddress address + ) throws SQLException { + final var byServiceId = address.serviceId().isEmpty() + ? Optional.empty() + : findByServiceId(connection, address.serviceId().get()); + + if (byServiceId.isPresent()) { + return byServiceId.get().id(); + } + + final var byPni = address.pni().isEmpty() + ? Optional.empty() + : findByServiceId(connection, address.pni().get()); + + if (byPni.isPresent()) { + return byPni.get().id(); + } + + final var byNumber = address.number().isEmpty() + ? Optional.empty() + : findByNumber(connection, address.number().get()); + + if (byNumber.isPresent()) { + return byNumber.get().id(); + } + + logger.debug("Got new recipient, both serviceId and number are unknown"); + + if (address.serviceId().isEmpty()) { + return addNewRecipient(connection, address); + } + + return addNewRecipient(connection, new RecipientAddress(address.serviceId().get())); + } + + private RecipientId resolveRecipientLocked(Connection connection, ServiceId serviceId) throws SQLException { + final var recipient = findByServiceId(connection, serviceId); + + if (recipient.isEmpty()) { + logger.debug("Got new recipient, serviceId is unknown"); + return addNewRecipient(connection, new RecipientAddress(serviceId)); + } + + return recipient.get().id(); + } + + private RecipientId resolveRecipientLocked(Connection connection, String number) throws SQLException { + final var recipient = findByNumber(connection, number); + + if (recipient.isEmpty()) { + logger.debug("Got new recipient, number is unknown"); + return addNewRecipient(connection, new RecipientAddress(null, number)); + } + + return recipient.get().id(); + } + private RecipientId addNewRecipient( final Connection connection, final RecipientAddress address ) throws SQLException { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java index 5020caf3..38949c64 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java @@ -5,6 +5,7 @@ import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.util.Optional; +import java.util.function.Supplier; public interface RecipientTrustedResolver { @@ -13,4 +14,30 @@ public interface RecipientTrustedResolver { RecipientId resolveRecipientTrusted(SignalServiceAddress address); RecipientId resolveRecipientTrusted(Optional aci, Optional pni, Optional number); + + class RecipientTrustedResolverWrapper implements RecipientTrustedResolver { + + private final Supplier recipientTrustedResolverSupplier; + + public RecipientTrustedResolverWrapper(final Supplier recipientTrustedResolverSupplier) { + this.recipientTrustedResolverSupplier = recipientTrustedResolverSupplier; + } + + @Override + public RecipientId resolveSelfRecipientTrusted(final RecipientAddress address) { + return recipientTrustedResolverSupplier.get().resolveSelfRecipientTrusted(address); + } + + @Override + public RecipientId resolveRecipientTrusted(final SignalServiceAddress address) { + return recipientTrustedResolverSupplier.get().resolveRecipientTrusted(address); + } + + @Override + public RecipientId resolveRecipientTrusted( + final Optional aci, final Optional pni, final Optional number + ) { + return recipientTrustedResolverSupplier.get().resolveRecipientTrusted(aci, pni, number); + } + } } From 58bb4b5358c798b7dd832e55a320891f3ec5d280 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 9 Oct 2022 12:18:43 +0200 Subject: [PATCH 025/713] Update client dependencies --- client/Cargo.lock | 195 +++++++++++++++++++++++----------------------- client/src/cli.rs | 10 +-- 2 files changed, 104 insertions(+), 101 deletions(-) diff --git a/client/Cargo.lock b/client/Cargo.lock index 607cf0d5..7380e538 100644 --- a/client/Cargo.lock +++ b/client/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "atty" @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cfg-if" @@ -63,16 +63,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.1.18" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", "indexmap", - "lazy_static", + "once_cell", "strsim", "termcolor", "textwrap", @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.1.18" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] @@ -133,9 +133,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -158,15 +158,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -176,15 +176,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -193,21 +193,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures 0.1.31", "futures-channel", @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" +checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", "bstr", @@ -248,9 +248,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -269,9 +269,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -288,9 +288,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "jsonrpc-client-transports" @@ -298,7 +298,7 @@ version = "18.0.0" source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6" dependencies = [ "derive_more", - "futures 0.3.21", + "futures 0.3.24", "jsonrpc-core 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)", "jsonrpc-pubsub", "jsonrpc-server-utils 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)", @@ -315,7 +315,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.21", + "futures 0.3.24", "futures-executor", "futures-util", "log", @@ -329,7 +329,7 @@ name = "jsonrpc-core" version = "18.0.0" source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6" dependencies = [ - "futures 0.3.21", + "futures 0.3.24", "futures-executor", "futures-util", "log", @@ -344,7 +344,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" dependencies = [ - "futures 0.3.21", + "futures 0.3.24", "jsonrpc-client-transports", ] @@ -364,7 +364,7 @@ name = "jsonrpc-pubsub" version = "18.0.0" source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6" dependencies = [ - "futures 0.3.21", + "futures 0.3.24", "jsonrpc-core 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)", "lazy_static", "log", @@ -380,7 +380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ "bytes", - "futures 0.3.21", + "futures 0.3.24", "globset", "jsonrpc-core 18.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static", @@ -397,7 +397,7 @@ version = "18.0.0" source = "git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params#8a68f95e202943fd338fd0c14da08c2dc8f6e6a6" dependencies = [ "bytes", - "futures 0.3.21", + "futures 0.3.24", "globset", "jsonrpc-core 18.0.0 (git+https://github.com/AsamK/jsonrpc?branch=client_subscribe_named_params)", "lazy_static", @@ -416,15 +416,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -447,9 +447,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mio" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", @@ -469,15 +469,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.11.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "os_str_bytes" -version = "6.0.1" +version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" [[package]] name = "parity-tokio-ipc" @@ -485,7 +485,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" dependencies = [ - "futures 0.3.21", + "futures 0.3.24", "libc", "log", "rand", @@ -571,18 +571,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -630,18 +630,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -650,9 +650,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "rustc_version" @@ -665,9 +665,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "scopeguard" @@ -677,24 +677,24 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.9" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa", "ryu", @@ -731,21 +731,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -759,9 +762,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.95" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -779,22 +782,22 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "tokio" -version = "1.18.2" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", - "once_cell", "pin-project-lite", "socket2", "tokio-macros", @@ -803,9 +806,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -814,9 +817,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" dependencies = [ "futures-core", "pin-project-lite", @@ -857,9 +860,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "version_check" diff --git a/client/src/cli.rs b/client/src/cli.rs index a98b16d3..f211bb20 100644 --- a/client/src/cli.rs +++ b/client/src/cli.rs @@ -69,7 +69,7 @@ pub enum CliCommands { recipient: Vec, #[clap(short = 'a', long = "all-recipients")] all_recipients: bool, - #[clap(long, parse(try_from_str))] + #[clap(long)] blocked: Option, #[clap(long)] name: Option, @@ -245,16 +245,16 @@ pub enum CliCommands { device_name: Option, }, UpdateConfiguration { - #[clap(long = "read-receipts", parse(try_from_str))] + #[clap(long = "read-receipts")] read_receipts: Option, - #[clap(long = "unidentified-delivery-indicators", parse(try_from_str))] + #[clap(long = "unidentified-delivery-indicators")] unidentified_delivery_indicators: Option, - #[clap(long = "typing-indicators", parse(try_from_str))] + #[clap(long = "typing-indicators")] typing_indicators: Option, - #[clap(long = "link-previews", parse(try_from_str))] + #[clap(long = "link-previews")] link_previews: Option, }, UpdateContact { From 94d79692df24f69807bc77898292109b55ae1735 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 9 Oct 2022 12:30:25 +0200 Subject: [PATCH 026/713] Update to clap 4 --- client/Cargo.lock | 94 +++++++++++++++------ client/Cargo.toml | 2 +- client/src/cli.rs | 200 ++++++++++++++++++++++----------------------- client/src/main.rs | 2 +- 4 files changed, 169 insertions(+), 129 deletions(-) diff --git a/client/Cargo.lock b/client/Cargo.lock index 7380e538..8e4bff27 100644 --- a/client/Cargo.lock +++ b/client/Cargo.lock @@ -55,6 +55,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" @@ -63,26 +69,25 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.22" +version = "4.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "4ed45cc2c62a3eff523e718d8576ba762c83a3146151093283ac62ae11933a73" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", "once_cell", "strsim", "termcolor", - "textwrap", + "terminal_size", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "db342ce9fda24fb191e2ed4e102055a4d381c1086a06630174cd8da8d5d917ce" dependencies = [ "heck", "proc-macro-error", @@ -93,9 +98,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] @@ -119,6 +124,27 @@ dependencies = [ "syn", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fnv" version = "1.0.7" @@ -246,12 +272,6 @@ dependencies = [ "regex", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "heck" version = "0.4.0" @@ -267,16 +287,6 @@ dependencies = [ "libc", ] -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - [[package]] name = "instant" version = "0.1.12" @@ -286,6 +296,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea37f355c05dde75b84bba2d767906ad522e97cd9e2eef2be7a4ab7fb442c06" + [[package]] name = "itoa" version = "1.0.4" @@ -420,6 +436,12 @@ version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + [[package]] name = "lock_api" version = "0.4.9" @@ -663,6 +685,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.35.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "ryu" version = "1.0.11" @@ -781,10 +817,14 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.15.1" +name = "terminal_size" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" +checksum = "8440c860cf79def6164e4a0a983bcc2305d82419177a0e0c71930d049e3ac5a1" +dependencies = [ + "rustix", + "windows-sys", +] [[package]] name = "tokio" diff --git a/client/Cargo.toml b/client/Cargo.toml index e14d2d74..9e3cd4df 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] anyhow = "1" -clap = { version = "3", features = ["cargo", "derive"] } +clap = { version = "4", features = ["cargo", "derive", "wrap_help"] } jsonrpc-core = "18" jsonrpc-core-client = "18" jsonrpc-client-transports = { version = "18", default-features = false, features = [ diff --git a/client/src/cli.rs b/client/src/cli.rs index f211bb20..01910001 100644 --- a/client/src/cli.rs +++ b/client/src/cli.rs @@ -1,34 +1,34 @@ -use clap::{crate_version, ArgEnum, Parser, Subcommand}; +use clap::{crate_version, Parser, Subcommand, ValueEnum}; use std::{ffi::OsString, net::SocketAddr}; /// JSON-RPC client for signal-cli #[derive(Parser, Debug)] -#[clap(rename_all = "kebab-case", version=crate_version!())] +#[command(rename_all = "kebab-case", version=crate_version!())] pub struct Cli { /// Account to use (for daemon in multi-account mode) - #[clap(short = 'a', long)] + #[arg(short = 'a', long)] pub account: Option, /// TCP host and port of signal-cli daemon - #[clap(long)] + #[arg(long)] pub json_rpc_tcp: Option>, /// UNIX socket address and port of signal-cli daemon - #[clap(long)] + #[arg(long)] pub json_rpc_socket: Option>, - #[clap(arg_enum, long, default_value_t = OutputTypes::Json)] + #[arg(value_enum, long, default_value_t = OutputTypes::Json)] pub output: OutputTypes, - #[clap(long)] + #[arg(long)] pub verbose: bool, - #[clap(subcommand)] + #[command(subcommand)] pub command: CliCommands, } -#[derive(ArgEnum, Clone, Debug)] -#[clap(rename_all = "kebab-case")] +#[derive(ValueEnum, Clone, Debug)] +#[value(rename_all = "kebab-case")] pub enum OutputTypes { PlainText, Json, @@ -36,181 +36,181 @@ pub enum OutputTypes { #[allow(clippy::large_enum_variant)] #[derive(Subcommand, Debug)] -#[clap(rename_all = "camelCase", version=crate_version!())] +#[command(rename_all = "camelCase", version=crate_version!())] pub enum CliCommands { AddDevice { - #[clap(long)] + #[arg(long)] uri: String, }, - #[clap(rename_all = "kebab-case")] + #[command(rename_all = "kebab-case")] Block { recipient: Vec, - #[clap(short = 'g', long)] + #[arg(short = 'g', long)] group_id: Vec, }, DeleteLocalAccountData { - #[clap(long = "ignore-registered")] + #[arg(long = "ignore-registered")] ignore_registered: Option, }, GetUserStatus { recipient: Vec, }, JoinGroup { - #[clap(long)] + #[arg(long)] uri: String, }, Link { - #[clap(short = 'n', long)] + #[arg(short = 'n', long)] name: String, }, ListAccounts, ListContacts { recipient: Vec, - #[clap(short = 'a', long = "all-recipients")] + #[arg(short = 'a', long = "all-recipients")] all_recipients: bool, - #[clap(long)] + #[arg(long)] blocked: Option, - #[clap(long)] + #[arg(long)] name: Option, }, ListDevices, ListGroups { - #[clap(short = 'd', long)] + #[arg(short = 'd', long)] detailed: bool, - #[clap(short = 'g', long = "group-id")] + #[arg(short = 'g', long = "group-id")] group_id: Vec, }, ListIdentities { - #[clap(short = 'n', long)] + #[arg(short = 'n', long)] number: Option, }, ListStickerPacks, QuitGroup { - #[clap(short = 'g', long = "group-id")] + #[arg(short = 'g', long = "group-id")] group_id: String, - #[clap(long)] + #[arg(long)] delete: bool, - #[clap(long)] + #[arg(long)] admin: Vec, }, Receive { - #[clap(short = 't', long, default_value_t = 3.0)] + #[arg(short = 't', long, default_value_t = 3.0)] timeout: f64, }, Register { - #[clap(short = 'v', long)] + #[arg(short = 'v', long)] voice: bool, - #[clap(long)] + #[arg(long)] captcha: Option, }, RemoveContact { recipient: String, - #[clap(long)] + #[arg(long)] forget: bool, }, RemoveDevice { - #[clap(short = 'd', long = "device-id")] + #[arg(short = 'd', long = "device-id")] device_id: u32, }, RemovePin, RemoteDelete { - #[clap(short = 't', long = "target-timestamp")] + #[arg(short = 't', long = "target-timestamp")] target_timestamp: u64, recipient: Vec, - #[clap(short = 'g', long = "group-id")] + #[arg(short = 'g', long = "group-id")] group_id: Vec, - #[clap(long = "note-to-self")] + #[arg(long = "note-to-self")] note_to_self: bool, }, - #[clap(rename_all = "kebab-case")] + #[command(rename_all = "kebab-case")] Send { recipient: Vec, - #[clap(short = 'g', long)] + #[arg(short = 'g', long)] group_id: Vec, - #[clap(long)] + #[arg(long)] note_to_self: bool, - #[clap(short = 'e', long)] + #[arg(short = 'e', long)] end_session: bool, - #[clap(short = 'm', long)] + #[arg(short = 'm', long)] message: Option, - #[clap(short = 'a', long)] + #[arg(short = 'a', long)] attachment: Vec, - #[clap(long)] + #[arg(long)] mention: Vec, - #[clap(long)] + #[arg(long)] quote_timestamp: Option, - #[clap(long)] + #[arg(long)] quote_author: Option, - #[clap(long)] + #[arg(long)] quote_message: Option, - #[clap(long)] + #[arg(long)] quote_mention: Vec, - #[clap(long)] + #[arg(long)] sticker: Option, }, SendContacts, SendPaymentNotification { recipient: String, - #[clap(long)] + #[arg(long)] receipt: String, - #[clap(long)] + #[arg(long)] note: String, }, SendReaction { recipient: Vec, - #[clap(short = 'g', long = "group-id")] + #[arg(short = 'g', long = "group-id")] group_id: Vec, - #[clap(long = "note-to-self")] + #[arg(long = "note-to-self")] note_to_self: bool, - #[clap(short = 'e', long)] + #[arg(short = 'e', long)] emoji: String, - #[clap(short = 'a', long = "target-author")] + #[arg(short = 'a', long = "target-author")] target_author: String, - #[clap(short = 't', long = "target-timestamp")] + #[arg(short = 't', long = "target-timestamp")] target_timestamp: u64, - #[clap(short = 'r', long)] + #[arg(short = 'r', long)] remove: bool, }, SendReceipt { recipient: String, - #[clap(short = 't', long = "target-timestamp")] + #[arg(short = 't', long = "target-timestamp")] target_timestamp: Vec, - #[clap(arg_enum, long)] + #[arg(value_enum, long)] r#type: ReceiptType, }, SendSyncRequest, SendTyping { recipient: Vec, - #[clap(short = 'g', long = "group-id")] + #[arg(short = 'g', long = "group-id")] group_id: Vec, - #[clap(short = 's', long)] + #[arg(short = 's', long)] stop: bool, }, SetPin { @@ -223,118 +223,118 @@ pub enum CliCommands { Trust { recipient: String, - #[clap(short = 'a', long = "trust-all-known-keys")] + #[arg(short = 'a', long = "trust-all-known-keys")] trust_all_known_keys: bool, - #[clap(short = 'v', long = "verified-safety-number")] + #[arg(short = 'v', long = "verified-safety-number")] verified_safety_number: Option, }, - #[clap(rename_all = "kebab-case")] + #[command(rename_all = "kebab-case")] Unblock { recipient: Vec, - #[clap(short = 'g', long)] + #[arg(short = 'g', long)] group_id: Vec, }, Unregister { - #[clap(long = "delete-account")] + #[arg(long = "delete-account")] delete_account: bool, }, UpdateAccount { - #[clap(short = 'n', long = "device-name")] + #[arg(short = 'n', long = "device-name")] device_name: Option, }, UpdateConfiguration { - #[clap(long = "read-receipts")] + #[arg(long = "read-receipts")] read_receipts: Option, - #[clap(long = "unidentified-delivery-indicators")] + #[arg(long = "unidentified-delivery-indicators")] unidentified_delivery_indicators: Option, - #[clap(long = "typing-indicators")] + #[arg(long = "typing-indicators")] typing_indicators: Option, - #[clap(long = "link-previews")] + #[arg(long = "link-previews")] link_previews: Option, }, UpdateContact { recipient: String, - #[clap(short = 'e', long)] + #[arg(short = 'e', long)] expiration: Option, - #[clap(short = 'n', long)] + #[arg(short = 'n', long)] name: Option, }, UpdateGroup { - #[clap(short = 'g', long = "group-id")] + #[arg(short = 'g', long = "group-id")] group_id: Option, - #[clap(short = 'n', long)] + #[arg(short = 'n', long)] name: Option, - #[clap(short = 'd', long)] + #[arg(short = 'd', long)] description: Option, - #[clap(short = 'a', long)] + #[arg(short = 'a', long)] avatar: Option, - #[clap(short = 'm', long)] + #[arg(short = 'm', long)] member: Vec, - #[clap(short = 'r', long = "remove-member")] + #[arg(short = 'r', long = "remove-member")] remove_member: Vec, - #[clap(long)] + #[arg(long)] admin: Vec, - #[clap(long = "remove-admin")] + #[arg(long = "remove-admin")] remove_admin: Vec, - #[clap(long)] + #[arg(long)] ban: Vec, - #[clap(long)] + #[arg(long)] unban: Vec, - #[clap(long = "reset-link")] + #[arg(long = "reset-link")] reset_link: bool, - #[clap(arg_enum, long)] + #[arg(value_enum, long)] link: Option, - #[clap(arg_enum, long = "set-permission-add-member")] + #[arg(value_enum, long = "set-permission-add-member")] set_permission_add_member: Option, - #[clap(arg_enum, long = "set-permission-edit-details")] + #[arg(value_enum, long = "set-permission-edit-details")] set_permission_edit_details: Option, - #[clap(arg_enum, long = "set-permission-send-messages")] + #[arg(value_enum, long = "set-permission-send-messages")] set_permission_send_messages: Option, - #[clap(short = 'e', long)] + #[arg(short = 'e', long)] expiration: Option, }, UpdateProfile { - #[clap(long = "given-name")] + #[arg(long = "given-name")] given_name: Option, - #[clap(long = "family-name")] + #[arg(long = "family-name")] family_name: Option, - #[clap(long)] + #[arg(long)] about: Option, - #[clap(long = "about-emoji")] + #[arg(long = "about-emoji")] about_emoji: Option, - #[clap(long = "mobile-coin-address")] + #[arg(long = "mobile-coin-address")] mobile_coin_address: Option, - #[clap(long)] + #[arg(long)] avatar: Option, - #[clap(long = "remove-avatar")] + #[arg(long = "remove-avatar")] remove_avatar: bool, }, UploadStickerPack { @@ -343,29 +343,29 @@ pub enum CliCommands { Verify { verification_code: String, - #[clap(short = 'p', long)] + #[arg(short = 'p', long)] pin: Option, }, Version, } -#[derive(ArgEnum, Clone, Debug)] -#[clap(rename_all = "kebab-case")] +#[derive(ValueEnum, Clone, Debug)] +#[value(rename_all = "kebab-case")] pub enum ReceiptType { Read, Viewed, } -#[derive(ArgEnum, Clone, Debug)] -#[clap(rename_all = "kebab-case")] +#[derive(ValueEnum, Clone, Debug)] +#[value(rename_all = "kebab-case")] pub enum LinkState { Enabled, EnabledWithApproval, Disabled, } -#[derive(ArgEnum, Clone, Debug)] -#[clap(rename_all = "kebab-case")] +#[derive(ValueEnum, Clone, Debug)] +#[value(rename_all = "kebab-case")] pub enum GroupPermission { EveryMember, OnlyAdmins, diff --git a/client/src/main.rs b/client/src/main.rs index c0ef0de6..50a0f4cb 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,4 +1,4 @@ -use clap::StructOpt; +use clap::Parser; use jsonrpc_client_transports::{RpcError, TypedSubscriptionStream}; use jsonrpc_core::{futures_util::StreamExt, Value}; use std::{path::PathBuf, time::Duration}; From 45a5795c9c0982302ab75aec74707ff37e1ee67f Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 16 Oct 2022 20:07:33 +0200 Subject: [PATCH 027/713] Handle PniChangeNumber --- lib/build.gradle.kts | 2 +- .../signal/manager/helper/AccountHelper.java | 16 +++++++++ .../signal/manager/helper/GroupV2Helper.java | 4 +++ .../helper/IncomingMessageHandler.java | 34 +++++++++++++++++-- .../signal/manager/helper/SendHelper.java | 3 +- .../signal/manager/storage/SignalAccount.java | 29 ++++++++++++++-- .../manager/util/MessageCacheUtils.java | 10 ++++-- 7 files changed, 89 insertions(+), 9 deletions(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index ae431ffb..1e24d6c7 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -14,7 +14,7 @@ repositories { } dependencies { - implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_61") + implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_62") implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4") implementation("com.google.protobuf", "protobuf-javalite", "3.21.6") implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java index 0b19a691..7ae9aa45 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java @@ -11,12 +11,15 @@ import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.NumberVerificationUtils; +import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.InvalidKeyException; +import org.signal.libsignal.protocol.state.SignedPreKeyRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest; import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceIdType; import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; @@ -111,6 +114,19 @@ public class AccountHelper { context.getAccountFileUpdater().updateAccountIdentifiers(account.getNumber(), account.getAci()); } + public void setPni( + final PNI updatedPni, + final IdentityKeyPair pniIdentityKeyPair, + final SignedPreKeyRecord pniSignedPreKey, + final int localPniRegistrationId + ) throws IOException { + account.setPni(updatedPni, pniIdentityKeyPair, pniSignedPreKey, localPniRegistrationId); + context.getPreKeyHelper().refreshPreKeysIfNecessary(ServiceIdType.PNI); + if (account.getPni() == null || !account.getPni().equals(updatedPni)) { + context.getGroupV2Helper().clearAuthCredentialCache(); + } + } + public void startChangeNumber( String newNumber, String captcha, boolean voiceVerification ) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException { diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java index 09e3ff95..84747e9c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java @@ -77,6 +77,10 @@ class GroupV2Helper { this.context = context; } + void clearAuthCredentialCache() { + groupApiCredentials = null; + } + DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException { try { final var groupsV2AuthorizationString = getGroupAuthForToday(groupSecretParams); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index a9c8fdae..69ad65f7 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -42,8 +42,10 @@ import org.signal.libsignal.metadata.ProtocolInvalidMessageException; import org.signal.libsignal.metadata.ProtocolNoSessionException; import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException; import org.signal.libsignal.metadata.SelfSendException; +import org.signal.libsignal.protocol.IdentityKeyPair; import org.signal.libsignal.protocol.InvalidMessageException; import org.signal.libsignal.protocol.message.DecryptionErrorMessage; +import org.signal.libsignal.protocol.state.SignedPreKeyRecord; import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.slf4j.Logger; @@ -58,6 +60,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; @@ -304,7 +307,10 @@ public final class IncomingMessageHandler { if (content.getSyncMessage().isPresent()) { var syncMessage = content.getSyncMessage().get(); - actions.addAll(handleSyncMessage(syncMessage, senderDeviceAddress, receiveConfig.ignoreAttachments())); + actions.addAll(handleSyncMessage(envelope, + syncMessage, + senderDeviceAddress, + receiveConfig.ignoreAttachments())); } return actions; @@ -364,7 +370,10 @@ public final class IncomingMessageHandler { } private List handleSyncMessage( - final SignalServiceSyncMessage syncMessage, final DeviceAddress sender, final boolean ignoreAttachments + final SignalServiceEnvelope envelope, + final SignalServiceSyncMessage syncMessage, + final DeviceAddress sender, + final boolean ignoreAttachments ) { var actions = new ArrayList(); account.setMultiDevice(true); @@ -519,7 +528,26 @@ public final class IncomingMessageHandler { pniIdentity.getPrivateKey().toByteArray())); actions.add(RefreshPreKeysAction.create()); } - // TODO handle PniChangeNumber + if (syncMessage.getPniChangeNumber().isPresent()) { + final var pniChangeNumber = syncMessage.getPniChangeNumber().get(); + logger.debug("Received PNI change number sync message, applying."); + if (pniChangeNumber.hasIdentityKeyPair() + && pniChangeNumber.hasRegistrationId() + && pniChangeNumber.hasSignedPreKey() + && !envelope.getUpdatedPni().isEmpty()) { + logger.debug("New PNI: {}", envelope.getUpdatedPni()); + try { + final var updatedPni = PNI.parseOrThrow(envelope.getUpdatedPni()); + context.getAccountHelper() + .setPni(updatedPni, + new IdentityKeyPair(pniChangeNumber.getIdentityKeyPair().toByteArray()), + new SignedPreKeyRecord(pniChangeNumber.getSignedPreKey().toByteArray()), + pniChangeNumber.getRegistrationId()); + } catch (Exception e) { + logger.warn("Failed to handle change number message", e); + } + } + } return actions; } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java index e8b19356..6d2021e0 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java @@ -352,7 +352,8 @@ public class SendHelper { contentHint, message, SignalServiceMessageSender.SenderKeyGroupEvents.EMPTY, - urgent); + urgent, + false); synchronized (entryId) { if (entryId.get() == -1) { final var newId = messageSendLogStore.insertIfPossible(message.getTimestamp(), diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 85e5cadd..730fe85a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -1297,11 +1297,31 @@ public class SignalAccount implements Closeable { return pni; } - public void setPni(final PNI pni) { - this.pni = pni; + public void setPni(final PNI updatedPni) { + if (this.pni != null && !this.pni.equals(updatedPni)) { + // Clear data for old PNI + identityKeyStore.deleteIdentity(this.pni); + getPniPreKeyStore().removeAllPreKeys(); + getPniSignedPreKeyStore().removeAllSignedPreKeys(); + } + + this.pni = updatedPni; save(); } + public void setPni( + final PNI updatedPni, + final IdentityKeyPair pniIdentityKeyPair, + final SignedPreKeyRecord pniSignedPreKey, + final int localPniRegistrationId + ) { + setPni(updatedPni); + + setPniIdentityKeyPair(pniIdentityKeyPair); + addPniSignedPreKey(pniSignedPreKey); + setLocalPniRegistrationId(localPniRegistrationId); + } + public SignalServiceAddress getSelfAddress() { return new SignalServiceAddress(aci, number); } @@ -1359,6 +1379,11 @@ public class SignalAccount implements Closeable { return localPniRegistrationId; } + public void setLocalPniRegistrationId(final int localPniRegistrationId) { + this.localPniRegistrationId = localPniRegistrationId; + save(); + } + public String getPassword() { return password; } diff --git a/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java b/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java index 7e8ebea5..f61ed2a2 100644 --- a/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java +++ b/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java @@ -19,7 +19,7 @@ public class MessageCacheUtils { try (var f = new FileInputStream(file)) { var in = new DataInputStream(f); var version = in.readInt(); - if (version > 7) { + if (version > 8) { // Unsupported envelope version return null; } @@ -71,6 +71,10 @@ public class MessageCacheUtils { if (version >= 7) { isStory = in.readBoolean(); } + String updatedPni = null; + if (version >= 8) { + updatedPni = in.readUTF(); + } Optional addressOptional = sourceServiceId == null ? Optional.empty() : Optional.of(new SignalServiceAddress(sourceServiceId, source)); @@ -84,6 +88,7 @@ public class MessageCacheUtils { uuid, destinationUuid == null ? UuidUtil.UNKNOWN_UUID.toString() : destinationUuid, isUrgent, + updatedPni == null ? "" : updatedPni, isStory); } } @@ -91,7 +96,7 @@ public class MessageCacheUtils { public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException { try (var f = new FileOutputStream(file)) { try (var out = new DataOutputStream(f)) { - out.writeInt(7); // version + out.writeInt(8); // version out.writeInt(envelope.getType()); out.writeUTF(""); // legacy number out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : ""); @@ -111,6 +116,7 @@ public class MessageCacheUtils { out.writeLong(envelope.getServerDeliveredTimestamp()); out.writeBoolean(envelope.isUrgent()); out.writeBoolean(envelope.isStory()); + out.writeUTF(envelope.getUpdatedPni() == null ? "" : envelope.getUpdatedPni()); } } } From 3522e43617c024882219a3c5634e79df05a3a627 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 16 Oct 2022 20:47:51 +0200 Subject: [PATCH 028/713] Update dependencies --- build.gradle.kts | 4 ++-- lib/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 97f2109b..404fbc5f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,11 +33,11 @@ repositories { dependencies { implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") - implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4") + implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4.2") implementation("net.sourceforge.argparse4j", "argparse4j", "0.9.0") implementation("com.github.hypfvieh", "dbus-java-transport-native-unixsocket", "4.2.1") implementation("org.slf4j", "slf4j-api", "2.0.3") - implementation("ch.qos.logback", "logback-classic", "1.4.3") + implementation("ch.qos.logback", "logback-classic", "1.4.4") implementation("org.slf4j", "jul-to-slf4j", "2.0.3") implementation(project(":lib")) } diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 1e24d6c7..2e5feb3a 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -15,7 +15,7 @@ repositories { dependencies { implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_62") - implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4") + implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4.2") implementation("com.google.protobuf", "protobuf-javalite", "3.21.6") implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") implementation("org.slf4j", "slf4j-api", "2.0.3") From 266129c61b4d8a0d464c0c601e224f36134a874b Mon Sep 17 00:00:00 2001 From: AsamK Date: Tue, 18 Oct 2022 17:38:46 +0200 Subject: [PATCH 029/713] Update reflect-config --- graalvm-config-dir/reflect-config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 4dc7e3e2..4abc4a10 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -2984,6 +2984,7 @@ {"name":"story_"}, {"name":"timestamp_"}, {"name":"type_"}, + {"name":"updatedPni_"}, {"name":"urgent_"} ] }, From 228713ebb5476ef2f2e66d3670004aaa82c0eafb Mon Sep 17 00:00:00 2001 From: AsamK Date: Tue, 18 Oct 2022 17:55:51 +0200 Subject: [PATCH 030/713] Reset pre key offset if it somehow gets corrupted Fixes #1055 --- .../signal/manager/helper/PreKeyHelper.java | 12 ++++++++++++ .../signal/manager/storage/SignalAccount.java | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/PreKeyHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/PreKeyHelper.java index 3fc1a5bf..30ab919e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/PreKeyHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/PreKeyHelper.java @@ -53,6 +53,18 @@ public class PreKeyHelper { if (accountId == null) { return; } + try { + refreshPreKeys(serviceIdType, identityKeyPair); + } catch (Exception e) { + logger.warn("Failed to store new pre keys, resetting preKey id offset", e); + account.resetPreKeyOffsets(serviceIdType); + refreshPreKeys(serviceIdType, identityKeyPair); + } + } + + private void refreshPreKeys( + final ServiceIdType serviceIdType, final IdentityKeyPair identityKeyPair + ) throws IOException { final var oneTimePreKeys = generatePreKeys(serviceIdType); final var signedPreKeyRecord = generateSignedPreKey(serviceIdType, identityKeyPair); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 730fe85a..db919269 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -294,10 +294,8 @@ public class SignalAccount implements Closeable { } private void clearAllPreKeys() { - this.aciPreKeyIdOffset = new SecureRandom().nextInt(Medium.MAX_VALUE); - this.aciNextSignedPreKeyId = new SecureRandom().nextInt(Medium.MAX_VALUE); - this.pniPreKeyIdOffset = new SecureRandom().nextInt(Medium.MAX_VALUE); - this.pniNextSignedPreKeyId = new SecureRandom().nextInt(Medium.MAX_VALUE); + resetPreKeyOffsets(ServiceIdType.ACI); + resetPreKeyOffsets(ServiceIdType.PNI); this.getAciPreKeyStore().removeAllPreKeys(); this.getAciSignedPreKeyStore().removeAllSignedPreKeys(); this.getPniPreKeyStore().removeAllPreKeys(); @@ -998,6 +996,17 @@ public class SignalAccount implements Closeable { } } + public void resetPreKeyOffsets(final ServiceIdType serviceIdType) { + if (serviceIdType.equals(ServiceIdType.ACI)) { + this.aciPreKeyIdOffset = new SecureRandom().nextInt(Medium.MAX_VALUE); + this.aciNextSignedPreKeyId = new SecureRandom().nextInt(Medium.MAX_VALUE); + } else { + this.pniPreKeyIdOffset = new SecureRandom().nextInt(Medium.MAX_VALUE); + this.pniNextSignedPreKeyId = new SecureRandom().nextInt(Medium.MAX_VALUE); + } + save(); + } + public void addPreKeys(ServiceIdType serviceIdType, List records) { if (serviceIdType.equals(ServiceIdType.ACI)) { addAciPreKeys(records); From 0aee7ff552eb9d1ca030cb9f52bc80bac6c0c397 Mon Sep 17 00:00:00 2001 From: AsamK Date: Tue, 18 Oct 2022 18:11:26 +0200 Subject: [PATCH 031/713] Update graalvm buildtools --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 404fbc5f..4e9fcfc6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { application eclipse `check-lib-versions` - id("org.graalvm.buildtools.native") version "0.9.14" + id("org.graalvm.buildtools.native") version "0.9.15" } version = "0.11.3" From 9da42e27f1b789cdd94c56a1b57e01f9614b71a7 Mon Sep 17 00:00:00 2001 From: AsamK Date: Tue, 18 Oct 2022 18:11:17 +0200 Subject: [PATCH 032/713] Update workflow actions --- .github/workflows/ci.yml | 7 ++++--- .github/workflows/codeql-analysis.yml | 11 ++++++----- .github/workflows/repackage-native-libs.yml | 7 ++++--- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a59d3cf..a3c2e2a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,17 +11,18 @@ jobs: java: [ '17', '18' ] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Set up JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: + distribution: 'adopt' java-version: ${{ matrix.java }} - name: Build with Gradle run: ./gradlew build - name: Compress archive run: gzip -n -9 build/distributions/signal-cli-*.tar - name: Archive production artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: signal-cli-archive-${{ matrix.java }} path: build/distributions/signal-cli-*.tar.gz diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0ef62f7e..25bcc265 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -17,12 +17,13 @@ jobs: steps: - name: Setup Java JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: + distribution: 'adopt' java-version: 17 - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -30,7 +31,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -38,7 +39,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -52,4 +53,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/repackage-native-libs.yml b/.github/workflows/repackage-native-libs.yml index fc5fa780..8ebba79e 100644 --- a/.github/workflows/repackage-native-libs.yml +++ b/.github/workflows/repackage-native-libs.yml @@ -10,7 +10,7 @@ jobs: ci_wf: uses: AsamK/signal-cli/.github/workflows/ci.yml@master - # ${{ github.repository }} not accpeted here + # ${{ github.repository }} not accpeted here lib_to_jar: @@ -24,7 +24,7 @@ jobs: steps: - name: Download signal-cli build from CI workflow - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Get signal-cli version id: cli_ver @@ -159,8 +159,9 @@ jobs: tar -xzf "$file_name" - name: Set up JDK for running signal-cli executable - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: + distribution: 'adopt' java-version: ${{ env.JAVA_VERSION }} - name: Run signal-cli From 316c35b25885ddb7944d7efdff450af0c66ed61d Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 11:02:10 +0200 Subject: [PATCH 033/713] Add additional logging for reading message cache --- .../manager/storage/messageCache/CachedMessage.java | 2 +- .../asamk/signal/manager/util/MessageCacheUtils.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/messageCache/CachedMessage.java b/lib/src/main/java/org/asamk/signal/manager/storage/messageCache/CachedMessage.java index 941c4fa9..c1f310e8 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/messageCache/CachedMessage.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/messageCache/CachedMessage.java @@ -27,7 +27,7 @@ public final class CachedMessage { try { return MessageCacheUtils.loadEnvelope(file); } catch (Exception e) { - logger.error("Failed to load cached message envelope “{}”: {}", file, e.getMessage()); + logger.error("Failed to load cached message envelope “{}”: {}", file, e.getMessage(), e); return null; } } diff --git a/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java b/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java index f61ed2a2..3691ef08 100644 --- a/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java +++ b/lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java @@ -1,5 +1,7 @@ package org.asamk.signal.manager.util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; @@ -15,11 +17,17 @@ import java.util.Optional; public class MessageCacheUtils { + private final static Logger logger = LoggerFactory.getLogger(MessageCacheUtils.class); + + final static int CURRENT_VERSION = 8; + public static SignalServiceEnvelope loadEnvelope(File file) throws IOException { try (var f = new FileInputStream(file)) { var in = new DataInputStream(f); var version = in.readInt(); - if (version > 8) { + logger.trace("Reading cached envelope file with version {} (current: {})", version, CURRENT_VERSION); + if (version > CURRENT_VERSION) { + logger.warn("Unsupported envelope version {} (current: {})", version, CURRENT_VERSION); // Unsupported envelope version return null; } @@ -96,7 +104,7 @@ public class MessageCacheUtils { public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException { try (var f = new FileOutputStream(file)) { try (var out = new DataOutputStream(f)) { - out.writeInt(8); // version + out.writeInt(CURRENT_VERSION); // version out.writeInt(envelope.getType()); out.writeUTF(""); // legacy number out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : ""); From 7188c75351bc4086e68990ba1769a903d080622c Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 15:36:13 +0200 Subject: [PATCH 034/713] Update reflect-config --- graalvm-config-dir/reflect-config.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 4abc4a10..1feb0917 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -1234,16 +1234,6 @@ {"name":"unidentifiedAccessMode","parameterTypes":[] } ] }, -{ - "name":"org.asamk.signal.manager.storage.recipients.RecipientAddress", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "queryAllDeclaredConstructors":true, - "methods":[ - {"name":"number","parameterTypes":[] }, - {"name":"uuid","parameterTypes":[] } - ] -}, { "name":"org.asamk.signal.manager.storage.senderKeys.LegacySenderKeySharedStore$Storage", "allDeclaredFields":true, From 2e5d8fe5619e3b341b4834d457f73da159cc4633 Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 15:23:58 +0200 Subject: [PATCH 035/713] Add build graalvm native step for CI --- .github/workflows/ci.yml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3c2e2a2..74a402ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: distribution: 'adopt' java-version: ${{ matrix.java }} - name: Build with Gradle - run: ./gradlew build + run: ./gradlew --no-daemon build - name: Compress archive run: gzip -n -9 build/distributions/signal-cli-*.tar - name: Archive production artifacts @@ -26,3 +26,22 @@ jobs: with: name: signal-cli-archive-${{ matrix.java }} path: build/distributions/signal-cli-*.tar.gz + + build-graalvm: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: graalvm/setup-graalvm@v1 + with: + version: 'latest' + java-version: '17' + components: 'native-image' + - name: Build with Gradle + run: ./gradlew --no-daemon nativeCompile + - name: Archive production artifacts + uses: actions/upload-artifact@v3 + with: + name: signal-cli-archive-native + path: build/native/nativeCompile/signal-cli From 3f7d8c60b9dc48d4aa9d81e065c0cf189af4d070 Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 17:51:12 +0200 Subject: [PATCH 036/713] Add workaround for #1045 --- .../signal/manager/helper/IncomingMessageHandler.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index 69ad65f7..80cf7687 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -144,7 +144,14 @@ public final class IncomingMessageHandler { } else { final var senderProfile = context.getProfileHelper().getRecipientProfile(sender); final var selfProfile = context.getProfileHelper().getSelfProfile(); - final var serviceId = ServiceId.parseOrNull(e.getSender()); + var serviceId = ServiceId.parseOrNull(e.getSender()); + if (serviceId == null) { + // Workaround for libsignal-client issue #492 + serviceId = account.getRecipientAddressResolver() + .resolveRecipientAddress(sender) + .serviceId() + .orElse(null); + } if (serviceId != null) { final var isSelf = sender.equals(account.getSelfRecipientId()) && e.getSenderDevice() == account.getDeviceId(); From 9ffacfe90e54a86da289d3e6fb3c3df738f57abb Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 19:09:23 +0200 Subject: [PATCH 037/713] Add --ignore-stories flag to prevent receiving story messages --- .../asamk/signal/manager/SignalDependencies.java | 14 ++++++++++++-- .../asamk/signal/manager/api/ReceiveConfig.java | 2 +- .../asamk/signal/manager/helper/AccountHelper.java | 1 - .../asamk/signal/manager/helper/ReceiveHelper.java | 11 ++++++----- man/signal-cli.1.adoc | 8 ++++++++ .../org/asamk/signal/commands/DaemonCommand.java | 13 +++++++++---- .../signal/commands/JsonRpcDispatcherCommand.java | 10 +++++++--- .../org/asamk/signal/commands/ReceiveCommand.java | 12 ++++++++---- 8 files changed, 51 insertions(+), 20 deletions(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java b/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java index 6450f1f8..3b3b375a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java +++ b/lib/src/main/java/org/asamk/signal/manager/SignalDependencies.java @@ -40,6 +40,8 @@ public class SignalDependencies { private final ExecutorService executor; private final SignalSessionLock sessionLock; + private boolean allowStories = true; + private SignalServiceAccountManager accountManager; private GroupsV2Api groupsV2Api; private GroupsV2Operations groupsV2Operations; @@ -72,6 +74,14 @@ public class SignalDependencies { public void resetAfterAddressChange() { this.messageSender = null; this.cipher = null; + getSignalWebSocket().forceNewWebSockets(); + } + + /** + * This method needs to be called before the first websocket is created + */ + public void setAllowStories(final boolean allowStories) { + this.allowStories = allowStories; } public ServiceEnvironmentConfig getServiceEnvironmentConfig() { @@ -135,7 +145,7 @@ public class SignalDependencies { Optional.of(credentialsProvider), userAgent, healthMonitor, - true); + allowStories); } @Override @@ -145,7 +155,7 @@ public class SignalDependencies { Optional.empty(), userAgent, healthMonitor, - true); + allowStories); } }; signalWebSocket = new SignalWebSocket(webSocketFactory); diff --git a/lib/src/main/java/org/asamk/signal/manager/api/ReceiveConfig.java b/lib/src/main/java/org/asamk/signal/manager/api/ReceiveConfig.java index bf5f1d99..e9108d12 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/ReceiveConfig.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/ReceiveConfig.java @@ -1,3 +1,3 @@ package org.asamk.signal.manager.api; -public record ReceiveConfig(boolean ignoreAttachments, boolean sendReadReceipts) {} +public record ReceiveConfig(boolean ignoreAttachments, boolean ignoreStories, boolean sendReadReceipts) {} diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java index 7ae9aa45..36cd76a3 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java @@ -110,7 +110,6 @@ public class AccountHelper { // TODO check and update remote storage context.getUnidentifiedAccessHelper().rotateSenderCertificates(); dependencies.resetAfterAddressChange(); - dependencies.getSignalWebSocket().forceNewWebSockets(); context.getAccountFileUpdater().updateAccountIdentifiers(account.getNumber(), account.getAci()); } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java index 09ca1a40..5dca96ea 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/ReceiveHelper.java @@ -9,6 +9,7 @@ import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.messageCache.CachedMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.whispersystems.signalservice.api.SignalWebSocket; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState; import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException; @@ -35,7 +36,7 @@ public class ReceiveHelper { private final SignalDependencies dependencies; private final Context context; - private ReceiveConfig receiveConfig = new ReceiveConfig(false, false); + private ReceiveConfig receiveConfig = new ReceiveConfig(false, false, false); private boolean needsToRetryFailedMessages = false; private boolean hasCaughtUpWithOldMessages = false; private boolean isWaitingForMessage = false; @@ -51,6 +52,7 @@ public class ReceiveHelper { public void setReceiveConfig(final ReceiveConfig receiveConfig) { this.receiveConfig = receiveConfig; + dependencies.setAllowStories(!receiveConfig.ignoreStories()); } public void setNeedsToRetryFailedMessages(final boolean needsToRetryFailedMessages) { @@ -104,25 +106,24 @@ public class ReceiveHelper { signalWebSocket.connect(); try { - receiveMessagesInternal(timeout, returnOnTimeout, handler, queuedActions); + receiveMessagesInternal(signalWebSocket, timeout, returnOnTimeout, handler, queuedActions); } finally { hasCaughtUpWithOldMessages = false; handleQueuedActions(queuedActions.keySet()); queuedActions.clear(); - dependencies.getSignalWebSocket().disconnect(); + signalWebSocket.disconnect(); webSocketStateDisposable.dispose(); shouldStop = false; } } private void receiveMessagesInternal( + final SignalWebSocket signalWebSocket, Duration timeout, boolean returnOnTimeout, Manager.ReceiveMessageHandler handler, final Map queuedActions ) throws IOException { - final var signalWebSocket = dependencies.getSignalWebSocket(); - var backOffCounter = 0; isWaitingForMessage = false; diff --git a/man/signal-cli.1.adoc b/man/signal-cli.1.adoc index f1e9e79a..9b6ec2db 100644 --- a/man/signal-cli.1.adoc +++ b/man/signal-cli.1.adoc @@ -359,9 +359,14 @@ In json mode this is outputted as one json object per line. *-t* TIMEOUT, *--timeout* TIMEOUT:: Number of seconds to wait for new messages (negative values disable timeout). Default is 5 seconds. + *--ignore-attachments*:: Don’t download attachments of received messages. +*--ignore-stories*:: +Don’t receive story messages from the server. + + *--send-read-receipts*:: Send read receipts for all incoming data messages (in addition to the default delivery receipts) @@ -639,6 +644,9 @@ See signal-cli-jsonrpc (5) for info on the JSON-RPC interface. *--ignore-attachments*:: Don’t download attachments of received messages. +*--ignore-stories*:: +Don’t receive story messages from the server. + *--send-read-receipts*:: Send read receipts for all incoming data messages (in addition to the default delivery receipts) diff --git a/src/main/java/org/asamk/signal/commands/DaemonCommand.java b/src/main/java/org/asamk/signal/commands/DaemonCommand.java index cec7cd03..01d0326f 100644 --- a/src/main/java/org/asamk/signal/commands/DaemonCommand.java +++ b/src/main/java/org/asamk/signal/commands/DaemonCommand.java @@ -79,6 +79,9 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand { subparser.addArgument("--ignore-attachments") .help("Don’t download attachments of received messages.") .action(Arguments.storeTrue()); + subparser.addArgument("--ignore-stories") + .help("Don’t receive story messages from the server.") + .action(Arguments.storeTrue()); subparser.addArgument("--send-read-receipts") .help("Send read receipts for all incoming data messages (in addition to the default delivery receipts)") .action(Arguments.storeTrue()); @@ -97,9 +100,10 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand { final var noReceiveStdOut = Boolean.TRUE.equals(ns.getBoolean("no-receive-stdout")); final var receiveMode = ns.get("receive-mode"); final var ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments")); - final boolean sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); + final var ignoreStories = Boolean.TRUE.equals(ns.getBoolean("ignore-stories")); + final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); - m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, sendReadReceipts)); + m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts)); addDefaultReceiveHandler(m, noReceiveStdOut ? null : outputWriter, receiveMode != ReceiveMode.ON_START); final Channel inheritedChannel; @@ -160,9 +164,10 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand { final var noReceiveStdOut = Boolean.TRUE.equals(ns.getBoolean("no-receive-stdout")); final var receiveMode = ns.get("receive-mode"); final var ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments")); - final boolean sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); + final var ignoreStories = Boolean.TRUE.equals(ns.getBoolean("ignore-stories")); + final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); - final var receiveConfig = new ReceiveConfig(ignoreAttachments, sendReadReceipts); + final var receiveConfig = new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts); c.getManagers().forEach(m -> { m.setReceiveConfig(receiveConfig); addDefaultReceiveHandler(m, noReceiveStdOut ? null : outputWriter, receiveMode != ReceiveMode.ON_START); diff --git a/src/main/java/org/asamk/signal/commands/JsonRpcDispatcherCommand.java b/src/main/java/org/asamk/signal/commands/JsonRpcDispatcherCommand.java index ef33a6e8..34961bd3 100644 --- a/src/main/java/org/asamk/signal/commands/JsonRpcDispatcherCommand.java +++ b/src/main/java/org/asamk/signal/commands/JsonRpcDispatcherCommand.java @@ -34,6 +34,9 @@ public class JsonRpcDispatcherCommand implements LocalCommand { subparser.addArgument("--ignore-attachments") .help("Don’t download attachments of received messages.") .action(Arguments.storeTrue()); + subparser.addArgument("--ignore-stories") + .help("Don’t receive story messages from the server.") + .action(Arguments.storeTrue()); subparser.addArgument("--send-read-receipts") .help("Send read receipts for all incoming data messages (in addition to the default delivery receipts)") .action(Arguments.storeTrue()); @@ -48,9 +51,10 @@ public class JsonRpcDispatcherCommand implements LocalCommand { public void handleCommand( final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { - final boolean ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments")); - final boolean sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); - m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, sendReadReceipts)); + final var ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments")); + final var ignoreStories = Boolean.TRUE.equals(ns.getBoolean("ignore-stories")); + final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); + m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts)); final var jsonOutputWriter = (JsonWriter) outputWriter; final Supplier lineSupplier = IOUtils.getLineSupplier(new InputStreamReader(System.in, diff --git a/src/main/java/org/asamk/signal/commands/ReceiveCommand.java b/src/main/java/org/asamk/signal/commands/ReceiveCommand.java index 68292557..4d5bdff0 100644 --- a/src/main/java/org/asamk/signal/commands/ReceiveCommand.java +++ b/src/main/java/org/asamk/signal/commands/ReceiveCommand.java @@ -40,6 +40,9 @@ public class ReceiveCommand implements LocalCommand { subparser.addArgument("--ignore-attachments") .help("Don’t download attachments of received messages.") .action(Arguments.storeTrue()); + subparser.addArgument("--ignore-stories") + .help("Don’t receive story messages from the server.") + .action(Arguments.storeTrue()); subparser.addArgument("--send-read-receipts") .help("Send read receipts for all incoming data messages (in addition to the default delivery receipts)") .action(Arguments.storeTrue()); @@ -54,10 +57,11 @@ public class ReceiveCommand implements LocalCommand { public void handleCommand( final Namespace ns, final Manager m, final OutputWriter outputWriter ) throws CommandException { - double timeout = ns.getDouble("timeout"); - boolean ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments")); - boolean sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); - m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, sendReadReceipts)); + final var timeout = ns.getDouble("timeout"); + final var ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments")); + final var ignoreStories = Boolean.TRUE.equals(ns.getBoolean("ignore-stories")); + final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); + m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts)); try { final var handler = outputWriter instanceof JsonWriter ? new JsonReceiveMessageHandler(m, (JsonWriter) outputWriter) : new ReceiveMessageHandler(m, (PlainTextWriter) outputWriter); From 47b6fe7dbe4f174909cabcdd0e0526a207950816 Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 19:09:39 +0200 Subject: [PATCH 038/713] Enable story capability Only receiving is supported --- .../java/org/asamk/signal/manager/config/ServiceConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java b/lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java index 5698d6f8..72b089f9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java +++ b/lib/src/main/java/org/asamk/signal/manager/config/ServiceConfig.java @@ -38,7 +38,7 @@ public class ServiceConfig { true, true, true, - false, + true, false, false); From e4a4788d5efde9c68c2d5464adddde4c94dd81a8 Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 20:09:03 +0200 Subject: [PATCH 039/713] Add native graalvm build to release --- .github/workflows/ci.yml | 3 ++- .github/workflows/repackage-native-libs.yml | 20 ++++++++++++++++++-- build.gradle.kts | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 74a402ab..a6c3f08c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,10 +38,11 @@ jobs: version: 'latest' java-version: '17' components: 'native-image' + github-token: ${{ secrets.GITHUB_TOKEN }} - name: Build with Gradle run: ./gradlew --no-daemon nativeCompile - name: Archive production artifacts uses: actions/upload-artifact@v3 with: - name: signal-cli-archive-native + name: signal-cli-native path: build/native/nativeCompile/signal-cli diff --git a/.github/workflows/repackage-native-libs.yml b/.github/workflows/repackage-native-libs.yml index 8ebba79e..3b8de939 100644 --- a/.github/workflows/repackage-native-libs.yml +++ b/.github/workflows/repackage-native-libs.yml @@ -10,7 +10,7 @@ jobs: ci_wf: uses: AsamK/signal-cli/.github/workflows/ci.yml@master - # ${{ github.repository }} not accpeted here + # ${{ github.repository }} not accepted here lib_to_jar: @@ -31,7 +31,7 @@ jobs: run: | #echo ${GITHUB_REF#refs/tag/} tree . - mv ./$(ls */ -d | tail -n1)/*.tar.gz . + mv ./$(ls signal-cli-archive-*/ -d | tail -n1)/*.tar.gz . ver=$(ls ./*.tar.gz | xargs basename | sed -E 's/signal-cli-(.*).tar.gz/\1/') echo $ver echo "::set-output name=signal_cli_version::${ver}" @@ -57,6 +57,12 @@ jobs: done tree . + - name: Compress native app + env: + SIGNAL_CLI_VER: ${{ steps.cli_ver.outputs.signal_cli_version }} + run: | + tar -czf signal-cli-${SIGNAL_CLI_VER}-Linux-native.tar.gz -C signal-cli-native signal-cli + - name: Replace Windows lib env: SIGNAL_CLI_VER: ${{ steps.cli_ver.outputs.signal_cli_version }} @@ -96,6 +102,16 @@ jobs: asset_name: signal-cli-${{ steps.cli_ver.outputs.signal_cli_version }}-Linux.tar.gz asset_content_type: application/x-compressed-tar # .tar.gz + - name: Upload Linux native archive + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: signal-cli-${{ steps.cli_ver.outputs.signal_cli_version }}-Linux-native.tar.gz + asset_name: signal-cli-${{ steps.cli_ver.outputs.signal_cli_version }}-Linux-native.tar.gz + asset_content_type: application/x-compressed-tar # .tar.gz + - name: Upload windows archive uses: actions/upload-release-asset@v1 env: diff --git a/build.gradle.kts b/build.gradle.kts index 4e9fcfc6..bf1ca15e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { application eclipse `check-lib-versions` - id("org.graalvm.buildtools.native") version "0.9.15" + id("org.graalvm.buildtools.native") version "0.9.16" } version = "0.11.3" From eb71fd1a5abff34af9e8d6e43a4c13885822856e Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 20:34:42 +0200 Subject: [PATCH 040/713] Add java 19 to CI --- .github/workflows/ci.yml | 2 +- .github/workflows/repackage-native-libs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6c3f08c..f336c480 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ '17', '18' ] + java: [ '17', '19' ] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/repackage-native-libs.yml b/.github/workflows/repackage-native-libs.yml index 3b8de939..6d334ecf 100644 --- a/.github/workflows/repackage-native-libs.yml +++ b/.github/workflows/repackage-native-libs.yml @@ -151,7 +151,7 @@ jobs: shell: bash # Explicit for windows env: - JAVA_VERSION: 18 + JAVA_VERSION: 19 steps: From af324eeca59d10a38214755d5e1349e90a5a44b3 Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 19 Oct 2022 20:35:53 +0200 Subject: [PATCH 041/713] Bump version --- CHANGELOG.md | 13 +++++++++++++ build.gradle.kts | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2dfae92..b16eb894 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ ## [Unreleased] +## [0.11.4] - 2022-10-19 + +### Added +- Approve/Refuse group join requests, using same interface as adding/removing members +- Add --ignore-stories flag to prevent receiving story messages + +### Fixed +- Fixed issue with receiving messages that can't be decrypted +- Do not discard incoming group join messages + +### Improved +- Add code to receive new PNI after change number + ## [0.11.3] - 2022-10-07 ### Fixed diff --git a/build.gradle.kts b/build.gradle.kts index bf1ca15e..2bf8eede 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("org.graalvm.buildtools.native") version "0.9.16" } -version = "0.11.3" +version = "0.11.4" java { sourceCompatibility = JavaVersion.VERSION_17 From 2a1be0bd85547a9308224ef44917a74186ec7b7b Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 21 Oct 2022 10:25:57 +0200 Subject: [PATCH 042/713] Improve graalvm native build wih resource autodetect --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2bf8eede..b88a6bf8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,8 +20,8 @@ application { graalvmNative { binaries { this["main"].run { + resources.autodetect() configurationFileDirectories.from(file("graalvm-config-dir")) - buildArgs.add("--report-unsupported-elements-at-runtime") } } } From ae221e0447e163f02ad5a198586ce998136a55e7 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 21 Oct 2022 10:33:46 +0200 Subject: [PATCH 043/713] Disable graalvm toolchain detection if GRAALVM_HOME is set --- build.gradle.kts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index b88a6bf8..49ff1f46 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,6 +22,13 @@ graalvmNative { this["main"].run { resources.autodetect() configurationFileDirectories.from(file("graalvm-config-dir")) + if (System.getenv("GRAALVM_HOME") == null) { + javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(17)) + }) + } else { + toolchainDetection.set(false) + } } } } From e450f36e813250f3a2a78ff13970b34d01ab1924 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 21 Oct 2022 16:22:09 +0200 Subject: [PATCH 044/713] Don't output caption if it's empty --- .../main/java/org/asamk/signal/manager/api/MessageEnvelope.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java index 2140d413..2eb0546a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java @@ -289,7 +289,7 @@ public record MessageEnvelope( a.getSize().map(Integer::longValue), a.getPreview(), Optional.empty(), - a.getCaption(), + a.getCaption().map(c -> c.isEmpty() ? null : c), a.getWidth() == 0 ? Optional.empty() : Optional.of(a.getWidth()), a.getHeight() == 0 ? Optional.empty() : Optional.of(a.getHeight()), a.getVoiceNote(), From b9eee539bdaa6eb27b9acd4e829e1eaeeb6e1c6c Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 16 Oct 2022 19:17:43 +0200 Subject: [PATCH 045/713] Add PNI to recipients --- .idea/codeStyles/Project.xml | 3 + lib/build.gradle.kts | 6 + .../helper/IncomingMessageHandler.java | 71 +++- .../manager/storage/AccountDatabase.java | 10 +- .../signal/manager/storage/SignalAccount.java | 5 +- .../recipients/MergeRecipientHelper.java | 140 ++++++++ .../storage/recipients/RecipientAddress.java | 60 ++++ .../storage/recipients/RecipientStore.java | 178 +++++----- .../recipients/RecipientWithAddress.java | 3 + .../recipients/MergeRecipientHelperTest.java | 330 ++++++++++++++++++ 10 files changed, 696 insertions(+), 110 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/storage/recipients/MergeRecipientHelper.java create mode 100644 lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientWithAddress.java create mode 100644 lib/src/test/java/org/asamk/signal/manager/storage/recipients/MergeRecipientHelperTest.java diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index bb65b3e9..adf3548b 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -54,6 +54,9 @@