diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 0bfd1cdf..2c7e16ef 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -2319,7 +2319,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"getAnnouncementGroup","parameterTypes":[] }, {"name":"getAttachmentBackfill","parameterTypes":[] }, {"name":"getChangeNumber","parameterTypes":[] }, {"name":"getDeleteSync","parameterTypes":[] }, {"name":"getGiftBadges","parameterTypes":[] }, {"name":"getPaymentActivation","parameterTypes":[] }, {"name":"getPni","parameterTypes":[] }, {"name":"getSenderKey","parameterTypes":[] }, {"name":"getStorage","parameterTypes":[] }, {"name":"getStorageServiceEncryptionV2","parameterTypes":[] }, {"name":"getStories","parameterTypes":[] }, {"name":"getVersionedExpirationTimer","parameterTypes":[] }] + "methods":[{"name":"getAnnouncementGroup","parameterTypes":[] }, {"name":"getAttachmentBackfill","parameterTypes":[] }, {"name":"getChangeNumber","parameterTypes":[] }, {"name":"getDeleteSync","parameterTypes":[] }, {"name":"getGiftBadges","parameterTypes":[] }, {"name":"getPaymentActivation","parameterTypes":[] }, {"name":"getPni","parameterTypes":[] }, {"name":"getSenderKey","parameterTypes":[] }, {"name":"getSpqr","parameterTypes":[] }, {"name":"getStorage","parameterTypes":[] }, {"name":"getStorageServiceEncryptionV2","parameterTypes":[] }, {"name":"getStories","parameterTypes":[] }, {"name":"getVersionedExpirationTimer","parameterTypes":[] }] }, { "name":"org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest", @@ -3002,6 +3002,7 @@ { "name":"org.whispersystems.signalservice.internal.storage.protos.AccountRecord", "allDeclaredFields":true, + "fields":[{"name":"avatarColor"}, {"name":"avatarUrlPath"}, {"name":"backupSubscriberData"}, {"name":"backupTier"}, {"name":"backupTierHistory"}, {"name":"displayBadgesOnProfile"}, {"name":"familyName"}, {"name":"givenName"}, {"name":"hasBackup"}, {"name":"hasCompletedUsernameOnboarding"}, {"name":"hasSeenGroupStoryEducationSheet"}, {"name":"hasSetMyStoriesPrivacy"}, {"name":"hasViewedOnboardingStory"}, {"name":"keepMutedChatsArchived"}, {"name":"linkPreviews"}, {"name":"noteToSelfArchived"}, {"name":"noteToSelfMarkedUnread"}, {"name":"notificationProfileManualOverride"}, {"name":"payments"}, {"name":"phoneNumberSharingMode"}, {"name":"pinnedConversations"}, {"name":"preferContactAvatars"}, {"name":"preferredReactionEmoji"}, {"name":"primarySendsSms"}, {"name":"profileKey"}, {"name":"readReceipts"}, {"name":"sealedSenderIndicators"}, {"name":"storiesDisabled"}, {"name":"storyViewReceiptsEnabled"}, {"name":"subscriberCurrencyCode"}, {"name":"subscriberId"}, {"name":"subscriptionManuallyCancelled"}, {"name":"typingIndicators"}, {"name":"universalExpireTimer"}, {"name":"unlistedPhoneNumber"}, {"name":"username"}, {"name":"usernameLink"}], "methods":[{"name":"adapter","parameterTypes":[] }, {"name":"unknownFields","parameterTypes":[] }] }, { @@ -3040,6 +3041,7 @@ { "name":"org.whispersystems.signalservice.internal.storage.protos.ContactRecord", "allDeclaredFields":true, + "fields":[{"name":"aci"}, {"name":"archived"}, {"name":"avatarColor"}, {"name":"blocked"}, {"name":"e164"}, {"name":"familyName"}, {"name":"givenName"}, {"name":"hidden"}, {"name":"hideStory"}, {"name":"identityKey"}, {"name":"identityState"}, {"name":"markedUnread"}, {"name":"mutedUntilTimestamp"}, {"name":"nickname"}, {"name":"note"}, {"name":"pni"}, {"name":"pniSignatureVerified"}, {"name":"profileKey"}, {"name":"systemFamilyName"}, {"name":"systemGivenName"}, {"name":"systemNickname"}, {"name":"unregisteredAtTimestamp"}, {"name":"username"}, {"name":"whitelisted"}], "methods":[{"name":"adapter","parameterTypes":[] }, {"name":"unknownFields","parameterTypes":[] }] }, { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fec44a43..d17ed6be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } slf4j-jul = { module = "org.slf4j:jul-to-slf4j", version.ref = "slf4j" } logback = "ch.qos.logback:logback-classic:1.5.18" -signalservice = "com.github.turasa:signal-service-java:2.15.3_unofficial_127" +signalservice = "com.github.turasa:signal-service-java:2.15.3_unofficial_128" sqlite = "org.xerial:sqlite-jdbc:3.50.2.0" hikari = "com.zaxxer:HikariCP:6.3.0" junit-jupiter = "org.junit.jupiter:junit-jupiter:5.13.2" 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 587fc89b..90cea121 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 @@ -28,10 +28,9 @@ public class ServiceConfig { public static final long UNREGISTERED_LIFESPAN = TimeUnit.DAYS.toMillis(30); public static AccountAttributes.Capabilities getCapabilities(boolean isPrimaryDevice) { - final var deleteSync = !isPrimaryDevice; - final var storageEncryptionV2 = !isPrimaryDevice; final var attachmentBackfill = !isPrimaryDevice; - return new AccountAttributes.Capabilities(true, deleteSync, true, storageEncryptionV2, attachmentBackfill); + final var spqr = !isPrimaryDevice; + return new AccountAttributes.Capabilities(true, true, attachmentBackfill, spqr); } public static ServiceEnvironmentConfig getServiceEnvironmentConfig( diff --git a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java index 726d0aaf..2339d261 100644 --- a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java @@ -91,6 +91,7 @@ import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.MimeUtils; import org.asamk.signal.manager.util.PhoneNumberFormatter; import org.asamk.signal.manager.util.StickerUtils; +import org.signal.core.util.Base64; import org.signal.libsignal.protocol.InvalidMessageException; import org.signal.libsignal.usernames.BaseUsernameException; import org.slf4j.Logger; @@ -100,6 +101,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServicePreview; import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage; import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage; +import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId.ACI; import org.whispersystems.signalservice.api.push.ServiceId.PNI; @@ -113,10 +115,12 @@ import org.whispersystems.signalservice.internal.util.Hex; import org.whispersystems.signalservice.internal.util.Util; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; @@ -474,14 +478,32 @@ public class ManagerImpl implements Manager { logger.debug("Failed to decrypt device name, maybe plain text?", e); } } + final var createdAt = getPlaintextCreatedAt(d); return new Device(d.getId(), deviceName, - d.getCreated(), + createdAt == null ? 0 : createdAt, d.getLastSeen(), d.getId() == account.getDeviceId()); }).toList(); } + private Long getPlaintextCreatedAt(DeviceInfo d) { + final var DECRYPTION_INFO = "deviceCreatedAt"; + var identityKey = account.getAciIdentityKeyPair().getPrivateKey(); + try { + + var associatedData = new ByteArrayOutputStream(); + associatedData.write(d.getId()); + associatedData.write(ByteBuffer.allocate(4).putInt(d.getRegistrationId()).array()); + var createdAtPlaintext = identityKey.open(Base64.decode(d.getCreatedAtCiphertext() + .getBytes(StandardCharsets.UTF_8)), DECRYPTION_INFO, associatedData.toByteArray()); + return ByteBuffer.wrap(createdAtPlaintext).getLong(); + } catch (Exception e) { + logger.warn("Failed while reading the protobuf.", e); + return null; + } + } + @Override public void removeLinkedDevices(int deviceId) throws IOException, NotPrimaryDeviceException { if (!account.isPrimaryDevice()) { diff --git a/lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java b/lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java index 0bc895cb..222751e4 100644 --- a/lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java +++ b/lib/src/main/java/org/asamk/signal/manager/internal/SignalDependencies.java @@ -328,7 +328,8 @@ public class SignalDependencies { executor, ServiceConfig.MAX_ENVELOPE_SIZE, () -> true, - UsePqRatchet.NO)); + UsePqRatchet.NO, + Optional.empty())); } public List getSecureValueRecovery() { diff --git a/src/main/java/org/asamk/signal/BaseConfig.java b/src/main/java/org/asamk/signal/BaseConfig.java index 730485bc..7ff5612f 100644 --- a/src/main/java/org/asamk/signal/BaseConfig.java +++ b/src/main/java/org/asamk/signal/BaseConfig.java @@ -8,7 +8,7 @@ public class BaseConfig { public static final String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion(); static final String USER_AGENT_SIGNAL_ANDROID = Optional.ofNullable(System.getenv("SIGNAL_CLI_USER_AGENT")) - .orElse("Signal-Android/7.47.1"); + .orElse("Signal-Android/7.56.6"); static final String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null ? "signal-cli" : PROJECT_NAME + "/" + PROJECT_VERSION;