├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── constants.gradle.kts ├── core-util-jvm ├── .gitignore ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── org │ │ └── signal │ │ └── core │ │ └── util │ │ ├── Base64.kt │ │ ├── Base64Tools.java │ │ ├── BidiUtil.kt │ │ ├── Bitmask.java │ │ ├── ByteExtensions.kt │ │ ├── CryptoUtil.java │ │ ├── DoubleExtensions.kt │ │ ├── DurationExtensions.kt │ │ ├── E164Util.kt │ │ ├── FloatExtensions.kt │ │ ├── FlowExtensions.kt │ │ ├── Hex.java │ │ ├── InputStreamExtensions.kt │ │ ├── LongExtensions.kt │ │ ├── OptionalExtensions.kt │ │ ├── OutputStreamExtensions.kt │ │ ├── ProtoExtensions.kt │ │ ├── ResettableLazy.kt │ │ ├── SetUtil.java │ │ ├── Stopwatch.kt │ │ ├── StreamUtil.java │ │ ├── StringExtensions.kt │ │ ├── concurrent │ │ ├── CascadingFuture.java │ │ ├── FutureMapTransformer.java │ │ ├── FutureTransformers.java │ │ ├── JvmRxExtensions.kt │ │ ├── ListenableFuture.java │ │ └── SettableFuture.java │ │ ├── logging │ │ ├── CompoundLogger.kt │ │ ├── Log.kt │ │ ├── LoggingExtensions.kt │ │ ├── NoopLogger.kt │ │ └── Scrubber.kt │ │ ├── stream │ │ ├── LimitedInputStream.kt │ │ ├── MacInputStream.kt │ │ ├── MacOutputStream.kt │ │ ├── NonClosingOutputStream.kt │ │ ├── NullOutputStream.kt │ │ └── TailerInputStream.kt │ │ └── test │ │ └── TestUtils.kt │ └── test │ └── java │ └── org │ └── signal │ └── core │ └── util │ ├── Base64Test.kt │ ├── E164UtilTest.kt │ ├── FlowExtensionsTests.kt │ ├── ResettableLazyTests.kt │ ├── VarInt32Tests.kt │ ├── logging │ ├── LogTest.kt │ └── ScrubberTest.kt │ └── stream │ ├── LimitedInputStreamTest.kt │ ├── MacInputStreamTest.kt │ ├── MacOutputStreamTest.kt │ └── TailerInputStreamTest.kt ├── gradle ├── libs.versions.toml ├── test-libs.versions.toml ├── verification-metadata.xml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── service ├── .gitignore ├── build.gradle.kts ├── lint.xml └── src │ ├── main │ ├── java │ │ ├── com │ │ │ └── squareup │ │ │ │ └── wire │ │ │ │ └── internal │ │ │ │ └── CountNonDefault.kt │ │ └── org │ │ │ └── whispersystems │ │ │ ├── signalservice │ │ │ ├── api │ │ │ │ ├── AccountEntropyPool.kt │ │ │ │ ├── CancelationException.java │ │ │ │ ├── ContentTooLargeException.java │ │ │ │ ├── InvalidMessageStructureException.java │ │ │ │ ├── InvalidPreKeyException.kt │ │ │ │ ├── NetworkResult.kt │ │ │ │ ├── NetworkResultUtil.kt │ │ │ │ ├── SignalServiceAccountDataStore.java │ │ │ │ ├── SignalServiceAccountManager.java │ │ │ │ ├── SignalServiceDataStore.java │ │ │ │ ├── SignalServiceKyberPreKeyStore.kt │ │ │ │ ├── SignalServiceMessageReceiver.java │ │ │ │ ├── SignalServiceMessageSender.java │ │ │ │ ├── SignalServicePreKeyStore.kt │ │ │ │ ├── SignalServiceSenderKeyStore.java │ │ │ │ ├── SignalServiceSessionStore.java │ │ │ │ ├── SignalSessionLock.java │ │ │ │ ├── SignalUrlExtensions.kt │ │ │ │ ├── SvrNoDataException.java │ │ │ │ ├── account │ │ │ │ │ ├── AccountApi.kt │ │ │ │ │ ├── AccountAttributes.kt │ │ │ │ │ ├── ChangePhoneNumberRequest.java │ │ │ │ │ ├── PniKeyDistributionRequest.java │ │ │ │ │ ├── PreKeyCollection.kt │ │ │ │ │ └── PreKeyUpload.kt │ │ │ │ ├── archive │ │ │ │ │ ├── ArchiveApi.kt │ │ │ │ │ ├── ArchiveCredentialPresentation.kt │ │ │ │ │ ├── ArchiveGetBackupInfoResponse.kt │ │ │ │ │ ├── ArchiveGetMediaItemsResponse.kt │ │ │ │ │ ├── ArchiveMediaRequest.kt │ │ │ │ │ ├── ArchiveMediaResponse.kt │ │ │ │ │ ├── ArchiveMediaUploadFormStatusCodes.kt │ │ │ │ │ ├── ArchiveServiceAccess.kt │ │ │ │ │ ├── ArchiveServiceAccessPair.kt │ │ │ │ │ ├── ArchiveServiceCredential.kt │ │ │ │ │ ├── ArchiveServiceCredentialsResponse.kt │ │ │ │ │ ├── ArchiveSetBackupIdRequest.kt │ │ │ │ │ ├── ArchiveSetPublicKeyRequest.kt │ │ │ │ │ ├── BatchArchiveMediaRequest.kt │ │ │ │ │ ├── BatchArchiveMediaResponse.kt │ │ │ │ │ ├── DeleteArchivedMediaRequest.kt │ │ │ │ │ └── GetArchiveCdnCredentialsResponse.kt │ │ │ │ ├── attachment │ │ │ │ │ ├── AttachmentApi.kt │ │ │ │ │ ├── AttachmentDownloadResult.kt │ │ │ │ │ └── AttachmentUploadResult.kt │ │ │ │ ├── backup │ │ │ │ │ ├── BackupId.kt │ │ │ │ │ ├── BackupKey.kt │ │ │ │ │ ├── MediaId.kt │ │ │ │ │ ├── MediaName.kt │ │ │ │ │ ├── MediaRootBackupKey.kt │ │ │ │ │ └── MessageBackupKey.kt │ │ │ │ ├── calling │ │ │ │ │ └── CallingApi.kt │ │ │ │ ├── cds │ │ │ │ │ ├── CdsApi.kt │ │ │ │ │ └── CdsiV2Service.java │ │ │ │ ├── certificate │ │ │ │ │ └── CertificateApi.kt │ │ │ │ ├── crypto │ │ │ │ │ ├── AttachmentCipherInputStream.java │ │ │ │ │ ├── AttachmentCipherOutputStream.java │ │ │ │ │ ├── AttachmentCipherStreamUtil.kt │ │ │ │ │ ├── ContentHint.java │ │ │ │ │ ├── Crypto.kt │ │ │ │ │ ├── DigestingOutputStream.java │ │ │ │ │ ├── EnvelopeContent.java │ │ │ │ │ ├── EnvelopeMetadata.kt │ │ │ │ │ ├── HmacSIV.java │ │ │ │ │ ├── IncrementalMacAdditionalValidationsInputStream.kt │ │ │ │ │ ├── InvalidCiphertextException.java │ │ │ │ │ ├── NoCipherOutputStream.java │ │ │ │ │ ├── ProfileCipher.java │ │ │ │ │ ├── ProfileCipherInputStream.java │ │ │ │ │ ├── ProfileCipherOutputStream.java │ │ │ │ │ ├── SealedSenderAccess.kt │ │ │ │ │ ├── SignalGroupCipher.java │ │ │ │ │ ├── SignalGroupSessionBuilder.java │ │ │ │ │ ├── SignalSealedSessionCipher.java │ │ │ │ │ ├── SignalServiceCipher.java │ │ │ │ │ ├── SignalServiceCipherResult.kt │ │ │ │ │ ├── SignalSessionBuilder.java │ │ │ │ │ ├── SignalSessionCipher.java │ │ │ │ │ ├── SkippingOutputStream.java │ │ │ │ │ ├── UnidentifiedAccess.java │ │ │ │ │ └── UntrustedIdentityException.java │ │ │ │ ├── donations │ │ │ │ │ ├── BoostReceiptCredentialRequestJson.java │ │ │ │ │ ├── DonationsApi.kt │ │ │ │ │ ├── PayPalConfirmOneTimePaymentIntentPayload.java │ │ │ │ │ ├── PayPalCreateOneTimePaymentIntentPayload.java │ │ │ │ │ ├── PayPalCreatePaymentMethodPayload.java │ │ │ │ │ ├── ReceiptCredentialRequestJson.java │ │ │ │ │ ├── ReceiptCredentialResponseJson.java │ │ │ │ │ ├── RedeemArchivesReceiptRequest.kt │ │ │ │ │ ├── RedeemDonationReceiptRequest.java │ │ │ │ │ └── StripeOneTimePaymentIntentPayload.java │ │ │ │ ├── groupsv2 │ │ │ │ │ ├── ChangeSetModifier.java │ │ │ │ │ ├── ClientZkOperations.java │ │ │ │ │ ├── CredentialResponse.java │ │ │ │ │ ├── DecryptChangeVerificationMode.kt │ │ │ │ │ ├── DecryptedGroupChangeActionsBuilderChangeSetModifier.kt │ │ │ │ │ ├── DecryptedGroupChangeLog.kt │ │ │ │ │ ├── DecryptedGroupExtensions.kt │ │ │ │ │ ├── DecryptedGroupResponse.kt │ │ │ │ │ ├── DecryptedGroupUtil.java │ │ │ │ │ ├── GroupCandidate.java │ │ │ │ │ ├── GroupChangeActionsBuilderChangeSetModifier.kt │ │ │ │ │ ├── GroupChangeReconstruct.java │ │ │ │ │ ├── GroupChangeUtil.java │ │ │ │ │ ├── GroupHistoryPage.kt │ │ │ │ │ ├── GroupLinkNotActiveException.java │ │ │ │ │ ├── GroupSendEndorsements.kt │ │ │ │ │ ├── GroupsV2Api.java │ │ │ │ │ ├── GroupsV2ApiHelper.kt │ │ │ │ │ ├── GroupsV2AuthorizationString.java │ │ │ │ │ ├── GroupsV2Operations.java │ │ │ │ │ ├── InvalidGroupStateException.java │ │ │ │ │ ├── NoCredentialForRedemptionTimeException.java │ │ │ │ │ ├── NotAbleToApplyGroupV2ChangeException.java │ │ │ │ │ ├── ReceivedGroupSendEndorsements.kt │ │ │ │ │ └── TemporalCredential.java │ │ │ │ ├── kbs │ │ │ │ │ ├── KbsData.java │ │ │ │ │ ├── MasterKey.java │ │ │ │ │ ├── PinHashUtil.kt │ │ │ │ │ ├── PinString.java │ │ │ │ │ └── PinValidityChecker.java │ │ │ │ ├── keys │ │ │ │ │ ├── KeysApi.kt │ │ │ │ │ └── OneTimePreKeyCounts.java │ │ │ │ ├── link │ │ │ │ │ ├── LinkDeviceApi.kt │ │ │ │ │ ├── LinkedDeviceVerificationCodeResponse.kt │ │ │ │ │ ├── SetDeviceNameRequest.kt │ │ │ │ │ ├── SetLinkedDeviceTransferArchiveRequest.kt │ │ │ │ │ ├── TransferArchiveError.kt │ │ │ │ │ └── WaitForLinkedDeviceResponse.kt │ │ │ │ ├── message │ │ │ │ │ ├── MessageApi.kt │ │ │ │ │ └── SpamTokenMessage.kt │ │ │ │ ├── messages │ │ │ │ │ ├── EnvelopeContentValidator.kt │ │ │ │ │ ├── EnvelopeResponse.kt │ │ │ │ │ ├── SendMessageResult.java │ │ │ │ │ ├── SignalServiceAttachment.kt │ │ │ │ │ ├── SignalServiceAttachmentPointer.kt │ │ │ │ │ ├── SignalServiceAttachmentRemoteId.kt │ │ │ │ │ ├── SignalServiceAttachmentStream.kt │ │ │ │ │ ├── SignalServiceContent.kt │ │ │ │ │ ├── SignalServiceDataMessage.kt │ │ │ │ │ ├── SignalServiceEditMessage.kt │ │ │ │ │ ├── SignalServiceEnvelope.kt │ │ │ │ │ ├── SignalServiceGroup.java │ │ │ │ │ ├── SignalServiceGroupContext.java │ │ │ │ │ ├── SignalServiceGroupV2.java │ │ │ │ │ ├── SignalServiceMetadata.java │ │ │ │ │ ├── SignalServicePniSignatureMessage.java │ │ │ │ │ ├── SignalServicePreview.java │ │ │ │ │ ├── SignalServiceReceiptMessage.java │ │ │ │ │ ├── SignalServiceStickerManifest.java │ │ │ │ │ ├── SignalServiceStickerManifestUpload.java │ │ │ │ │ ├── SignalServiceStoryMessage.java │ │ │ │ │ ├── SignalServiceStoryMessageRecipient.java │ │ │ │ │ ├── SignalServiceTextAttachment.java │ │ │ │ │ ├── SignalServiceTypingMessage.java │ │ │ │ │ ├── calls │ │ │ │ │ │ ├── AnswerMessage.java │ │ │ │ │ │ ├── BusyMessage.java │ │ │ │ │ │ ├── CallingResponse.java │ │ │ │ │ │ ├── HangupMessage.java │ │ │ │ │ │ ├── IceUpdateMessage.java │ │ │ │ │ │ ├── OfferMessage.java │ │ │ │ │ │ ├── OpaqueMessage.java │ │ │ │ │ │ ├── SignalServiceCallMessage.java │ │ │ │ │ │ └── TurnServerInfo.java │ │ │ │ │ ├── multidevice │ │ │ │ │ │ ├── BlockedListMessage.kt │ │ │ │ │ │ ├── ChunkedInputStream.java │ │ │ │ │ │ ├── ChunkedOutputStream.java │ │ │ │ │ │ ├── ConfigurationMessage.java │ │ │ │ │ │ ├── ContactsMessage.java │ │ │ │ │ │ ├── DeviceContact.java │ │ │ │ │ │ ├── DeviceContactAvatar.kt │ │ │ │ │ │ ├── DeviceContactsInputStream.java │ │ │ │ │ │ ├── DeviceContactsOutputStream.java │ │ │ │ │ │ ├── DeviceGroup.java │ │ │ │ │ │ ├── DeviceGroupsInputStream.java │ │ │ │ │ │ ├── DeviceGroupsOutputStream.java │ │ │ │ │ │ ├── DeviceInfo.java │ │ │ │ │ │ ├── KeysMessage.kt │ │ │ │ │ │ ├── MessageRequestResponseMessage.java │ │ │ │ │ │ ├── OutgoingPaymentMessage.java │ │ │ │ │ │ ├── ReadMessage.java │ │ │ │ │ │ ├── RequestMessage.java │ │ │ │ │ │ ├── SentTranscriptMessage.java │ │ │ │ │ │ ├── SignalServiceSyncMessage.java │ │ │ │ │ │ ├── StickerPackOperationMessage.java │ │ │ │ │ │ ├── VerifiedMessage.java │ │ │ │ │ │ ├── VerifyDeviceResponse.java │ │ │ │ │ │ ├── ViewOnceOpenMessage.java │ │ │ │ │ │ └── ViewedMessage.java │ │ │ │ │ └── shared │ │ │ │ │ │ └── SharedContact.java │ │ │ │ ├── payments │ │ │ │ │ ├── Currency.java │ │ │ │ │ ├── CurrencyConversion.java │ │ │ │ │ ├── CurrencyConversions.java │ │ │ │ │ ├── Formatter.java │ │ │ │ │ ├── FormatterOptions.java │ │ │ │ │ ├── Money.java │ │ │ │ │ ├── PaymentsApi.kt │ │ │ │ │ ├── PaymentsConstants.java │ │ │ │ │ └── UnsupportedCurrencyException.java │ │ │ │ ├── profiles │ │ │ │ │ ├── AvatarUploadParams.java │ │ │ │ │ ├── ProfileAndCredential.java │ │ │ │ │ ├── ProfileApi.kt │ │ │ │ │ ├── ProfileRepository.kt │ │ │ │ │ ├── SignalServiceProfile.java │ │ │ │ │ └── SignalServiceProfileWrite.kt │ │ │ │ ├── provisioning │ │ │ │ │ ├── ProvisioningApi.kt │ │ │ │ │ ├── ProvisioningMessage.java │ │ │ │ │ ├── ProvisioningSocket.kt │ │ │ │ │ └── RestoreMethod.kt │ │ │ │ ├── push │ │ │ │ │ ├── ContactTokenDetails.java │ │ │ │ │ ├── DistributionId.java │ │ │ │ │ ├── ServiceId.kt │ │ │ │ │ ├── ServiceIdType.java │ │ │ │ │ ├── ServiceIds.java │ │ │ │ │ ├── SignalServiceAddress.java │ │ │ │ │ ├── SignedPreKeyEntity.java │ │ │ │ │ ├── TrustStore.java │ │ │ │ │ ├── UsernameLinkComponents.kt │ │ │ │ │ └── exceptions │ │ │ │ │ │ ├── AlreadyVerifiedException.kt │ │ │ │ │ │ ├── AuthorizationFailedException.java │ │ │ │ │ │ ├── CdsiInvalidArgumentException.java │ │ │ │ │ │ ├── CdsiInvalidTokenException.java │ │ │ │ │ │ ├── CdsiResourceExhaustedException.java │ │ │ │ │ │ ├── ChallengeRequiredException.kt │ │ │ │ │ │ ├── ConflictException.java │ │ │ │ │ │ ├── ContactManifestMismatchException.java │ │ │ │ │ │ ├── DeprecatedVersionException.java │ │ │ │ │ │ ├── ExpectationFailedException.java │ │ │ │ │ │ ├── ExternalServiceFailureException.kt │ │ │ │ │ │ ├── HttpConflictException.kt │ │ │ │ │ │ ├── ImpossiblePhoneNumberException.java │ │ │ │ │ │ ├── IncorrectCodeException.kt │ │ │ │ │ │ ├── IncorrectRegistrationRecoveryPasswordException.kt │ │ │ │ │ │ ├── InvalidTransportModeException.kt │ │ │ │ │ │ ├── LocalRateLimitException.java │ │ │ │ │ │ ├── MalformedRequestException.kt │ │ │ │ │ │ ├── MalformedResponseException.java │ │ │ │ │ │ ├── MissingConfigurationException.java │ │ │ │ │ │ ├── MustRequestNewCodeException.kt │ │ │ │ │ │ ├── NoContentException.java │ │ │ │ │ │ ├── NoSuchSessionException.kt │ │ │ │ │ │ ├── NonNormalizedPhoneNumberException.java │ │ │ │ │ │ ├── NonSuccessfulResponseCodeException.kt │ │ │ │ │ │ ├── NonSuccessfulResumableUploadResponseCodeException.java │ │ │ │ │ │ ├── NotFoundException.java │ │ │ │ │ │ ├── ProofRequiredException.java │ │ │ │ │ │ ├── PushNetworkException.java │ │ │ │ │ │ ├── RangeException.java │ │ │ │ │ │ ├── RateLimitException.java │ │ │ │ │ │ ├── RemoteAttestationResponseExpiredException.java │ │ │ │ │ │ ├── RequestVerificationCodeRateLimitException.kt │ │ │ │ │ │ ├── ResumeLocationInvalidException.java │ │ │ │ │ │ ├── ServerRejectedException.java │ │ │ │ │ │ ├── SubmitVerificationCodeRateLimitException.kt │ │ │ │ │ │ ├── TokenNotAcceptedException.kt │ │ │ │ │ │ ├── UnregisteredUserException.java │ │ │ │ │ │ ├── UsernameIsNotAssociatedWithAnAccountException.java │ │ │ │ │ │ ├── UsernameIsNotReservedException.java │ │ │ │ │ │ ├── UsernameMalformedException.java │ │ │ │ │ │ └── UsernameTakenException.java │ │ │ │ ├── ratelimit │ │ │ │ │ ├── RateLimitChallengeApi.kt │ │ │ │ │ ├── SubmitPushChallengePayload.java │ │ │ │ │ └── SubmitRecaptchaChallengePayload.java │ │ │ │ ├── registration │ │ │ │ │ ├── ProvisioningApi.java │ │ │ │ │ ├── RegistrationApi.kt │ │ │ │ │ └── RestoreMethodBody.kt │ │ │ │ ├── remoteconfig │ │ │ │ │ ├── RemoteConfigApi.kt │ │ │ │ │ ├── RemoteConfigResponse.java │ │ │ │ │ └── RemoteConfigResult.kt │ │ │ │ ├── services │ │ │ │ │ ├── DonationsService.java │ │ │ │ │ └── ProfileService.java │ │ │ │ ├── storage │ │ │ │ │ ├── AccountRecordExtensions.kt │ │ │ │ │ ├── ContactRecordExtensions.kt │ │ │ │ │ ├── IAPSubscriptionId.kt │ │ │ │ │ ├── ManifestRecordIdentifierExtensions.kt │ │ │ │ │ ├── RecordIkm.kt │ │ │ │ │ ├── SignalAccountRecord.kt │ │ │ │ │ ├── SignalCallLinkRecord.kt │ │ │ │ │ ├── SignalChatFolderRecord.kt │ │ │ │ │ ├── SignalContactRecord.kt │ │ │ │ │ ├── SignalGroupV1Record.kt │ │ │ │ │ ├── SignalGroupV2Record.kt │ │ │ │ │ ├── SignalNotificationProfileRecord.kt │ │ │ │ │ ├── SignalRecord.kt │ │ │ │ │ ├── SignalStorageCipher.kt │ │ │ │ │ ├── SignalStorageManifest.kt │ │ │ │ │ ├── SignalStorageRecord.kt │ │ │ │ │ ├── SignalStoryDistributionListRecord.kt │ │ │ │ │ ├── StorageAuthResponse.java │ │ │ │ │ ├── StorageCipherKey.kt │ │ │ │ │ ├── StorageId.java │ │ │ │ │ ├── StorageItemKey.kt │ │ │ │ │ ├── StorageKey.kt │ │ │ │ │ ├── StorageManifestKey.kt │ │ │ │ │ ├── StorageRecordConverters.kt │ │ │ │ │ ├── StorageRecordProtoUtil.kt │ │ │ │ │ ├── StorageServiceApi.kt │ │ │ │ │ ├── StorageServiceRepository.kt │ │ │ │ │ └── StoryDistributionListRecordExtensions.kt │ │ │ │ ├── subscriptions │ │ │ │ │ ├── ActiveSubscription.java │ │ │ │ │ ├── IdempotencyKey.java │ │ │ │ │ ├── PayPalConfirmPaymentIntentResponse.java │ │ │ │ │ ├── PayPalCreatePaymentIntentResponse.java │ │ │ │ │ ├── PayPalCreatePaymentMethodResponse.java │ │ │ │ │ ├── StripeClientSecret.java │ │ │ │ │ ├── SubscriberId.java │ │ │ │ │ └── SubscriptionLevels.java │ │ │ │ ├── svr │ │ │ │ │ ├── SecureValueRecovery.kt │ │ │ │ │ ├── SecureValueRecoveryV2.kt │ │ │ │ │ ├── SecureValueRecoveryV3.kt │ │ │ │ │ ├── SetShareSetRequest.kt │ │ │ │ │ ├── Svr2Socket.kt │ │ │ │ │ └── Svr3Credentials.kt │ │ │ │ ├── username │ │ │ │ │ └── UsernameApi.kt │ │ │ │ ├── util │ │ │ │ │ ├── AttachmentPointerUtil.java │ │ │ │ │ ├── CredentialsProvider.java │ │ │ │ │ ├── DeviceNameUtil.java │ │ │ │ │ ├── ExpiringProfileCredentialUtil.java │ │ │ │ │ ├── InvalidNumberException.java │ │ │ │ │ ├── OptionalUtil.kt │ │ │ │ │ ├── Preconditions.java │ │ │ │ │ ├── SleepTimer.java │ │ │ │ │ ├── StreamDetails.java │ │ │ │ │ ├── Tls12SocketFactory.java │ │ │ │ │ ├── TlsProxySocketFactory.kt │ │ │ │ │ ├── Uint64RangeException.java │ │ │ │ │ ├── Uint64Util.java │ │ │ │ │ ├── UptimeSleepTimer.java │ │ │ │ │ ├── UsernameExtensions.kt │ │ │ │ │ ├── Usernames.kt │ │ │ │ │ ├── UuidExtensions.kt │ │ │ │ │ └── UuidUtil.java │ │ │ │ └── websocket │ │ │ │ │ ├── HealthMonitor.kt │ │ │ │ │ ├── SignalWebSocket.kt │ │ │ │ │ ├── WebSocketConnectionState.java │ │ │ │ │ ├── WebSocketFactory.java │ │ │ │ │ └── WebSocketUnavailableException.java │ │ │ └── internal │ │ │ │ ├── EmptyResponse.java │ │ │ │ ├── ServiceResponse.java │ │ │ │ ├── ServiceResponseProcessor.java │ │ │ │ ├── WebSocketRequestExt.kt │ │ │ │ ├── configuration │ │ │ │ ├── HttpProxy.kt │ │ │ │ ├── SignalCdnUrl.java │ │ │ │ ├── SignalCdsiUrl.java │ │ │ │ ├── SignalProxy.java │ │ │ │ ├── SignalServiceConfiguration.kt │ │ │ │ ├── SignalServiceUrl.java │ │ │ │ ├── SignalStorageUrl.java │ │ │ │ ├── SignalSvr2Url.kt │ │ │ │ └── SignalUrl.java │ │ │ │ ├── contacts │ │ │ │ ├── crypto │ │ │ │ │ └── SignatureBodyEntity.java │ │ │ │ └── entities │ │ │ │ │ ├── DiscoveryRequest.java │ │ │ │ │ ├── DiscoveryResponse.java │ │ │ │ │ ├── KeyBackupRequest.java │ │ │ │ │ ├── KeyBackupResponse.java │ │ │ │ │ ├── MultiRemoteAttestationResponse.java │ │ │ │ │ ├── QueryEnvelope.java │ │ │ │ │ ├── RemoteAttestationRequest.java │ │ │ │ │ ├── RemoteAttestationResponse.java │ │ │ │ │ └── TokenResponse.java │ │ │ │ ├── crypto │ │ │ │ ├── AttachmentDigest.kt │ │ │ │ ├── PaddingInputStream.java │ │ │ │ ├── PrimaryProvisioningCipher.java │ │ │ │ └── SecondaryProvisioningCipher.kt │ │ │ │ ├── push │ │ │ │ ├── AttachmentUploadForm.kt │ │ │ │ ├── AttachmentV2UploadAttributes.java │ │ │ │ ├── AuthCredentials.java │ │ │ │ ├── BackupAuthCheckProcessor.kt │ │ │ │ ├── BackupAuthCheckRequest.kt │ │ │ │ ├── BackupV2AuthCheckResponse.kt │ │ │ │ ├── BackupV3AuthCheckResponse.kt │ │ │ │ ├── BankMandate.kt │ │ │ │ ├── ByteArrayDeserializerBase64.kt │ │ │ │ ├── ByteArraySerializerBase64NoPadding.kt │ │ │ │ ├── CdsiAuthResponse.java │ │ │ │ ├── CdsiResourceExhaustedResponse.java │ │ │ │ ├── CheckRepeatedUsedPreKeysRequest.kt │ │ │ │ ├── ConfirmUsernameRequest.java │ │ │ │ ├── ConfirmUsernameResponse.kt │ │ │ │ ├── ContactDiscoveryFailureReason.java │ │ │ │ ├── ContactTokenDetailsList.java │ │ │ │ ├── ContentRange.java │ │ │ │ ├── CreateCallLinkAuthRequest.kt │ │ │ │ ├── CreateCallLinkAuthResponse.kt │ │ │ │ ├── DeviceId.java │ │ │ │ ├── DeviceInfoList.java │ │ │ │ ├── DeviceLimit.java │ │ │ │ ├── DeviceLimitExceededException.java │ │ │ │ ├── DonationIntentResult.java │ │ │ │ ├── DonationProcessor.java │ │ │ │ ├── GcmRegistrationId.kt │ │ │ │ ├── GetAciByUsernameResponse.java │ │ │ │ ├── GetCallingRelaysResponse.kt │ │ │ │ ├── GetUsernameFromLinkResponseBody.kt │ │ │ │ ├── GroupMismatchedDevices.java │ │ │ │ ├── GroupStaleDevices.java │ │ │ │ ├── IdentityCheckRequest.java │ │ │ │ ├── IdentityCheckResponse.java │ │ │ │ ├── KyberPreKeyEntity.java │ │ │ │ ├── LinkDeviceRequest.java │ │ │ │ ├── LockedException.java │ │ │ │ ├── MismatchedDevices.java │ │ │ │ ├── NowhereBufferedSink.java │ │ │ │ ├── OutgoingPushMessage.java │ │ │ │ ├── OutgoingPushMessageList.java │ │ │ │ ├── PreKeyEntity.java │ │ │ │ ├── PreKeyResponse.java │ │ │ │ ├── PreKeyResponseItem.java │ │ │ │ ├── PreKeyState.java │ │ │ │ ├── ProfileAvatarData.java │ │ │ │ ├── ProfileAvatarUploadAttributes.java │ │ │ │ ├── ProofRequiredResponse.java │ │ │ │ ├── ProvisioningSocket.java │ │ │ │ ├── PushAttachmentData.kt │ │ │ │ ├── PushServiceSocket.java │ │ │ │ ├── PushTransportDetails.java │ │ │ │ ├── RegistrationSessionMetadataResponse.kt │ │ │ │ ├── RegistrationSessionRequestBody.kt │ │ │ │ ├── RequestVerificationCodeResponse.java │ │ │ │ ├── ReserveUsernameRequest.java │ │ │ │ ├── ReserveUsernameResponse.java │ │ │ │ ├── SendGroupMessageResponse.java │ │ │ │ ├── SendMessageResponse.java │ │ │ │ ├── SenderCertificate.java │ │ │ │ ├── SetUsernameLinkRequestBody.kt │ │ │ │ ├── SetUsernameLinkResponseBody.kt │ │ │ │ ├── SetUsernameRequest.java │ │ │ │ ├── SetUsernameResponse.java │ │ │ │ ├── SignalServiceEnvelopeEntity.java │ │ │ │ ├── StaleDevices.java │ │ │ │ ├── StickerUploadAttributes.java │ │ │ │ ├── StickerUploadAttributesResponse.java │ │ │ │ ├── SubscriptionsConfiguration.java │ │ │ │ ├── UnsupportedDataMessageException.java │ │ │ │ ├── UnsupportedDataMessageProtocolVersionException.java │ │ │ │ ├── UpdateVerificationSessionRequestBody.kt │ │ │ │ ├── VerificationCodeFailureResponseBody.kt │ │ │ │ ├── VerificationSessionMetadataRequestBody.kt │ │ │ │ ├── VerifyAccountResponse.java │ │ │ │ ├── WhoAmIResponse.kt │ │ │ │ ├── exceptions │ │ │ │ │ ├── CaptchaRejectedException.kt │ │ │ │ │ ├── ForbiddenException.java │ │ │ │ │ ├── GroupExistsException.java │ │ │ │ │ ├── GroupMismatchedDevicesException.java │ │ │ │ │ ├── GroupNotFoundException.java │ │ │ │ │ ├── GroupPatchNotAcceptedException.java │ │ │ │ │ ├── GroupStaleDevicesException.java │ │ │ │ │ ├── InAppPaymentProcessorError.kt │ │ │ │ │ ├── InAppPaymentReceiptCredentialError.kt │ │ │ │ │ ├── InvalidUnidentifiedAccessHeaderException.java │ │ │ │ │ ├── MismatchedDevicesException.java │ │ │ │ │ ├── MissingCapabilitiesException.java │ │ │ │ │ ├── NotInGroupException.java │ │ │ │ │ ├── PaymentsRegionException.java │ │ │ │ │ └── StaleDevicesException.java │ │ │ │ └── http │ │ │ │ │ ├── AcceptLanguagesUtil.java │ │ │ │ │ ├── AttachmentCipherOutputStreamFactory.kt │ │ │ │ │ ├── CancelationSignal.java │ │ │ │ │ ├── DigestingRequestBody.kt │ │ │ │ │ ├── NoCipherOutputStreamFactory.java │ │ │ │ │ ├── OutputStreamFactory.java │ │ │ │ │ ├── PartialSendBatchCompleteListener.java │ │ │ │ │ ├── PartialSendCompleteListener.java │ │ │ │ │ ├── ProfileCipherOutputStreamFactory.java │ │ │ │ │ ├── ResumableUploadSpec.kt │ │ │ │ │ └── StickerCipherOutputStreamFactory.java │ │ │ │ ├── serialize │ │ │ │ ├── SignalServiceAddressProtobufSerializer.kt │ │ │ │ └── SignalServiceMetadataProtobufSerializer.kt │ │ │ │ ├── util │ │ │ │ ├── BlacklistingTrustManager.java │ │ │ │ ├── CompletableFutureExtensions.kt │ │ │ │ ├── DynamicCredentialsProvider.java │ │ │ │ ├── Hex.java │ │ │ │ ├── JsonUtil.java │ │ │ │ ├── StaticCredentialsProvider.java │ │ │ │ └── Util.java │ │ │ │ └── websocket │ │ │ │ ├── DefaultErrorMapper.java │ │ │ │ ├── DefaultResponseMapper.java │ │ │ │ ├── ErrorMapper.java │ │ │ │ ├── LibSignalChatConnection.kt │ │ │ │ ├── LibSignalNetworkExtensions.kt │ │ │ │ ├── LibSignalResponseExtension.kt │ │ │ │ ├── OkHttpWebSocketConnection.java │ │ │ │ ├── ResponseMapper.java │ │ │ │ ├── WebSocketConnection.kt │ │ │ │ └── WebsocketResponse.java │ │ │ └── util │ │ │ ├── ByteArrayUtil.java │ │ │ └── StringUtil.java │ └── protowire │ │ ├── CDSI.proto │ │ ├── DecryptedGroups.proto │ │ ├── DeviceName.proto │ │ ├── Groups.proto │ │ ├── InternalSerialization.proto │ │ ├── MessageProcessing.proto │ │ ├── Provisioning.proto │ │ ├── RegistrationProvisioning.proto │ │ ├── ResumableUploads.proto │ │ ├── SVR2.proto │ │ ├── SignalService.proto │ │ ├── SignalServiceLegacy.proto │ │ ├── StickerResources.proto │ │ ├── StorageService.proto │ │ └── WebSocketResources.proto │ ├── test │ ├── java │ │ └── org │ │ │ └── whispersystems │ │ │ └── signalservice │ │ │ ├── api │ │ │ ├── NetworkResultTest.kt │ │ │ ├── crypto │ │ │ │ ├── AttachmentCipherStreamUtilTest.kt │ │ │ │ ├── AttachmentCipherTest.java │ │ │ │ ├── AttachmentCipherTestHelper.kt │ │ │ │ ├── ProfileCipherTest.java │ │ │ │ ├── SkippingOutputStreamTest.java │ │ │ │ └── UnidentifiedAccessTest.java │ │ │ ├── groupsv2 │ │ │ │ ├── DecryptedGroupUtilTest.kt │ │ │ │ ├── DecryptedGroupUtil_apply_Test.java │ │ │ │ ├── DecryptedGroupUtil_empty_Test.java │ │ │ │ ├── GroupChangeReconstructTest.java │ │ │ │ ├── GroupChangeUtil_changeIsEmpty_Test.java │ │ │ │ ├── GroupChangeUtil_resolveConflict_Test.java │ │ │ │ ├── GroupChangeUtil_resolveConflict_decryptedOnly_Test.java │ │ │ │ ├── GroupsV2Operations_ban_Test.kt │ │ │ │ ├── GroupsV2Operations_decrypt_change_Test.java │ │ │ │ ├── GroupsV2Operations_decrypt_groupJoinInfo_Test.java │ │ │ │ ├── GroupsV2Operations_decrypt_group_Test.java │ │ │ │ ├── ProtoTestUtils.java │ │ │ │ ├── ProtobufTestUtils.java │ │ │ │ └── TestZkGroupServer.java │ │ │ ├── kbs │ │ │ │ └── MasterKeyTest.java │ │ │ ├── messages │ │ │ │ ├── EnvelopeContentValidatorTest.kt │ │ │ │ └── multidevice │ │ │ │ │ └── DeviceContactsInputStreamTest.java │ │ │ ├── payments │ │ │ │ ├── FiatFormatterTest.java │ │ │ │ ├── MobileCoinFormatterTest.java │ │ │ │ ├── MoneyTest_MobileCoin.java │ │ │ │ ├── MoneyTest_MobileCoin_add.java │ │ │ │ ├── MoneyTest_MobileCoin_comparators.java │ │ │ │ ├── MoneyTest_MobileCoin_subtract.java │ │ │ │ └── MoneyTest_MobileCoin_sum.java │ │ │ ├── push │ │ │ │ ├── PushTransportDetailsTest.kt │ │ │ │ └── ServiceIdTests.kt │ │ │ ├── services │ │ │ │ └── DonationsServiceTest.kt │ │ │ ├── storage │ │ │ │ ├── SignalContactRecordTest.java │ │ │ │ └── SignalStorageCipherTest.java │ │ │ ├── subscriptions │ │ │ │ └── ActiveSubscriptionTest.java │ │ │ └── util │ │ │ │ ├── CredentialsProviderTest.kt │ │ │ │ ├── OptionalUtilTest.java │ │ │ │ ├── Uint64UtilTest.java │ │ │ │ └── UuidUtilTest.java │ │ │ ├── internal │ │ │ ├── crypto │ │ │ │ ├── PaddingInputStreamTest.kt │ │ │ │ └── SecondaryProvisioningCipherTest.kt │ │ │ ├── push │ │ │ │ ├── ContentRange_parse_Test.kt │ │ │ │ ├── ContentRange_parse_withInvalidStrings_Test.kt │ │ │ │ ├── GroupMismatchedDevicesTest.kt │ │ │ │ ├── GroupStaleDevicesTest.kt │ │ │ │ ├── exceptions │ │ │ │ │ └── InAppPaymentProcessorErrorTest.kt │ │ │ │ └── http │ │ │ │ │ └── DigestingRequestBodyTest.kt │ │ │ └── websocket │ │ │ │ └── LibSignalChatConnectionTest.kt │ │ │ └── testutil │ │ │ └── LibSignalLibraryUtil.java │ └── resources │ │ ├── ias.cert │ │ ├── ias.jks │ │ └── ias.store │ └── testFixtures │ └── java │ └── org │ └── whispersystems │ └── signalservice │ └── test │ └── LibSignalLibraryUtil.java ├── settings.gradle.kts └── wire-handler └── wire-handler-1.0.0.jar /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{kt,kts}] 4 | indent_size = 2 5 | ij_kotlin_allow_trailing_comma_on_call_site = false 6 | ij_kotlin_allow_trailing_comma = false 7 | ktlint_code_style = intellij_idea 8 | twitter_compose_allowed_composition_locals=LocalExtendedColors 9 | ktlint_standard_class-naming = disabled 10 | 11 | # below rules disabled during ktlint version migration because they were preexisting but should be corrected and re-enabled ASAP 12 | ktlint_function_naming_ignore_when_annotated_with = Composable 13 | ktlint_standard_property-naming = disabled 14 | ktlint_standard_enum-wrapping = disabled 15 | ktlint_standard_multiline-if-else = disabled 16 | ktlint_standard_backing-property-naming = disabled 17 | ktlint_standard_statement-wrapping = disabled 18 | internal:ktlint-suppression = disabled 19 | ktlint_standard_unnecessary-parentheses-before-trailing-lambda = disabled 20 | ktlint_standard_value-parameter-comment = disabled 21 | ktlint_standard_class-signature = disabled 22 | ktlint_standard_function-expression-body = disabled 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | *.iml 4 | build/ 5 | gradle.properties 6 | .kotlin/ 7 | -------------------------------------------------------------------------------- /constants.gradle.kts: -------------------------------------------------------------------------------- 1 | val signalJavaVersion by extra(JavaVersion.VERSION_17) 2 | val signalKotlinJvmTarget by extra("17") 3 | val lib_signal_service_version_number by extra { "2.15.3_unofficial_124" } 4 | val lib_signal_service_group_info by extra { "com.github.turasa" } 5 | -------------------------------------------------------------------------------- /core-util-jvm/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/DoubleExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util 7 | 8 | import java.util.Locale 9 | 10 | /** 11 | * Rounds a number to the specified number of places. e.g. 12 | * 13 | * 1.123456f.roundedString(2) = 1.12 14 | * 1.123456f.roundedString(5) = 1.12346 15 | */ 16 | fun Double.roundedString(places: Int): String { 17 | return String.format(Locale.US, "%.${places}f", this) 18 | } 19 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/DurationExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util 7 | 8 | import kotlin.time.Duration 9 | import kotlin.time.DurationUnit 10 | 11 | fun Duration.inRoundedMilliseconds(places: Int = 2) = this.toDouble(DurationUnit.MILLISECONDS).roundedString(places) 12 | fun Duration.inRoundedMinutes(places: Int = 2) = this.toDouble(DurationUnit.MINUTES).roundedString(places) 13 | fun Duration.inRoundedHours(places: Int = 2) = this.toDouble(DurationUnit.HOURS).roundedString(places) 14 | fun Duration.inRoundedDays(places: Int = 2) = this.toDouble(DurationUnit.DAYS).roundedString(places) 15 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/FloatExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util 7 | 8 | /** 9 | * Rounds a number to the specified number of places. e.g. 10 | * 11 | * 1.123456f.roundedString(2) = 1.12 12 | * 1.123456f.roundedString(5) = 1.12346 13 | */ 14 | fun Float.roundedString(places: Int): String { 15 | return String.format("%.${places}f", this) 16 | } 17 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/LongExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util 7 | 8 | import java.nio.ByteBuffer 9 | 10 | /** 11 | * Converts the long into [ByteArray]. 12 | */ 13 | fun Long.toByteArray(): ByteArray { 14 | return ByteBuffer 15 | .allocate(Long.SIZE_BYTES) 16 | .putLong(this) 17 | .array() 18 | } 19 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/OptionalExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util 7 | 8 | import java.util.Optional 9 | 10 | fun Optional.or(other: Optional): Optional { 11 | return if (this.isPresent) { 12 | this 13 | } else { 14 | other 15 | } 16 | } 17 | 18 | fun Optional.isAbsent(): Boolean { 19 | return !isPresent 20 | } 21 | 22 | fun E?.toOptional(): Optional { 23 | return Optional.ofNullable(this) 24 | } 25 | 26 | fun Optional.orNull(): E? { 27 | return orElse(null) 28 | } 29 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/OutputStreamExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util 7 | 8 | import java.io.OutputStream 9 | 10 | /** 11 | * Writes a 32-bit variable-length integer to the stream. 12 | * 13 | * The format uses one byte for each 7 bits of the integer, with the most significant bit (MSB) of each byte indicating whether more bytes need to be read. 14 | */ 15 | fun OutputStream.writeVarInt32(value: Int) { 16 | var remaining = value 17 | 18 | while (true) { 19 | // We write 7 bits of the integer at a time 20 | val lowestSevenBits = remaining and 0x7F 21 | remaining = remaining ushr 7 22 | 23 | if (remaining == 0) { 24 | // If there are no more bits to write, we're done 25 | write(lowestSevenBits) 26 | return 27 | } else { 28 | // Otherwise, we need to write the next 7 bits, and set the MSB to 1 to indicate that there are more bits to come 29 | write(lowestSevenBits or 0x80) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/concurrent/FutureTransformers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util.concurrent; 7 | 8 | public final class FutureTransformers { 9 | 10 | public static ListenableFuture map(ListenableFuture future, Transformer transformer) { 11 | return new FutureMapTransformer<>(future, transformer); 12 | } 13 | 14 | public interface Transformer { 15 | Output transform(Input a) throws Exception; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/concurrent/JvmRxExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | @file:JvmName("JvmRxExtensions") 7 | 8 | package org.signal.core.util.concurrent 9 | 10 | import io.reactivex.rxjava3.core.Single 11 | 12 | /** 13 | * Throw an [InterruptedException] if a [Single.blockingGet] call is interrupted. This can 14 | * happen when being called by code already within an Rx chain that is disposed. 15 | * 16 | * [Single.blockingGet] is considered harmful and should not be used. 17 | */ 18 | @Throws(InterruptedException::class) 19 | fun Single.safeBlockingGet(): T { 20 | try { 21 | return blockingGet() 22 | } catch (e: RuntimeException) { 23 | val cause = e.cause 24 | if (cause is InterruptedException) { 25 | throw cause 26 | } else { 27 | throw e 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/concurrent/ListenableFuture.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util.concurrent; 7 | 8 | import java.util.concurrent.ExecutionException; 9 | import java.util.concurrent.Future; 10 | 11 | public interface ListenableFuture extends Future { 12 | void addListener(Listener listener); 13 | 14 | public interface Listener { 15 | public void onSuccess(T result); 16 | public void onFailure(ExecutionException e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/logging/NoopLogger.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util.logging 7 | 8 | /** 9 | * A logger that does nothing. 10 | */ 11 | internal class NoopLogger : Log.Logger() { 12 | override fun v(tag: String, message: String?, t: Throwable?, keepLonger: Boolean) = Unit 13 | override fun d(tag: String, message: String?, t: Throwable?, keepLonger: Boolean) = Unit 14 | override fun i(tag: String, message: String?, t: Throwable?, keepLonger: Boolean) = Unit 15 | override fun w(tag: String, message: String?, t: Throwable?, keepLonger: Boolean) = Unit 16 | override fun e(tag: String, message: String?, t: Throwable?, keepLonger: Boolean) = Unit 17 | override fun flush() = Unit 18 | } 19 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/stream/NonClosingOutputStream.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util.stream 7 | 8 | import java.io.FilterOutputStream 9 | import java.io.OutputStream 10 | 11 | /** 12 | * Wraps a provided [OutputStream] but ignores calls to [OutputStream.close] on it but will call [OutputStream.flush] just in case. 13 | * Wrappers must call [OutputStream.close] on the passed in [wrap] stream directly. 14 | */ 15 | class NonClosingOutputStream(wrap: OutputStream) : FilterOutputStream(wrap) { 16 | override fun close() { 17 | flush() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/stream/NullOutputStream.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util.stream 7 | 8 | import java.io.OutputStream 9 | 10 | /** 11 | * An output stream that drops all data on the floor. Basically piping to /dev/null. 12 | */ 13 | object NullOutputStream : OutputStream() { 14 | override fun write(b: Int) = Unit 15 | override fun write(b: ByteArray?) = Unit 16 | override fun write(b: ByteArray?, off: Int, len: Int) = Unit 17 | } 18 | -------------------------------------------------------------------------------- /core-util-jvm/src/main/java/org/signal/core/util/test/TestUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.signal.core.util.test 7 | 8 | import kotlin.reflect.full.memberProperties 9 | import kotlin.reflect.jvm.isAccessible 10 | 11 | /** 12 | * Returns a string containing the differences between the expected and actual objects. 13 | * Useful for diffing complex data classes in your tests. 14 | */ 15 | inline fun getObjectDiff(expected: T, actual: T): String { 16 | val builder = StringBuilder() 17 | 18 | val properties = T::class.memberProperties 19 | 20 | for (prop in properties) { 21 | prop.isAccessible = true 22 | val expectedValue = prop.get(expected) 23 | val actualValue = prop.get(actual) 24 | if (expectedValue != actualValue) { 25 | builder.append("[${prop.name}] Expected: $expectedValue, Actual: $actualValue\n") 26 | } 27 | } 28 | 29 | return builder.toString() 30 | } 31 | -------------------------------------------------------------------------------- /core-util-jvm/src/test/java/org/signal/core/util/logging/LogTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | package org.signal.core.util.logging 6 | 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Test 9 | 10 | class LogTest { 11 | @Test 12 | fun tag_short_class_name() { 13 | assertEquals("MyClass", Log.tag(MyClass::class)) 14 | } 15 | 16 | @Test 17 | fun tag_23_character_class_name() { 18 | val tag = Log.tag(TwentyThreeCharacters23::class) 19 | assertEquals("TwentyThreeCharacters23", tag) 20 | assertEquals(23, tag.length) 21 | } 22 | 23 | @Test 24 | fun tag_24_character_class_name() { 25 | assertEquals(24, TwentyFour24Characters24::class.simpleName!!.length) 26 | val tag = Log.tag(TwentyFour24Characters24::class) 27 | assertEquals("TwentyFour24Characters2", tag) 28 | assertEquals(23, Log.tag(TwentyThreeCharacters23::class).length) 29 | } 30 | 31 | private inner class MyClass 32 | 33 | private inner class TwentyThreeCharacters23 34 | 35 | private inner class TwentyFour24Characters24 36 | } 37 | -------------------------------------------------------------------------------- /gradle/test-libs.versions.toml: -------------------------------------------------------------------------------- 1 | # IMPORTANT: After changing a dependency, please run: 2 | # ./gradlew --write-verification-metadata sha256 qa --rerun-tasks 3 | 4 | [versions] 5 | 6 | [libraries] 7 | junit-junit = "junit:junit:4.13.2" 8 | kotlinx-coroutines-test = "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0" 9 | assertk = "com.willowtreeapps.assertk:assertk:0.28.1" 10 | mockk = "io.mockk:mockk:1.13.2" 11 | 12 | conscrypt-openjdk-uber = "org.conscrypt:conscrypt-openjdk-uber:2.5.2" 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turasa/libsignal-service-java/c95ad5823be36f55d605e895e604a2bfb70ecb7c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=89d4e70e4e84e2d2dfbb63e4daa53e21b25017cc70c37e4eea31ee51fb15098a 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /service/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /service/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/CancelationException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | import java.io.IOException; 4 | 5 | public class CancelationException extends IOException { 6 | public CancelationException() { 7 | } 8 | 9 | public CancelationException(Throwable cause) { 10 | super(cause); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/ContentTooLargeException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | public class ContentTooLargeException extends IllegalStateException { 4 | public ContentTooLargeException(long size) { 5 | super("Too large! Size: " + size + " bytes"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/InvalidPreKeyException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api 7 | 8 | import org.signal.libsignal.protocol.InvalidKeyException 9 | import org.signal.libsignal.protocol.SignalProtocolAddress 10 | import java.io.IOException 11 | 12 | /** 13 | * Wraps an [InvalidKeyException] in an [IOException] with a nicer message. 14 | */ 15 | class InvalidPreKeyException( 16 | address: SignalProtocolAddress, 17 | invalidKeyException: InvalidKeyException 18 | ) : IOException("Invalid prekey for $address", invalidKeyException) 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountDataStore.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | import org.signal.libsignal.protocol.state.SignalProtocolStore; 4 | 5 | /** 6 | * And extension of the normal protocol store interface that has additional methods that are needed 7 | * in the service layer, but not the protocol layer. 8 | */ 9 | public interface SignalServiceAccountDataStore extends SignalProtocolStore, 10 | SignalServicePreKeyStore, 11 | SignalServiceSessionStore, 12 | SignalServiceSenderKeyStore, 13 | SignalServiceKyberPreKeyStore { 14 | /** 15 | * @return True if the user has linked devices, otherwise false. 16 | */ 17 | boolean isMultiDevice(); 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/SignalServiceDataStore.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | import org.whispersystems.signalservice.api.push.ServiceId; 4 | 5 | /** 6 | * And extension of the normal protocol store interface that has additional methods that are needed 7 | * in the service layer, but not the protocol layer. 8 | */ 9 | public interface SignalServiceDataStore { 10 | 11 | /** 12 | * @return A {@link SignalServiceAccountDataStore} for the specified account. 13 | */ 14 | SignalServiceAccountDataStore get(ServiceId accountIdentifier); 15 | 16 | /** 17 | * @return A {@link SignalServiceAccountDataStore} for the ACI account. 18 | */ 19 | SignalServiceAccountDataStore aci(); 20 | 21 | /** 22 | * @return A {@link SignalServiceAccountDataStore} for the PNI account. 23 | */ 24 | SignalServiceAccountDataStore pni(); 25 | 26 | /** 27 | * @return True if the user has linked devices, otherwise false. 28 | */ 29 | boolean isMultiDevice(); 30 | } 31 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/SignalServicePreKeyStore.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api 2 | 3 | import org.signal.libsignal.protocol.state.PreKeyStore 4 | 5 | /** 6 | * And extension of the normal protocol prekey store interface that has additional methods that are 7 | * needed in the service layer, but not the protocol layer. 8 | */ 9 | interface SignalServicePreKeyStore : PreKeyStore { 10 | /** 11 | * Marks all prekeys stale if they haven't been marked already. "Stale" means the time that the keys have been replaced. 12 | */ 13 | fun markAllOneTimeEcPreKeysStaleIfNecessary(staleTime: Long) 14 | 15 | /** 16 | * Deletes all prekeys that have been stale since before the threshold. "Stale" means the time that the keys have been replaced. 17 | */ 18 | fun deleteAllStaleOneTimeEcPreKeys(threshold: Long, minCount: Int) 19 | } 20 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/SignalServiceSessionStore.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | import org.signal.libsignal.protocol.SignalProtocolAddress; 4 | import org.signal.libsignal.protocol.state.SessionRecord; 5 | import org.signal.libsignal.protocol.state.SessionStore; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | /** 12 | * And extension of the normal protocol session store interface that has additional methods that are 13 | * needed in the service layer, but not the protocol layer. 14 | */ 15 | public interface SignalServiceSessionStore extends SessionStore { 16 | void archiveSession(SignalProtocolAddress address); 17 | Map getAllAddressesWithActiveSessions(List addressNames); 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/SignalSessionLock.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | import java.io.Closeable; 4 | 5 | /** 6 | * An interface to allow the injection of a lock that will be used to keep interactions with 7 | * ecryptions/decryptions thread-safe. 8 | */ 9 | public interface SignalSessionLock { 10 | 11 | Lock acquire(); 12 | 13 | interface Lock extends Closeable { 14 | @Override 15 | void close(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/SvrNoDataException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api; 2 | 3 | public final class SvrNoDataException extends Exception { 4 | 5 | public SvrNoDataException() { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/account/PreKeyCollection.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.account 7 | 8 | import org.signal.libsignal.protocol.IdentityKey 9 | import org.signal.libsignal.protocol.state.KyberPreKeyRecord 10 | import org.signal.libsignal.protocol.state.SignedPreKeyRecord 11 | 12 | /** 13 | * Holder class to pass around a bunch of prekeys that we send off to the service during registration. 14 | * As the service does not return the submitted prekeys, we need to hold them in memory so that when 15 | * the service approves the keys we have a local copy to persist. 16 | */ 17 | data class PreKeyCollection( 18 | val identityKey: IdentityKey, 19 | val signedPreKey: SignedPreKeyRecord, 20 | val lastResortKyberPreKey: KyberPreKeyRecord 21 | ) 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/account/PreKeyUpload.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.account 7 | 8 | import org.signal.libsignal.protocol.state.KyberPreKeyRecord 9 | import org.signal.libsignal.protocol.state.PreKeyRecord 10 | import org.signal.libsignal.protocol.state.SignedPreKeyRecord 11 | import org.whispersystems.signalservice.api.push.ServiceIdType 12 | 13 | /** 14 | * Represents a bundle of prekeys you want to upload. 15 | * 16 | * If a field is nullable, not setting it will simply leave that field alone on the service. 17 | */ 18 | data class PreKeyUpload( 19 | val serviceIdType: ServiceIdType, 20 | val signedPreKey: SignedPreKeyRecord?, 21 | val oneTimeEcPreKeys: List?, 22 | val lastResortKyberPreKey: KyberPreKeyRecord?, 23 | val oneTimeKyberPreKeys: List? 24 | ) 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveCredentialPresentation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import org.signal.core.util.Base64 9 | 10 | /** 11 | * Acts as credentials for various archive operations. 12 | */ 13 | class ArchiveCredentialPresentation( 14 | val presentation: ByteArray, 15 | val signedPresentation: ByteArray 16 | ) { 17 | fun toHeaders(): MutableMap { 18 | return mutableMapOf( 19 | "X-Signal-ZK-Auth" to Base64.encodeWithPadding(presentation), 20 | "X-Signal-ZK-Auth-Signature" to Base64.encodeWithPadding(signedPresentation) 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveGetBackupInfoResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Represents the response when fetching the archive backup info. 12 | */ 13 | data class ArchiveGetBackupInfoResponse( 14 | @JsonProperty 15 | val cdn: Int?, 16 | @JsonProperty 17 | val backupDir: String?, 18 | @JsonProperty 19 | val mediaDir: String?, 20 | @JsonProperty 21 | val backupName: String?, 22 | @JsonProperty 23 | val usedSpace: Long? 24 | ) 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveGetMediaItemsResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Response body for getting the media items stored in the user's archive. 12 | */ 13 | class ArchiveGetMediaItemsResponse( 14 | @JsonProperty val storedMediaObjects: List, 15 | @JsonProperty val backupDir: String?, 16 | @JsonProperty val mediaDir: String?, 17 | @JsonProperty val cursor: String? 18 | ) { 19 | class StoredMediaObject( 20 | @JsonProperty val cdn: Int, 21 | @JsonProperty val mediaId: String, 22 | @JsonProperty val objectLength: Long 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveMediaRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Request to copy and re-encrypt media from the attachments cdn into the backup cdn. 12 | */ 13 | class ArchiveMediaRequest( 14 | @JsonProperty val sourceAttachment: SourceAttachment, 15 | @JsonProperty val objectLength: Int, 16 | @JsonProperty val mediaId: String, 17 | @JsonProperty val hmacKey: String, 18 | @JsonProperty val encryptionKey: String 19 | ) { 20 | class SourceAttachment( 21 | @JsonProperty val cdn: Int, 22 | @JsonProperty val key: String 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveMediaResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Response to archiving media, backup CDN number where media is located. 12 | */ 13 | class ArchiveMediaResponse( 14 | @JsonProperty val cdn: Int 15 | ) { 16 | enum class StatusCodes(val code: Int) { 17 | BadArguments(400), 18 | InvalidPresentationOrSignature(401), 19 | InsufficientPermissions(403), 20 | NoMediaSpaceRemaining(413), 21 | RateLimited(429), 22 | Unknown(-1); 23 | 24 | companion object { 25 | fun from(code: Int): StatusCodes { 26 | return entries.firstOrNull { it.code == code } ?: Unknown 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveMediaUploadFormStatusCodes.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | /** 9 | * Status codes for the ArchiveMediaUploadForm endpoint. 10 | * 11 | * Kept in a separate class because [AttachmentUploadForm] (the model the request returns) is used for multiple endpoints with different status codes. 12 | */ 13 | enum class ArchiveMediaUploadFormStatusCodes(val code: Int) { 14 | BadArguments(400), 15 | InvalidPresentationOrSignature(401), 16 | InsufficientPermissions(403), 17 | RateLimited(429), 18 | Unknown(-1); 19 | 20 | companion object { 21 | fun from(code: Int): ArchiveMediaUploadFormStatusCodes { 22 | return entries.firstOrNull { it.code == code } ?: Unknown 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveServiceAccess.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import org.whispersystems.signalservice.api.backup.BackupKey 9 | 10 | /** 11 | * Key and credential combo needed to perform backup operations on the server. 12 | */ 13 | class ArchiveServiceAccess( 14 | val credential: ArchiveServiceCredential, 15 | val backupKey: T 16 | ) 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveServiceAccessPair.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import org.whispersystems.signalservice.api.backup.MediaRootBackupKey 9 | import org.whispersystems.signalservice.api.backup.MessageBackupKey 10 | 11 | /** 12 | * A convenient container for passing around both a message and media archive service credential. 13 | */ 14 | data class ArchiveServiceAccessPair( 15 | val messageBackupAccess: ArchiveServiceAccess, 16 | val mediaBackupAccess: ArchiveServiceAccess 17 | ) 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/ArchiveServiceCredential.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.archive 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | /** 6 | * Represents an individual credential for an archive operation. Note that is isn't the final 7 | * credential you will actually use -- that's [org.signal.libsignal.zkgroup.backups.BackupAuthCredential]. 8 | * But you use these to make those. 9 | */ 10 | class ArchiveServiceCredential( 11 | @JsonProperty 12 | val credential: ByteArray, 13 | @JsonProperty 14 | val redemptionTime: Long 15 | ) 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/BatchArchiveMediaRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Request to copy and re-encrypt media from the attachments cdn into the backup cdn. 12 | */ 13 | class BatchArchiveMediaRequest( 14 | @JsonProperty val items: List 15 | ) 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/BatchArchiveMediaResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Multi-response data for a batch archive media operation. 12 | */ 13 | class BatchArchiveMediaResponse( 14 | @JsonProperty val responses: List 15 | ) { 16 | class BatchArchiveMediaItemResponse( 17 | @JsonProperty val status: Int?, 18 | @JsonProperty val failureReason: String?, 19 | @JsonProperty val cdn: Int?, 20 | @JsonProperty val mediaId: String 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/DeleteArchivedMediaRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Delete media from the backup cdn. 12 | */ 13 | class DeleteArchivedMediaRequest( 14 | @JsonProperty val mediaToDelete: List 15 | ) { 16 | class ArchivedMediaObject( 17 | @JsonProperty val cdn: Int, 18 | @JsonProperty val mediaId: String 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/archive/GetArchiveCdnCredentialsResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.archive 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Get response with headers to use to read from archive cdn. 12 | */ 13 | class GetArchiveCdnCredentialsResponse( 14 | @JsonProperty val headers: Map 15 | ) 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentDownloadResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.attachment 7 | 8 | import org.signal.core.util.stream.LimitedInputStream 9 | 10 | /** 11 | * Holds the result of an attachment download. 12 | */ 13 | class AttachmentDownloadResult( 14 | val dataStream: LimitedInputStream, 15 | val iv: ByteArray 16 | ) 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentUploadResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.attachment 7 | 8 | import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId 9 | 10 | /** 11 | * The result of uploading an attachment. Just the additional metadata related to the upload itself. 12 | */ 13 | class AttachmentUploadResult( 14 | val remoteId: SignalServiceAttachmentRemoteId, 15 | val cdnNumber: Int, 16 | val key: ByteArray, 17 | val iv: ByteArray, 18 | val digest: ByteArray, 19 | val incrementalDigest: ByteArray?, 20 | val incrementalDigestChunkSize: Int, 21 | val dataSize: Long, 22 | val uploadTimestamp: Long, 23 | val blurHash: String? 24 | ) 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/backup/BackupId.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.backup 7 | 8 | import org.signal.core.util.Base64 9 | import java.security.MessageDigest 10 | 11 | /** 12 | * Safe typing around a backupId, which is a 16-byte array. 13 | */ 14 | @JvmInline 15 | value class BackupId(val value: ByteArray) { 16 | 17 | init { 18 | require(value.size == 16) { "BackupId must be 16 bytes!" } 19 | } 20 | 21 | /** Encode backup-id for use in a URL/request */ 22 | fun encode(): String { 23 | return Base64.encodeUrlSafeWithPadding(MessageDigest.getInstance("SHA-256").digest(value).copyOfRange(0, 16)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/backup/BackupKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.backup 7 | 8 | import org.signal.libsignal.protocol.ecc.ECPrivateKey 9 | import org.whispersystems.signalservice.api.push.ServiceId.ACI 10 | 11 | /** 12 | * Contains the common properties for all "backup keys", namely the [MessageBackupKey] and [MediaRootBackupKey] 13 | */ 14 | interface BackupKey { 15 | 16 | val value: ByteArray 17 | 18 | /** 19 | * The private key used to generate anonymous credentials when interacting with the backup service. 20 | */ 21 | fun deriveAnonymousCredentialPrivateKey(aci: ACI): ECPrivateKey 22 | } 23 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/backup/MediaId.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.backup 7 | 8 | import org.signal.core.util.Base64 9 | 10 | /** 11 | * Safe typing around a mediaId, which is a 15-byte array. 12 | */ 13 | @JvmInline 14 | value class MediaId(val value: ByteArray) { 15 | 16 | constructor(mediaId: String) : this(Base64.decode(mediaId)) 17 | 18 | init { 19 | require(value.size == 15) { "MediaId must be 15 bytes!" } 20 | } 21 | 22 | /** Encode media-id for use in a URL/request */ 23 | fun encode(): String { 24 | return Base64.encodeUrlSafeWithPadding(value) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherStreamUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.crypto 7 | 8 | object AttachmentCipherStreamUtil { 9 | 10 | /** 11 | * Given the size of the plaintext, this will return the length of ciphertext output. 12 | * @param inputSize Size of the plaintext fed into the stream. This does *not* automatically include padding. Add that yourself before calling if needed. 13 | */ 14 | @JvmStatic 15 | fun getCiphertextLength(plaintextLength: Long): Long { 16 | val ivLength: Long = 16 17 | val macLength: Long = 32 18 | val blockLength: Long = (plaintextLength / 16 + 1) * 16 19 | return ivLength + macLength + blockLength 20 | } 21 | 22 | @JvmStatic 23 | fun getPlaintextLength(ciphertextLength: Long): Long { 24 | return ((ciphertextLength - 16 - 32) / 16 - 1) * 16 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/Crypto.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.crypto 7 | 8 | import org.signal.libsignal.protocol.kdf.HKDF 9 | 10 | /** 11 | * A collection of cryptographic functions in the same namespace for easy access. 12 | */ 13 | object Crypto { 14 | 15 | fun hkdf(inputKeyMaterial: ByteArray, info: ByteArray, outputLength: Int, salt: ByteArray? = null): ByteArray { 16 | return HKDF.deriveSecrets(inputKeyMaterial, salt, info, outputLength) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/EnvelopeMetadata.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.crypto 2 | 3 | import org.whispersystems.signalservice.api.push.ServiceId 4 | 5 | class EnvelopeMetadata( 6 | val sourceServiceId: ServiceId, 7 | val sourceE164: String?, 8 | val sourceDeviceId: Int, 9 | val sealedSender: Boolean, 10 | val groupId: ByteArray?, 11 | val destinationServiceId: ServiceId 12 | ) 13 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/InvalidCiphertextException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.crypto; 2 | 3 | public class InvalidCiphertextException extends Exception { 4 | public InvalidCiphertextException(Exception nested) { 5 | super(nested); 6 | } 7 | 8 | public InvalidCiphertextException(String s) { 9 | super(s); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/NoCipherOutputStream.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.crypto; 2 | 3 | import java.io.OutputStream; 4 | 5 | /** 6 | * Use when the stream is already encrypted. 7 | */ 8 | public final class NoCipherOutputStream extends DigestingOutputStream { 9 | 10 | public NoCipherOutputStream(OutputStream outputStream) { 11 | super(outputStream); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalServiceCipherResult.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.crypto 2 | 3 | import org.whispersystems.signalservice.internal.push.Content 4 | 5 | /** 6 | * Represents the output of decrypting a [SignalServiceProtos.Envelope] via [SignalServiceCipher.decrypt] 7 | * 8 | * @param content The [SignalServiceProtos.Content] that was decrypted from the envelope. 9 | * @param metadata The decrypted metadata of the envelope. Represents sender information that may have 10 | * been encrypted with sealed sender. 11 | */ 12 | data class SignalServiceCipherResult( 13 | val content: Content, 14 | val metadata: EnvelopeMetadata 15 | ) 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/SignalSessionBuilder.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.crypto; 2 | 3 | import org.signal.libsignal.protocol.InvalidKeyException; 4 | import org.signal.libsignal.protocol.SessionBuilder; 5 | import org.signal.libsignal.protocol.UntrustedIdentityException; 6 | import org.signal.libsignal.protocol.state.PreKeyBundle; 7 | import org.whispersystems.signalservice.api.SignalSessionLock; 8 | 9 | /** 10 | * A thread-safe wrapper around {@link SessionBuilder}. 11 | */ 12 | public class SignalSessionBuilder { 13 | 14 | private final SignalSessionLock lock; 15 | private final SessionBuilder builder; 16 | 17 | public SignalSessionBuilder(SignalSessionLock lock, SessionBuilder builder) { 18 | this.lock = lock; 19 | this.builder = builder; 20 | } 21 | 22 | public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException { 23 | try (SignalSessionLock.Lock unused = lock.acquire()) { 24 | builder.process(preKey); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/crypto/UntrustedIdentityException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.crypto; 8 | 9 | import org.signal.libsignal.protocol.IdentityKey; 10 | 11 | public class UntrustedIdentityException extends Exception { 12 | 13 | private final IdentityKey identityKey; 14 | private final String identifier; 15 | 16 | public UntrustedIdentityException(String s, String identifier, IdentityKey identityKey) { 17 | super(s); 18 | this.identifier = identifier; 19 | this.identityKey = identityKey; 20 | } 21 | 22 | public UntrustedIdentityException(UntrustedIdentityException e) { 23 | this(e.getMessage(), e.getIdentifier(), e.getIdentityKey()); 24 | } 25 | 26 | public IdentityKey getIdentityKey() { 27 | return identityKey; 28 | } 29 | 30 | public String getIdentifier() { 31 | return identifier; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/donations/PayPalCreateOneTimePaymentIntentPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.donations; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | /** 11 | * Request JSON for creating a PayPal one-time payment intent 12 | */ 13 | class PayPalCreateOneTimePaymentIntentPayload { 14 | @JsonProperty 15 | private long amount; 16 | 17 | @JsonProperty 18 | private String currency; 19 | 20 | @JsonProperty 21 | private long level; 22 | 23 | @JsonProperty 24 | private String returnUrl; 25 | 26 | @JsonProperty 27 | private String cancelUrl; 28 | 29 | public PayPalCreateOneTimePaymentIntentPayload(long amount, String currency, long level, String returnUrl, String cancelUrl) { 30 | this.amount = amount; 31 | this.currency = currency; 32 | this.level = level; 33 | this.returnUrl = returnUrl; 34 | this.cancelUrl = cancelUrl; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/donations/PayPalCreatePaymentMethodPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.donations; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | class PayPalCreatePaymentMethodPayload { 11 | @JsonProperty 12 | private String returnUrl; 13 | 14 | @JsonProperty 15 | private String cancelUrl; 16 | 17 | PayPalCreatePaymentMethodPayload(String returnUrl, String cancelUrl) { 18 | this.returnUrl = returnUrl; 19 | this.cancelUrl = cancelUrl; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/donations/ReceiptCredentialRequestJson.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.donations; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialRequest; 11 | import org.signal.core.util.Base64; 12 | 13 | class ReceiptCredentialRequestJson { 14 | @JsonProperty("receiptCredentialRequest") 15 | private final String receiptCredentialRequest; 16 | 17 | ReceiptCredentialRequestJson(ReceiptCredentialRequest receiptCredentialRequest) { 18 | this.receiptCredentialRequest = Base64.encodeWithPadding(receiptCredentialRequest.serialize()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/donations/RedeemArchivesReceiptRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.donations 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import com.fasterxml.jackson.annotation.JsonProperty 10 | 11 | /** 12 | * POST /v1/archives/redeem-receipt 13 | * 14 | * Request object for redeeming a receipt from a donation transaction. 15 | * 16 | * @param receiptCredentialPresentation base64-encoded no-newlines standard-character-set with-padding of the bytes of a [ReceiptCredentialPresentation] object 17 | */ 18 | internal class RedeemArchivesReceiptRequest @JsonCreator constructor(@param:JsonProperty("receiptCredentialPresentation") val receiptCredentialPresentation: String) 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/donations/StripeOneTimePaymentIntentPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.donations; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | class StripeOneTimePaymentIntentPayload { 11 | @JsonProperty 12 | private long amount; 13 | 14 | @JsonProperty 15 | private String currency; 16 | 17 | @JsonProperty 18 | private long level; 19 | 20 | @JsonProperty 21 | private String paymentMethod; 22 | 23 | public StripeOneTimePaymentIntentPayload(long amount, String currency, long level, String paymentMethod) { 24 | this.amount = amount; 25 | this.currency = currency; 26 | this.level = level; 27 | this.paymentMethod = paymentMethod; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/CredentialResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class CredentialResponse { 6 | 7 | @JsonProperty 8 | private TemporalCredential[] credentials; 9 | 10 | @JsonProperty 11 | private TemporalCredential[] callLinkAuthCredentials; 12 | 13 | public TemporalCredential[] getCredentials() { 14 | return credentials; 15 | } 16 | 17 | public TemporalCredential[] getCallLinkAuthCredentials() { 18 | return callLinkAuthCredentials; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/DecryptedGroupResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.groupsv2 7 | 8 | import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsementsResponse 9 | import org.signal.storageservice.protos.groups.local.DecryptedGroup 10 | 11 | /** 12 | * Decrypted response from server operations that includes our global group state and 13 | * our specific-to-us group send endorsements. 14 | */ 15 | class DecryptedGroupResponse( 16 | val group: DecryptedGroup, 17 | val groupSendEndorsementsResponse: GroupSendEndorsementsResponse? 18 | ) 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupHistoryPage.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2 2 | 3 | import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsementsResponse 4 | import org.whispersystems.signalservice.internal.push.PushServiceSocket.GroupHistory 5 | 6 | /** 7 | * Wraps result of group history fetch with it's associated paging data. 8 | */ 9 | data class GroupHistoryPage(val changeLogs: List, val groupSendEndorsementsResponse: GroupSendEndorsementsResponse?, val pagingData: PagingData) { 10 | 11 | data class PagingData(val hasMorePages: Boolean, val nextPageRevision: Int) { 12 | companion object { 13 | @JvmField 14 | val NONE = PagingData(false, -1) 15 | 16 | @JvmStatic 17 | fun forGroupHistory(groupHistory: GroupHistory): PagingData { 18 | return PagingData(groupHistory.hasMore(), if (groupHistory.hasMore()) groupHistory.nextPageStartGroupRevision else -1) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupLinkNotActiveException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | 4 | import java.util.Optional; 5 | 6 | /** 7 | * Thrown when a group link: 8 | * - has an out of date password, or; 9 | * - is currently not shared, or; 10 | * - has been banned from the group, or; 11 | * - the master key does not match a group on the server 12 | */ 13 | public final class GroupLinkNotActiveException extends Exception { 14 | 15 | private final Reason reason; 16 | 17 | public GroupLinkNotActiveException(Throwable t, Optional reason) { 18 | super(t); 19 | 20 | if (reason.isPresent() && reason.get().equalsIgnoreCase("banned")) { 21 | this.reason = Reason.BANNED; 22 | } else { 23 | this.reason = Reason.UNKNOWN; 24 | } 25 | } 26 | 27 | public Reason getReason() { 28 | return reason; 29 | } 30 | 31 | public enum Reason { 32 | UNKNOWN, 33 | BANNED 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/GroupsV2AuthorizationString.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | import org.signal.libsignal.zkgroup.auth.AuthCredentialPresentation; 4 | import org.signal.libsignal.zkgroup.groups.GroupSecretParams; 5 | import org.whispersystems.signalservice.internal.util.Hex; 6 | 7 | import okhttp3.Credentials; 8 | 9 | public final class GroupsV2AuthorizationString { 10 | 11 | private final String authString; 12 | 13 | GroupsV2AuthorizationString(GroupSecretParams groupSecretParams, AuthCredentialPresentation authCredentialPresentation) { 14 | String username = Hex.toStringCondensed(groupSecretParams.getPublicParams().serialize()); 15 | String password = Hex.toStringCondensed(authCredentialPresentation.serialize()); 16 | 17 | authString = Credentials.basic(username, password); 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return authString; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/InvalidGroupStateException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | import org.signal.libsignal.zkgroup.InvalidInputException; 4 | 5 | /** 6 | * Thrown when a group has some data that cannot be decrypted, or is in some other way in an 7 | * unexpected state. 8 | */ 9 | public final class InvalidGroupStateException extends Exception { 10 | 11 | InvalidGroupStateException(InvalidInputException e) { 12 | super(e); 13 | } 14 | 15 | InvalidGroupStateException(String message) { 16 | super(message); 17 | } 18 | 19 | InvalidGroupStateException() { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/NoCredentialForRedemptionTimeException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | /** 4 | * Thrown when we do not have a credential locally for a given time. 5 | */ 6 | public final class NoCredentialForRedemptionTimeException extends Exception { 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/NotAbleToApplyGroupV2ChangeException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | public final class NotAbleToApplyGroupV2ChangeException extends Exception { 4 | 5 | public NotAbleToApplyGroupV2ChangeException() { 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/ReceivedGroupSendEndorsements.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.groupsv2 7 | 8 | import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsement 9 | import org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsementsResponse 10 | import org.whispersystems.signalservice.api.push.ServiceId 11 | import java.time.Instant 12 | 13 | /** 14 | * Group send endorsement data received from the server. 15 | */ 16 | data class ReceivedGroupSendEndorsements( 17 | val expirationMs: Long, 18 | val endorsements: Map 19 | ) { 20 | constructor( 21 | expiration: Instant, 22 | members: List, 23 | receivedEndorsements: GroupSendEndorsementsResponse.ReceivedEndorsements 24 | ) : this( 25 | expirationMs = expiration.toEpochMilli(), 26 | endorsements = members.zip(receivedEndorsements.endorsements).toMap() 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/groupsv2/TemporalCredential.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class TemporalCredential { 6 | 7 | @JsonProperty 8 | private byte[] credential; 9 | 10 | @JsonProperty 11 | private long redemptionTime; 12 | 13 | public byte[] getCredential() { 14 | return credential; 15 | } 16 | 17 | public long getRedemptionTime() { 18 | return redemptionTime; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/kbs/KbsData.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.kbs; 2 | 3 | /** 4 | * Construct from a {@link org.signal.libsignal.svr2.PinHash}. 5 | */ 6 | public final class KbsData { 7 | private final MasterKey masterKey; 8 | private final byte[] kbsAccessKey; 9 | private final byte[] cipherText; 10 | 11 | KbsData(MasterKey masterKey, byte[] kbsAccessKey, byte[] cipherText) { 12 | this.masterKey = masterKey; 13 | this.kbsAccessKey = kbsAccessKey; 14 | this.cipherText = cipherText; 15 | } 16 | 17 | public MasterKey getMasterKey() { 18 | return masterKey; 19 | } 20 | 21 | public byte[] getKbsAccessKey() { 22 | return kbsAccessKey; 23 | } 24 | 25 | public byte[] getCipherText() { 26 | return cipherText; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/kbs/PinString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.kbs; 7 | 8 | final class PinString { 9 | 10 | static boolean allNumeric(CharSequence pin) { 11 | for (int i = 0; i < pin.length(); i++) { 12 | if (!Character.isDigit(pin.charAt(i))) return false; 13 | } 14 | return true; 15 | } 16 | 17 | /** 18 | * Converts a string of not necessarily Arabic numerals to Arabic 0..9 characters. 19 | */ 20 | static String toArabic(CharSequence numerals) { 21 | int length = numerals.length(); 22 | char[] arabic = new char[length]; 23 | 24 | for (int i = 0; i < length; i++) { 25 | int digit = Character.digit(numerals.charAt(i), 10); 26 | 27 | arabic[i] = (char) ('0' + digit); 28 | } 29 | 30 | return new String(arabic); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/keys/OneTimePreKeyCounts.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.keys; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | public class OneTimePreKeyCounts { 11 | 12 | @JsonProperty("count") 13 | private int ecCount; 14 | 15 | @JsonProperty("pqCount") 16 | private int kyberCount; 17 | 18 | public OneTimePreKeyCounts() {} 19 | 20 | public OneTimePreKeyCounts(int ecCount, int kyberCount) { 21 | this.ecCount = ecCount; 22 | this.kyberCount = kyberCount; 23 | } 24 | 25 | public int getEcCount() { 26 | return ecCount; 27 | } 28 | 29 | public int getKyberCount() { 30 | return kyberCount; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/link/LinkedDeviceVerificationCodeResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.link 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Response object for: GET /v1/devices/provisioning/code 12 | */ 13 | data class LinkedDeviceVerificationCodeResponse( 14 | @JsonProperty val verificationCode: String, 15 | @JsonProperty val tokenIdentifier: String 16 | ) 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/link/SetDeviceNameRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.link 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Request body for setting the name of a linked device. 12 | */ 13 | data class SetDeviceNameRequest( 14 | @JsonProperty val deviceName: String 15 | ) 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/link/SetLinkedDeviceTransferArchiveRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.link 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Request body for setting the transfer archive for a linked device. 12 | */ 13 | data class SetLinkedDeviceTransferArchiveRequest( 14 | @JsonProperty val destinationDeviceId: Int, 15 | @JsonProperty val destinationDeviceCreated: Long, 16 | @JsonProperty val transferArchive: TransferArchive 17 | ) { 18 | sealed class TransferArchive { 19 | data class CdnInfo( 20 | @JsonProperty val cdn: Int, 21 | @JsonProperty val key: String 22 | ) : TransferArchive() 23 | data class Error( 24 | @JsonProperty val error: TransferArchiveError 25 | ) : TransferArchive() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/link/TransferArchiveError.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.link 7 | 8 | /** 9 | * Error response options chosen by a user. Response is sent to a linked device after its transfer archive has failed 10 | */ 11 | enum class TransferArchiveError { 12 | RELINK_REQUESTED, 13 | CONTINUE_WITHOUT_UPLOAD 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/link/WaitForLinkedDeviceResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.link 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | /** 11 | * Response body for GET /v1/devices/wait_for_linked_device/{tokenIdentifier} 12 | */ 13 | data class WaitForLinkedDeviceResponse( 14 | @JsonProperty val id: Int, 15 | @JsonProperty val name: String, 16 | @JsonProperty val created: Long, 17 | @JsonProperty val lastSeen: Long 18 | ) 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/message/SpamTokenMessage.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.message 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | 10 | data class SpamTokenMessage(@JsonProperty val token: String?) 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeResponse.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages 2 | 3 | import org.whispersystems.signalservice.internal.push.Envelope 4 | import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage 5 | 6 | /** 7 | * Represents an envelope off the wire, paired with the metadata needed to process it. 8 | */ 9 | class EnvelopeResponse( 10 | val envelope: Envelope, 11 | val serverDeliveredTimestamp: Long, 12 | val websocketRequest: WebSocketRequestMessage 13 | ) 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceEditMessage.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages 2 | 3 | data class SignalServiceEditMessage( 4 | val targetSentTimestamp: Long, 5 | val dataMessage: SignalServiceDataMessage 6 | ) 7 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServicePniSignatureMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.ServiceId.PNI; 5 | 6 | /** 7 | * When someone sends a message to your PNI, you need to attach one of these PNI signature messages, 8 | * proving that you own the PNI identity. 9 | * 10 | * The signature is generated by signing your ACI public key with your PNI identity. 11 | */ 12 | public class SignalServicePniSignatureMessage { 13 | 14 | private final PNI pni; 15 | private final byte[] signature; 16 | 17 | public SignalServicePniSignatureMessage(PNI pni, byte[] signature) { 18 | this.pni = pni; 19 | this.signature = signature; 20 | } 21 | 22 | public PNI getPni() { 23 | return pni; 24 | } 25 | 26 | public byte[] getSignature() { 27 | return signature; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceReceiptMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages; 2 | 3 | 4 | import java.util.List; 5 | 6 | public class SignalServiceReceiptMessage { 7 | 8 | public enum Type { 9 | UNKNOWN, DELIVERY, READ, VIEWED 10 | } 11 | 12 | private final Type type; 13 | private final List timestamps; 14 | private final long when; 15 | 16 | public SignalServiceReceiptMessage(Type type, List timestamps, long when) { 17 | this.type = type; 18 | this.timestamps = timestamps; 19 | this.when = when; 20 | } 21 | 22 | public Type getType() { 23 | return type; 24 | } 25 | 26 | public List getTimestamps() { 27 | return timestamps; 28 | } 29 | 30 | public long getWhen() { 31 | return when; 32 | } 33 | 34 | public boolean isDeliveryReceipt() { 35 | return type == Type.DELIVERY; 36 | } 37 | 38 | public boolean isReadReceipt() { 39 | return type == Type.READ; 40 | } 41 | 42 | public boolean isViewedReceipt() { 43 | return type == Type.VIEWED; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/SignalServiceTypingMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages; 2 | 3 | 4 | import java.util.Optional; 5 | 6 | public class SignalServiceTypingMessage { 7 | 8 | public enum Action { 9 | UNKNOWN, STARTED, STOPPED 10 | } 11 | 12 | private final Action action; 13 | private final long timestamp; 14 | private final Optional groupId; 15 | 16 | public SignalServiceTypingMessage(Action action, long timestamp, Optional groupId) { 17 | this.action = action; 18 | this.timestamp = timestamp; 19 | this.groupId = groupId; 20 | } 21 | 22 | public Action getAction() { 23 | return action; 24 | } 25 | 26 | public long getTimestamp() { 27 | return timestamp; 28 | } 29 | 30 | public Optional getGroupId() { 31 | return groupId; 32 | } 33 | 34 | public boolean isTypingStarted() { 35 | return action == Action.STARTED; 36 | } 37 | 38 | public boolean isTypingStopped() { 39 | return action == Action.STOPPED; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/calls/AnswerMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.calls; 2 | 3 | 4 | public class AnswerMessage { 5 | 6 | private final long id; 7 | private final byte[] opaque; 8 | 9 | public AnswerMessage(long id, byte[] opaque) { 10 | this.id = id; 11 | this.opaque = opaque; 12 | } 13 | 14 | public long getId() { 15 | return id; 16 | } 17 | 18 | public byte[] getOpaque() { 19 | return opaque; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/calls/BusyMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.calls; 2 | 3 | 4 | public class BusyMessage { 5 | 6 | private final long id; 7 | 8 | public BusyMessage(long id) { 9 | this.id = id; 10 | } 11 | 12 | public long getId() { 13 | return id; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/calls/IceUpdateMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.calls; 2 | 3 | 4 | public class IceUpdateMessage { 5 | 6 | private final long id; 7 | private final byte[] opaque; 8 | 9 | public IceUpdateMessage(long id, byte[] opaque) { 10 | this.id = id; 11 | this.opaque = opaque; 12 | } 13 | 14 | public long getId() { 15 | return id; 16 | } 17 | 18 | public byte[] getOpaque() { 19 | return opaque; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/calls/OpaqueMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.calls; 2 | 3 | import org.whispersystems.signalservice.internal.push.CallMessage; 4 | 5 | public class OpaqueMessage { 6 | 7 | private final byte[] opaque; 8 | private final Urgency urgency; 9 | 10 | public OpaqueMessage(byte[] opaque, Urgency urgency) { 11 | this.opaque = opaque; 12 | this.urgency = urgency == null ? Urgency.DROPPABLE : urgency; 13 | } 14 | 15 | public byte[] getOpaque() { 16 | return opaque; 17 | } 18 | 19 | public Urgency getUrgency() { 20 | return urgency; 21 | } 22 | 23 | public enum Urgency { 24 | DROPPABLE, 25 | HANDLE_IMMEDIATELY; 26 | 27 | public CallMessage.Opaque.Urgency toProto() { 28 | if (this == HANDLE_IMMEDIATELY) { 29 | return CallMessage.Opaque.Urgency.HANDLE_IMMEDIATELY; 30 | } 31 | return CallMessage.Opaque.Urgency.DROPPABLE; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/calls/TurnServerInfo.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.calls; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public class TurnServerInfo { 8 | 9 | @JsonProperty 10 | private String username; 11 | 12 | @JsonProperty 13 | private String password; 14 | 15 | @JsonProperty 16 | private String hostname; 17 | 18 | @JsonProperty 19 | private List urls; 20 | 21 | @JsonProperty 22 | private List urlsWithIps; 23 | 24 | @JsonProperty 25 | private Long ttl; 26 | 27 | public String getUsername() { 28 | return username; 29 | } 30 | 31 | public String getPassword() { 32 | return password; 33 | } 34 | 35 | // Hostname for the ips in urlsWithIps 36 | public String getHostname() { 37 | return hostname; 38 | } 39 | 40 | public List getUrls() { 41 | return urls; 42 | } 43 | 44 | public List getUrlsWithIps() { 45 | return urlsWithIps; 46 | } 47 | 48 | public Long getTtl() { 49 | return ttl; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/BlockedListMessage.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice 2 | 3 | import org.whispersystems.signalservice.api.push.ServiceId 4 | 5 | class BlockedListMessage( 6 | @JvmField val individuals: List, 7 | @JvmField val groupIds: List 8 | ) { 9 | data class Individual( 10 | val aci: ServiceId.ACI?, 11 | val e164: String? 12 | ) { 13 | init { 14 | check(aci != null || e164 != null) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/ChunkedInputStream.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | public class ChunkedInputStream { 7 | 8 | protected final InputStream in; 9 | 10 | public ChunkedInputStream(InputStream in) { 11 | this.in = in; 12 | } 13 | 14 | long readRawVarint32() throws IOException { 15 | long result = 0; 16 | for (int shift = 0; shift < 32; shift += 7) { 17 | int tmpInt = in.read(); 18 | if (tmpInt < 0) { 19 | return -1; 20 | } 21 | final byte b = (byte) tmpInt; 22 | result |= (long) (b & 0x7F) << shift; 23 | if ((b & 0x80) == 0) { 24 | return result; 25 | } 26 | } 27 | throw new IOException("Malformed varint!"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/ChunkedOutputStream.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | public class ChunkedOutputStream { 8 | 9 | protected final OutputStream out; 10 | 11 | public ChunkedOutputStream(OutputStream out) { 12 | this.out = out; 13 | } 14 | 15 | protected void writeVarint32(int value) throws IOException { 16 | while (true) { 17 | if ((value & ~0x7F) == 0) { 18 | out.write(value); 19 | return; 20 | } else { 21 | out.write((value & 0x7F) | 0x80); 22 | value >>>= 7; 23 | } 24 | } 25 | } 26 | 27 | protected void writeStream(InputStream in) throws IOException { 28 | byte[] buffer = new byte[4096]; 29 | int read; 30 | 31 | while ((read = in.read(buffer)) != -1) { 32 | out.write(buffer, 0, read); 33 | } 34 | 35 | in.close(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/ContactsMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | 4 | import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; 5 | 6 | public class ContactsMessage { 7 | 8 | private final SignalServiceAttachment contacts; 9 | private final boolean complete; 10 | 11 | public ContactsMessage(SignalServiceAttachment contacts, boolean complete) { 12 | this.contacts = contacts; 13 | this.complete = complete; 14 | } 15 | 16 | public SignalServiceAttachment getContactsStream() { 17 | return contacts; 18 | } 19 | 20 | public boolean isComplete() { 21 | return complete; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceContactAvatar.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.messages.multidevice 7 | 8 | import java.io.InputStream 9 | 10 | /** 11 | * Data needed to sync a device contact avatar to/from other devices. 12 | */ 13 | data class DeviceContactAvatar(val inputStream: InputStream, val length: Long, val contentType: String) 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.messages.multidevice; 8 | 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | 11 | public class DeviceInfo { 12 | 13 | @JsonProperty 14 | public int id; 15 | 16 | @JsonProperty 17 | public String name; 18 | 19 | @JsonProperty 20 | public long created; 21 | 22 | @JsonProperty 23 | public long lastSeen; 24 | 25 | public DeviceInfo() {} 26 | 27 | public int getId() { 28 | return id; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public long getCreated() { 36 | return created; 37 | } 38 | 39 | public long getLastSeen() { 40 | return lastSeen; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/KeysMessage.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice 2 | 3 | import org.whispersystems.signalservice.api.AccountEntropyPool 4 | import org.whispersystems.signalservice.api.backup.MediaRootBackupKey 5 | import org.whispersystems.signalservice.api.kbs.MasterKey 6 | import org.whispersystems.signalservice.api.storage.StorageKey 7 | 8 | data class KeysMessage( 9 | val storageService: StorageKey?, 10 | val master: MasterKey?, 11 | val accountEntropyPool: AccountEntropyPool?, 12 | val mediaRootBackupKey: MediaRootBackupKey? 13 | ) 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/ReadMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.messages.multidevice; 8 | 9 | import org.whispersystems.signalservice.api.push.ServiceId; 10 | 11 | public class ReadMessage { 12 | 13 | private final ServiceId sender; 14 | private final long timestamp; 15 | 16 | public ReadMessage(ServiceId sender, long timestamp) { 17 | this.sender = sender; 18 | this.timestamp = timestamp; 19 | } 20 | 21 | public long getTimestamp() { 22 | return timestamp; 23 | } 24 | 25 | public ServiceId getSender() { 26 | return sender; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/StickerPackOperationMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | 4 | import java.util.Optional; 5 | 6 | public class StickerPackOperationMessage { 7 | 8 | private final Optional packId; 9 | private final Optional packKey; 10 | private final Optional type; 11 | 12 | public StickerPackOperationMessage(byte[] packId, byte[] packKey, Type type) { 13 | this.packId = Optional.ofNullable(packId); 14 | this.packKey = Optional.ofNullable(packKey); 15 | this.type = Optional.ofNullable(type); 16 | } 17 | 18 | public Optional getPackId() { 19 | return packId; 20 | } 21 | 22 | public Optional getPackKey() { 23 | return packKey; 24 | } 25 | 26 | public Optional getType() { 27 | return type; 28 | } 29 | 30 | public enum Type { 31 | INSTALL, REMOVE 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/VerifyDeviceResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.UUID; 6 | 7 | public class VerifyDeviceResponse { 8 | @JsonProperty 9 | private UUID uuid; 10 | 11 | @JsonProperty 12 | private UUID pni; 13 | 14 | @JsonProperty 15 | private int deviceId; 16 | 17 | public VerifyDeviceResponse() {} 18 | 19 | public VerifyDeviceResponse(UUID uuid, UUID pni, int deviceId) { 20 | this.uuid = uuid; 21 | this.pni = pni; 22 | this.deviceId = deviceId; 23 | } 24 | 25 | public UUID getUuid() { 26 | return uuid; 27 | } 28 | 29 | public UUID getPni() { 30 | return pni; 31 | } 32 | 33 | public int getDeviceId() { 34 | return deviceId; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/ViewOnceOpenMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | import org.whispersystems.signalservice.api.push.ServiceId; 4 | 5 | public class ViewOnceOpenMessage { 6 | 7 | private final ServiceId sender; 8 | private final long timestamp; 9 | 10 | public ViewOnceOpenMessage(ServiceId sender, long timestamp) { 11 | this.sender = sender; 12 | this.timestamp = timestamp; 13 | } 14 | 15 | public long getTimestamp() { 16 | return timestamp; 17 | } 18 | 19 | public ServiceId getSender() { 20 | return sender; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/ViewedMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.messages.multidevice; 2 | 3 | import org.whispersystems.signalservice.api.push.ServiceId; 4 | 5 | public class ViewedMessage { 6 | 7 | private final ServiceId sender; 8 | private final long timestamp; 9 | 10 | public ViewedMessage(ServiceId sender, long timestamp) { 11 | this.sender = sender; 12 | this.timestamp = timestamp; 13 | } 14 | 15 | public long getTimestamp() { 16 | return timestamp; 17 | } 18 | 19 | public ServiceId getSender() { 20 | return sender; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/payments/CurrencyConversion.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.payments; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.Map; 6 | 7 | public final class CurrencyConversion { 8 | @JsonProperty 9 | private String base; 10 | 11 | @JsonProperty 12 | private Map conversions; 13 | 14 | public String getBase() { 15 | return base; 16 | } 17 | 18 | public Map getConversions() { 19 | return conversions; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/payments/CurrencyConversions.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.payments; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public final class CurrencyConversions { 8 | @JsonProperty 9 | private List currencies; 10 | 11 | @JsonProperty 12 | private long timestamp; 13 | 14 | public List getCurrencies() { 15 | return currencies; 16 | } 17 | 18 | public long getTimestamp() { 19 | return timestamp; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/payments/PaymentsConstants.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.payments; 2 | 3 | public final class PaymentsConstants { 4 | 5 | private PaymentsConstants() {} 6 | 7 | public static final int PAYMENTS_ENTROPY_LENGTH = 32; 8 | public static final int MNEMONIC_LENGTH = Math.round(PAYMENTS_ENTROPY_LENGTH * 0.75f); 9 | public static final int SHORT_FRACTION_LENGTH = 4; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/payments/UnsupportedCurrencyException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.payments; 2 | 3 | public final class UnsupportedCurrencyException extends Exception { 4 | } 5 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/profiles/SignalServiceProfileWrite.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.profiles 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | class SignalServiceProfileWrite( 6 | @JsonProperty val version: String, 7 | @JsonProperty val name: ByteArray, 8 | @JsonProperty val about: ByteArray, 9 | @JsonProperty val aboutEmoji: ByteArray, 10 | @JsonProperty val paymentAddress: ByteArray?, 11 | @JsonProperty val phoneNumberSharing: ByteArray, 12 | @JsonProperty val avatar: Boolean, 13 | @JsonProperty val sameAvatar: Boolean, 14 | @JsonProperty val commitment: ByteArray, 15 | @JsonProperty val badgeIds: List 16 | ) 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/provisioning/ProvisioningMessage.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.provisioning; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ProvisioningMessage { 6 | 7 | @JsonProperty 8 | private String body; 9 | 10 | public ProvisioningMessage(String body) { 11 | this.body = body; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/provisioning/RestoreMethod.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.provisioning 7 | 8 | /** 9 | * Restore method chosen by user on new device after performing a quick-restore. 10 | */ 11 | enum class RestoreMethod { 12 | REMOTE_BACKUP, 13 | LOCAL_BACKUP, 14 | DEVICE_TRANSFER, 15 | DECLINE 16 | } 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/ServiceIdType.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push; 2 | 3 | public enum ServiceIdType { 4 | ACI("aci"), PNI("pni"); 5 | 6 | private final String queryParamName; 7 | 8 | ServiceIdType(String queryParamName) { 9 | this.queryParamName = queryParamName; 10 | } 11 | 12 | public String queryParam() { 13 | return queryParamName; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/TrustStore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push; 8 | 9 | import java.io.InputStream; 10 | 11 | /** 12 | * A class that represents a Java {@link java.security.KeyStore} and 13 | * its associated password. 14 | */ 15 | public interface TrustStore { 16 | public InputStream getKeyStoreInputStream(); 17 | public String getKeyStorePassword(); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/UsernameLinkComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.push 7 | 8 | import java.util.UUID 9 | 10 | /** 11 | * Wrapper for passing around the two components of a username link: the entropy and serverId, which when combined together form the full link handle. 12 | */ 13 | data class UsernameLinkComponents( 14 | val entropy: ByteArray, 15 | val serverId: UUID 16 | ) { 17 | override fun equals(other: Any?): Boolean { 18 | if (this === other) return true 19 | if (javaClass != other?.javaClass) return false 20 | 21 | other as UsernameLinkComponents 22 | 23 | if (!entropy.contentEquals(other.entropy)) return false 24 | return serverId == other.serverId 25 | } 26 | 27 | override fun hashCode(): Int { 28 | var result = entropy.contentHashCode() 29 | result = 31 * result + serverId.hashCode() 30 | return result 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/AlreadyVerifiedException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class AlreadyVerifiedException : NonSuccessfulResponseCodeException(409) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/AuthorizationFailedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | public class AuthorizationFailedException extends NonSuccessfulResponseCodeException { 10 | public AuthorizationFailedException(int code, String s) { 11 | super(code, s); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/CdsiInvalidArgumentException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | 4 | /** 5 | * Indicates that something about our request was wrong. Could be: 6 | * - Over 50k new contacts 7 | * - Missing version byte prefix 8 | * - Missing credentials 9 | * - E164s are not a multiple of 8 bytes 10 | * - Something else? 11 | */ 12 | public class CdsiInvalidArgumentException extends NonSuccessfulResponseCodeException { 13 | public CdsiInvalidArgumentException() { 14 | super(4003); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/CdsiInvalidTokenException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | 4 | /** 5 | * Indicates that you provided a bad token to CDSI. 6 | */ 7 | public class CdsiInvalidTokenException extends NonSuccessfulResponseCodeException { 8 | public CdsiInvalidTokenException() { 9 | super(4101); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/CdsiResourceExhaustedException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | /** 4 | * A 4008 responses from CDSI indicating we've exhausted our quota. 5 | */ 6 | public class CdsiResourceExhaustedException extends NonSuccessfulResponseCodeException { 7 | 8 | private final int retryAfterSeconds; 9 | 10 | public CdsiResourceExhaustedException(int retryAfterSeconds) { 11 | super(4008); 12 | this.retryAfterSeconds = retryAfterSeconds; 13 | } 14 | 15 | public int getRetryAfterSeconds() { 16 | return retryAfterSeconds; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ChallengeRequiredException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.push.exceptions 7 | 8 | import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse 9 | 10 | /** 11 | * We tried to do something on registration endpoints that didn't go well, so now we have to do a challenge. And not a 12 | * fun one involving ice buckets. 13 | */ 14 | class ChallengeRequiredException(val response: RegistrationSessionMetadataResponse) : NonSuccessfulResponseCodeException(409) 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ConflictException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | /** 4 | * Represents a 409 http conflict error. 5 | */ 6 | public class ConflictException extends NonSuccessfulResponseCodeException { 7 | public ConflictException() { 8 | super(409, "Conflict"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ContactManifestMismatchException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class ContactManifestMismatchException extends ConflictException { 4 | 5 | private final byte[] responseBody; 6 | 7 | public ContactManifestMismatchException(byte[] responseBody) { 8 | this.responseBody = responseBody; 9 | } 10 | 11 | public byte[] getResponseBody() { 12 | return responseBody; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/DeprecatedVersionException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class DeprecatedVersionException extends NonSuccessfulResponseCodeException { 4 | public DeprecatedVersionException() { 5 | super(499); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ExpectationFailedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | package org.whispersystems.signalservice.api.push.exceptions; 7 | 8 | public class ExpectationFailedException extends NonSuccessfulResponseCodeException { 9 | public ExpectationFailedException() { 10 | super(417); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ExternalServiceFailureException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | /** 4 | * known possible values for @property[reason]: 5 | * providerRejected - indicates that the provider understood the request, but declined to deliver a verification SMS/call (potentially due to fraud prevention rules) 6 | * providerUnavailable - indicates that the provider could not be reached or did not respond to the request to send a verification code in a timely manner 7 | * illegalArgument - some part of the request was not understood or accepted by the provider (e.g. the provider did not recognize the phone number as a valid number for the selected transport) 8 | */ 9 | class ExternalServiceFailureException(val isPermanent: Boolean, val reason: String) : NonSuccessfulResponseCodeException(502) { 10 | override fun toString(): String { 11 | return "ExternalServiceFailureException: External service failed to send SMS code ${if (isPermanent) "permanently" else "temporarily"} due to $reason" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/HttpConflictException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class HttpConflictException : NonSuccessfulResponseCodeException(409) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ImpossiblePhoneNumberException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | /** 4 | * An exception indicating that the server believes the number provided is 'impossible', meaning it fails the most basic libphonenumber checks. 5 | */ 6 | public class ImpossiblePhoneNumberException extends NonSuccessfulResponseCodeException { 7 | public ImpossiblePhoneNumberException() { 8 | super(400); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/IncorrectCodeException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class IncorrectCodeException : NonSuccessfulResponseCodeException(403) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/IncorrectRegistrationRecoveryPasswordException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class IncorrectRegistrationRecoveryPasswordException : NonSuccessfulResponseCodeException(403) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/InvalidTransportModeException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class InvalidTransportModeException : NonSuccessfulResponseCodeException(400) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/LocalRateLimitException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | /** 4 | * Thrown when self limiting networking. 5 | */ 6 | public final class LocalRateLimitException extends Exception { 7 | public LocalRateLimitException() { } 8 | } 9 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/MalformedRequestException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.push.exceptions 7 | 8 | class MalformedRequestException : NonSuccessfulResponseCodeException(400) 9 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/MalformedResponseException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Indicates that a response is malformed or otherwise in an unexpected format. 7 | */ 8 | public class MalformedResponseException extends IOException { 9 | 10 | public MalformedResponseException(String message) { 11 | super(message); 12 | } 13 | 14 | public MalformedResponseException(String message, IOException e) { 15 | super(message, e); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/MissingConfigurationException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public final class MissingConfigurationException extends Exception { 4 | public MissingConfigurationException(String s) { 5 | super(s); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/MustRequestNewCodeException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class MustRequestNewCodeException : NonSuccessfulResponseCodeException(409) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/NoContentException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | public class NoContentException extends NonSuccessfulResponseCodeException { 10 | public NoContentException(String s) { 11 | super(204, s); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/NoSuchSessionException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | class NoSuchSessionException : NonSuccessfulResponseCodeException(404) 4 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/NonSuccessfulResumableUploadResponseCodeException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class NonSuccessfulResumableUploadResponseCodeException extends NonSuccessfulResponseCodeException { 4 | public NonSuccessfulResumableUploadResponseCodeException(int code, String s) { 5 | super(code, s); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/NotFoundException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | public class NotFoundException extends NonSuccessfulResponseCodeException { 10 | public NotFoundException(String s) { 11 | super(404, s); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/PushNetworkException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | import java.io.IOException; 10 | 11 | public class PushNetworkException extends IOException { 12 | 13 | public PushNetworkException(Exception exception) { 14 | super(exception); 15 | } 16 | 17 | public PushNetworkException(String s) { 18 | super(s); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/RangeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | *

4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | public final class RangeException extends NonSuccessfulResponseCodeException { 10 | 11 | public RangeException(long requested) { 12 | super(416, "Range request out of bounds " + requested); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/RateLimitException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | 10 | import java.util.Optional; 11 | 12 | public class RateLimitException extends NonSuccessfulResponseCodeException { 13 | private final Optional retryAfterMilliseconds; 14 | 15 | public RateLimitException(int status, String message) { 16 | this(status, message, Optional.empty()); 17 | } 18 | 19 | public RateLimitException(int status, String message, Optional retryAfterMilliseconds) { 20 | super(status, message); 21 | this.retryAfterMilliseconds = retryAfterMilliseconds; 22 | } 23 | 24 | public Optional getRetryAfterMilliseconds() { 25 | return retryAfterMilliseconds; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/RemoteAttestationResponseExpiredException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | public class RemoteAttestationResponseExpiredException extends NonSuccessfulResponseCodeException { 10 | public RemoteAttestationResponseExpiredException(String message) { 11 | super(409, message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/RequestVerificationCodeRateLimitException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.push.exceptions 7 | 8 | import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse 9 | 10 | /** 11 | * Rate limit exception specific to requesting a verification code for registration. 12 | */ 13 | class RequestVerificationCodeRateLimitException( 14 | val sessionMetadata: RegistrationSessionMetadataResponse 15 | ) : NonSuccessfulResponseCodeException(429, "User request verification code rate limited") 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ResumeLocationInvalidException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | import java.io.IOException; 4 | 5 | public class ResumeLocationInvalidException extends IOException { 6 | 7 | public ResumeLocationInvalidException() { 8 | super(); 9 | } 10 | 11 | public ResumeLocationInvalidException(String s) { 12 | super(s); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/ServerRejectedException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | /** 4 | * Indicates the server has rejected the request and we should stop retrying. 5 | */ 6 | public class ServerRejectedException extends NonSuccessfulResponseCodeException { 7 | public ServerRejectedException() { 8 | super(508); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/SubmitVerificationCodeRateLimitException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.push.exceptions 7 | 8 | import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse 9 | 10 | /** 11 | * Rate limit exception specific to submitting verification codes during registration. 12 | */ 13 | class SubmitVerificationCodeRateLimitException( 14 | val sessionMetadata: RegistrationSessionMetadataResponse 15 | ) : NonSuccessfulResponseCodeException(429, "User submit verification code rate limited") 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/TokenNotAcceptedException.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions 2 | 3 | /** 4 | * Exception representing that the submitted information was not accepted (e.g. the push challenge token or captcha did not match) 5 | */ 6 | class TokenNotAcceptedException : NonSuccessfulResponseCodeException(403) 7 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/UnregisteredUserException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.push.exceptions; 8 | 9 | import java.io.IOException; 10 | 11 | public class UnregisteredUserException extends IOException { 12 | 13 | private final String e164number; 14 | 15 | public UnregisteredUserException(String e164number, Exception exception) { 16 | super(exception); 17 | this.e164number = e164number; 18 | } 19 | 20 | public String getE164Number() { 21 | return e164number; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/UsernameIsNotAssociatedWithAnAccountException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class UsernameIsNotAssociatedWithAnAccountException extends NotFoundException { 4 | public UsernameIsNotAssociatedWithAnAccountException() { 5 | super("The given username is not associated with an account."); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/UsernameIsNotReservedException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class UsernameIsNotReservedException extends NonSuccessfulResponseCodeException { 4 | public UsernameIsNotReservedException() { 5 | super(409, "The given username is not associated with an account."); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/UsernameMalformedException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class UsernameMalformedException extends NonSuccessfulResponseCodeException { 4 | public UsernameMalformedException() { 5 | super(400); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/push/exceptions/UsernameTakenException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.push.exceptions; 2 | 3 | public class UsernameTakenException extends NonSuccessfulResponseCodeException { 4 | public UsernameTakenException() { 5 | super(409); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/ratelimit/SubmitPushChallengePayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.ratelimit; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | class SubmitPushChallengePayload { 11 | 12 | @JsonProperty 13 | private String type; 14 | 15 | @JsonProperty 16 | private String challenge; 17 | 18 | public SubmitPushChallengePayload() {} 19 | 20 | public SubmitPushChallengePayload(String challenge) { 21 | this.type = "rateLimitPushChallenge"; 22 | this.challenge = challenge; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/ratelimit/SubmitRecaptchaChallengePayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.ratelimit; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | class SubmitRecaptchaChallengePayload { 11 | 12 | @JsonProperty 13 | private String type; 14 | 15 | @JsonProperty 16 | private String token; 17 | 18 | @JsonProperty 19 | private String captcha; 20 | 21 | public SubmitRecaptchaChallengePayload() {} 22 | 23 | public SubmitRecaptchaChallengePayload(String challenge, String recaptchaToken) { 24 | this.type = "captcha"; 25 | this.token = challenge; 26 | this.captcha = recaptchaToken; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/registration/RestoreMethodBody.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.registration 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import com.fasterxml.jackson.annotation.JsonProperty 10 | import org.whispersystems.signalservice.api.provisioning.RestoreMethod 11 | 12 | /** 13 | * Request and response body used to communicate a quick restore method selection during registration. 14 | */ 15 | data class RestoreMethodBody @JsonCreator constructor( 16 | @JsonProperty val method: RestoreMethod? 17 | ) 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/remoteconfig/RemoteConfigResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.remoteconfig; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | import java.util.List; 11 | 12 | import javax.annotation.Nullable; 13 | 14 | public class RemoteConfigResponse { 15 | @JsonProperty 16 | private List config; 17 | 18 | public List getConfig() { 19 | return config; 20 | } 21 | 22 | public static class Config { 23 | @JsonProperty 24 | private String name; 25 | 26 | @JsonProperty 27 | private boolean enabled; 28 | 29 | @JsonProperty 30 | private String value; 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | public boolean isEnabled() { 37 | return enabled; 38 | } 39 | 40 | public @Nullable String getValue() { 41 | return value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/remoteconfig/RemoteConfigResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.remoteconfig 7 | 8 | data class RemoteConfigResult( 9 | val config: Map, 10 | val serverEpochTimeMilliseconds: Long 11 | ) 12 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/ContactRecordExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.storage 7 | 8 | import org.whispersystems.signalservice.api.push.ServiceId 9 | import org.whispersystems.signalservice.internal.storage.protos.ContactRecord 10 | 11 | val ContactRecord.signalAci: ServiceId.ACI? 12 | get() = ServiceId.ACI.parseOrNull(this.aci) 13 | 14 | val ContactRecord.signalPni: ServiceId.PNI? 15 | get() = ServiceId.PNI.parseOrNull(this.pni) 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.AccountRecord 4 | import java.io.IOException 5 | 6 | /** 7 | * Wrapper around a [AccountRecord] to pair it with a [StorageId]. 8 | */ 9 | data class SignalAccountRecord( 10 | override val id: StorageId, 11 | override val proto: AccountRecord 12 | ) : SignalRecord { 13 | 14 | companion object { 15 | fun newBuilder(serializedUnknowns: ByteArray?): AccountRecord.Builder { 16 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: AccountRecord.Builder() 17 | } 18 | 19 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): AccountRecord.Builder { 20 | return try { 21 | AccountRecord.ADAPTER.decode(serializedUnknowns).newBuilder() 22 | } catch (e: IOException) { 23 | AccountRecord.Builder() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalCallLinkRecord.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.storage 7 | 8 | import org.whispersystems.signalservice.internal.storage.protos.CallLinkRecord 9 | import java.io.IOException 10 | 11 | /** 12 | * Wrapper around a [CallLinkRecord] to pair it with a [StorageId]. 13 | */ 14 | data class SignalCallLinkRecord( 15 | override val id: StorageId, 16 | override val proto: CallLinkRecord 17 | ) : SignalRecord { 18 | 19 | companion object { 20 | fun newBuilder(serializedUnknowns: ByteArray?): CallLinkRecord.Builder { 21 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: CallLinkRecord.Builder() 22 | } 23 | 24 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): CallLinkRecord.Builder { 25 | return try { 26 | CallLinkRecord.ADAPTER.decode(serializedUnknowns).newBuilder() 27 | } catch (e: IOException) { 28 | CallLinkRecord.Builder() 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalChatFolderRecord.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.ChatFolderRecord 4 | import java.io.IOException 5 | 6 | /** 7 | * Wrapper around a [ChatFolderRecord] to pair it with a [StorageId]. 8 | */ 9 | data class SignalChatFolderRecord( 10 | override val id: StorageId, 11 | override val proto: ChatFolderRecord 12 | ) : SignalRecord { 13 | 14 | companion object { 15 | fun newBuilder(serializedUnknowns: ByteArray?): ChatFolderRecord.Builder { 16 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: ChatFolderRecord.Builder() 17 | } 18 | 19 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): ChatFolderRecord.Builder { 20 | return try { 21 | ChatFolderRecord.ADAPTER.decode(serializedUnknowns).newBuilder() 22 | } catch (e: IOException) { 23 | ChatFolderRecord.Builder() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalContactRecord.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.ContactRecord 4 | import java.io.IOException 5 | 6 | /** 7 | * Wrapper around a [ContactRecord] to pair it with a [StorageId]. 8 | */ 9 | data class SignalContactRecord( 10 | override val id: StorageId, 11 | override val proto: ContactRecord 12 | ) : SignalRecord { 13 | 14 | companion object { 15 | fun newBuilder(serializedUnknowns: ByteArray?): ContactRecord.Builder { 16 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: ContactRecord.Builder() 17 | } 18 | 19 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): ContactRecord.Builder { 20 | return try { 21 | ContactRecord.ADAPTER.decode(serializedUnknowns).newBuilder() 22 | } catch (e: IOException) { 23 | ContactRecord.Builder() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV1Record.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record 4 | import java.io.IOException 5 | 6 | /** 7 | * Wrapper around a [GroupV1Record] to pair it with a [StorageId]. 8 | */ 9 | data class SignalGroupV1Record( 10 | override val id: StorageId, 11 | override val proto: GroupV1Record 12 | ) : SignalRecord { 13 | 14 | companion object { 15 | fun newBuilder(serializedUnknowns: ByteArray?): GroupV1Record.Builder { 16 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: GroupV1Record.Builder() 17 | } 18 | 19 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): GroupV1Record.Builder { 20 | return try { 21 | GroupV1Record.ADAPTER.decode(serializedUnknowns).newBuilder() 22 | } catch (e: IOException) { 23 | GroupV1Record.Builder() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalGroupV2Record.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record 4 | import java.io.IOException 5 | 6 | /** 7 | * Wrapper around a [GroupV2Record] to pair it with a [StorageId]. 8 | */ 9 | data class SignalGroupV2Record( 10 | override val id: StorageId, 11 | override val proto: GroupV2Record 12 | ) : SignalRecord { 13 | 14 | companion object { 15 | fun newBuilder(serializedUnknowns: ByteArray?): GroupV2Record.Builder { 16 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: GroupV2Record.Builder() 17 | } 18 | 19 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): GroupV2Record.Builder { 20 | return try { 21 | GroupV2Record.ADAPTER.decode(serializedUnknowns).newBuilder() 22 | } catch (e: IOException) { 23 | GroupV2Record.Builder() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalNotificationProfileRecord.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.NotificationProfile 4 | import java.io.IOException 5 | 6 | /** 7 | * Wrapper around a [NotificationProfile] to pair it with a [StorageId]. 8 | */ 9 | data class SignalNotificationProfileRecord( 10 | override val id: StorageId, 11 | override val proto: NotificationProfile 12 | ) : SignalRecord { 13 | 14 | companion object { 15 | fun newBuilder(serializedUnknowns: ByteArray?): NotificationProfile.Builder { 16 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: NotificationProfile.Builder() 17 | } 18 | 19 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): NotificationProfile.Builder { 20 | return try { 21 | NotificationProfile.ADAPTER.decode(serializedUnknowns).newBuilder() 22 | } catch (e: IOException) { 23 | NotificationProfile.Builder() 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStorageRecord.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.StorageRecord 4 | 5 | /** 6 | * A wrapper around [StorageRecord] to pair it with a [StorageId]. 7 | */ 8 | data class SignalStorageRecord( 9 | val id: StorageId, 10 | val proto: StorageRecord 11 | ) { 12 | val isUnknown: Boolean 13 | get() = proto.contact == null && proto.groupV1 == null && proto.groupV2 == null && proto.account == null && proto.storyDistributionList == null && proto.callLink == null && proto.chatFolder == null && proto.notificationProfile == null 14 | 15 | companion object { 16 | @JvmStatic 17 | fun forUnknown(key: StorageId): SignalStorageRecord { 18 | return SignalStorageRecord(key, proto = StorageRecord()) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/SignalStoryDistributionListRecord.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | import org.whispersystems.signalservice.internal.storage.protos.StoryDistributionListRecord 4 | import java.io.IOException 5 | 6 | data class SignalStoryDistributionListRecord( 7 | override val id: StorageId, 8 | override val proto: StoryDistributionListRecord 9 | ) : SignalRecord { 10 | 11 | companion object { 12 | fun newBuilder(serializedUnknowns: ByteArray?): StoryDistributionListRecord.Builder { 13 | return serializedUnknowns?.let { builderFromUnknowns(it) } ?: StoryDistributionListRecord.Builder() 14 | } 15 | 16 | private fun builderFromUnknowns(serializedUnknowns: ByteArray): StoryDistributionListRecord.Builder { 17 | return try { 18 | StoryDistributionListRecord.ADAPTER.decode(serializedUnknowns).newBuilder() 19 | } catch (e: IOException) { 20 | StoryDistributionListRecord.Builder() 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/StorageAuthResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class StorageAuthResponse { 6 | 7 | @JsonProperty 8 | private String username; 9 | 10 | @JsonProperty 11 | private String password; 12 | 13 | public StorageAuthResponse() { } 14 | 15 | public StorageAuthResponse(String username, String password) { 16 | this.username = username; 17 | this.password = password; 18 | } 19 | 20 | public String getUsername() { 21 | return username; 22 | } 23 | 24 | public String getPassword() { 25 | return password; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/StorageCipherKey.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | interface StorageCipherKey { 4 | fun serialize(): ByteArray 5 | } 6 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/StorageItemKey.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | /** 4 | * Key used to encrypt individual storage items in the storage service. 5 | * 6 | * Created via [StorageKey.deriveItemKey]. 7 | */ 8 | class StorageItemKey(val key: ByteArray) : StorageCipherKey { 9 | init { 10 | check(key.size == 32) 11 | } 12 | 13 | override fun serialize(): ByteArray = key.clone() 14 | 15 | override fun equals(other: Any?): Boolean { 16 | if (this === other) return true 17 | if (javaClass != other?.javaClass) return false 18 | 19 | other as StorageItemKey 20 | 21 | return key.contentEquals(other.key) 22 | } 23 | 24 | override fun hashCode(): Int { 25 | return key.contentHashCode() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/StorageManifestKey.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.storage 2 | 3 | /** 4 | * Key used to encrypt a manifest in the storage service. 5 | * 6 | * Created via [StorageKey.deriveManifestKey]. 7 | */ 8 | class StorageManifestKey(val key: ByteArray) : StorageCipherKey { 9 | init { 10 | check(key.size == 32) 11 | } 12 | 13 | override fun serialize(): ByteArray = key.clone() 14 | 15 | override fun equals(other: Any?): Boolean { 16 | if (this === other) return true 17 | if (javaClass != other?.javaClass) return false 18 | 19 | other as StorageManifestKey 20 | 21 | return key.contentEquals(other.key) 22 | } 23 | 24 | override fun hashCode(): Int { 25 | return key.contentHashCode() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/StorageRecordProtoUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | @file:JvmName("StorageRecordProtoUtil") 7 | 8 | package org.whispersystems.signalservice.api.storage 9 | 10 | import org.whispersystems.signalservice.internal.storage.protos.AccountRecord 11 | 12 | /** 13 | * Provide helpers for various Storage Service protos. 14 | */ 15 | object StorageRecordProtoUtil { 16 | 17 | /** Must match tag value specified for ManifestRecord.Identifier#type in StorageService.proto */ 18 | const val STORAGE_ID_TYPE_TAG = 2 19 | 20 | @JvmStatic 21 | val defaultAccountRecord by lazy { AccountRecord() } 22 | } 23 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/storage/StoryDistributionListRecordExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.storage 7 | 8 | import org.whispersystems.signalservice.api.push.ServiceId 9 | import org.whispersystems.signalservice.api.push.SignalServiceAddress 10 | import org.whispersystems.signalservice.internal.storage.protos.StoryDistributionListRecord 11 | 12 | val StoryDistributionListRecord.recipientServiceAddresses: List 13 | get() { 14 | return this.recipientServiceIds 15 | .mapNotNull { ServiceId.parseOrNull(it) } 16 | .map { SignalServiceAddress(it) } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/subscriptions/PayPalConfirmPaymentIntentResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.subscriptions; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | /** 7 | * Response object from creating a payment intent via PayPal 8 | */ 9 | public class PayPalConfirmPaymentIntentResponse { 10 | 11 | private final String paymentId; 12 | 13 | @JsonCreator 14 | public PayPalConfirmPaymentIntentResponse(@JsonProperty("paymentId") String paymentId) { 15 | this.paymentId = paymentId; 16 | } 17 | 18 | public String getPaymentId() { 19 | return paymentId; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/subscriptions/PayPalCreatePaymentIntentResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.subscriptions; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | /** 7 | * Response object from creating a payment intent via PayPal 8 | */ 9 | public class PayPalCreatePaymentIntentResponse { 10 | 11 | private final String approvalUrl; 12 | private final String paymentId; 13 | 14 | @JsonCreator 15 | public PayPalCreatePaymentIntentResponse(@JsonProperty("approvalUrl") String approvalUrl, @JsonProperty("paymentId") String paymentId) { 16 | this.approvalUrl = approvalUrl; 17 | this.paymentId = paymentId; 18 | } 19 | 20 | public String getApprovalUrl() { 21 | return approvalUrl; 22 | } 23 | 24 | public String getPaymentId() { 25 | return paymentId; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/subscriptions/PayPalCreatePaymentMethodResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.subscriptions; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class PayPalCreatePaymentMethodResponse { 7 | private final String approvalUrl; 8 | private final String token; 9 | 10 | @JsonCreator 11 | public PayPalCreatePaymentMethodResponse(@JsonProperty("approvalUrl") String approvalUrl, @JsonProperty("token") String token) { 12 | this.approvalUrl = approvalUrl; 13 | this.token = token; 14 | } 15 | 16 | public String getApprovalUrl() { 17 | return approvalUrl; 18 | } 19 | 20 | public String getToken() { 21 | return token; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/subscriptions/StripeClientSecret.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.subscriptions; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public final class StripeClientSecret { 7 | 8 | private final String id; 9 | private final String clientSecret; 10 | 11 | @JsonCreator 12 | public StripeClientSecret(@JsonProperty("clientSecret") String clientSecret) { 13 | this.id = clientSecret.replaceFirst("_secret.*", ""); 14 | this.clientSecret = clientSecret; 15 | } 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public String getClientSecret() { 22 | return clientSecret; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/svr/SetShareSetRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.svr 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | import com.fasterxml.jackson.databind.annotation.JsonSerialize 10 | import org.whispersystems.signalservice.internal.push.ByteArraySerializerBase64NoPadding 11 | 12 | /** 13 | * Request body for setting a share-set on the service. 14 | */ 15 | class SetShareSetRequest( 16 | @JsonProperty 17 | @JsonSerialize(using = ByteArraySerializerBase64NoPadding::class) 18 | val shareSet: ByteArray 19 | ) 20 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/svr/Svr3Credentials.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.svr 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize 10 | import org.whispersystems.signalservice.internal.push.AuthCredentials 11 | import org.whispersystems.signalservice.internal.push.ByteArrayDeserializerBase64 12 | 13 | /** 14 | * Response object when fetching SVR3 auth credentials. We also use it elsewhere as a convenient container 15 | * for the (username, password, shareset) tuple. 16 | */ 17 | class Svr3Credentials( 18 | @JsonProperty 19 | val username: String, 20 | 21 | @JsonProperty 22 | val password: String, 23 | 24 | @JsonProperty 25 | @JsonDeserialize(using = ByteArrayDeserializerBase64::class) 26 | val shareSet: ByteArray? 27 | ) { 28 | val authCredentials: AuthCredentials 29 | get() = AuthCredentials.create(username, password) 30 | } 31 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/CredentialsProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.util; 8 | 9 | import org.whispersystems.signalservice.api.push.ServiceId.ACI; 10 | import org.whispersystems.signalservice.api.push.ServiceId.PNI; 11 | import org.whispersystems.signalservice.api.push.SignalServiceAddress; 12 | 13 | public interface CredentialsProvider { 14 | ACI getAci(); 15 | PNI getPni(); 16 | String getE164(); 17 | int getDeviceId(); 18 | String getPassword(); 19 | 20 | default boolean isInvalid() { 21 | return getAci() == null || getPassword() == null; 22 | } 23 | 24 | default String getUsername() { 25 | StringBuilder sb = new StringBuilder(); 26 | sb.append(getAci().toString()); 27 | if (getDeviceId() != SignalServiceAddress.DEFAULT_DEVICE_ID) { 28 | sb.append("."); 29 | sb.append(getDeviceId()); 30 | } 31 | return sb.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/ExpiringProfileCredentialUtil.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.util; 2 | 3 | import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential; 4 | 5 | import java.time.temporal.ChronoField; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public final class ExpiringProfileCredentialUtil { 9 | 10 | private ExpiringProfileCredentialUtil() {} 11 | 12 | public static boolean isValid(ExpiringProfileKeyCredential credential) { 13 | if (credential == null) { 14 | return false; 15 | } 16 | 17 | long now = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); 18 | long expires = credential.getExpirationTime().getLong(ChronoField.INSTANT_SECONDS); 19 | return now < expires; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/InvalidNumberException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.api.util; 8 | 9 | public class InvalidNumberException extends Throwable { 10 | public InvalidNumberException(String s) { 11 | super(s); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/SleepTimer.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.util; 2 | 3 | public interface SleepTimer { 4 | public void sleep(long millis) throws InterruptedException; 5 | } 6 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/Uint64RangeException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.util; 2 | 3 | public final class Uint64RangeException extends Exception { 4 | Uint64RangeException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/UptimeSleepTimer.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.util; 2 | 3 | /** 4 | * A simle sleep timer. Since Thread.sleep is based on uptime 5 | * this will not work properly in low-power sleep modes, when 6 | * the CPU is suspended and uptime does not elapse. 7 | * 8 | */ 9 | public class UptimeSleepTimer implements SleepTimer { 10 | @Override 11 | public void sleep(long millis) throws InterruptedException { 12 | Thread.sleep(millis); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/UsernameExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.util 7 | 8 | import org.signal.libsignal.usernames.Username 9 | 10 | val Username.nickname: String get() = username.split(Usernames.DELIMITER)[0] 11 | val Username.discriminator: String get() = username.split(Usernames.DELIMITER)[1] 12 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/Usernames.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.util 7 | 8 | object Usernames { 9 | const val DELIMITER = "." 10 | } 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/util/UuidExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.util 7 | 8 | import java.util.UUID 9 | 10 | fun UUID.toByteArray(): ByteArray = UuidUtil.toByteArray(this) 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/websocket/HealthMonitor.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.websocket 2 | 3 | /** 4 | * Callbacks to provide WebSocket health information to a monitor. 5 | */ 6 | interface HealthMonitor { 7 | fun onKeepAliveResponse(sentTimestamp: Long, isIdentifiedWebSocket: Boolean) 8 | 9 | fun onMessageError(status: Int, isIdentifiedWebSocket: Boolean) 10 | } 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketConnectionState.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.websocket; 2 | 3 | /** 4 | * Represent the state of a single WebSocketConnection. 5 | */ 6 | public enum WebSocketConnectionState { 7 | DISCONNECTED, 8 | CONNECTING, 9 | CONNECTED, 10 | DISCONNECTING, 11 | AUTHENTICATION_FAILED, 12 | REMOTE_DEPRECATED, 13 | FAILED; 14 | 15 | public boolean isFailure() { 16 | return this == AUTHENTICATION_FAILED || this == REMOTE_DEPRECATED || this == FAILED; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketFactory.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.websocket; 2 | 3 | import org.whispersystems.signalservice.internal.websocket.WebSocketConnection; 4 | 5 | public interface WebSocketFactory { 6 | WebSocketConnection createConnection() throws WebSocketUnavailableException; 7 | } 8 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/api/websocket/WebSocketUnavailableException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.websocket; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Thrown when the WebSocket is not available for use by runtime policy. Currently, the 7 | * WebSocket is only unavailable when networking is blocked by a device transfer or if 8 | * requesting to connect via auth but provide no auth credentials. 9 | */ 10 | public final class WebSocketUnavailableException extends IOException { 11 | public WebSocketUnavailableException() { 12 | super("WebSocket not currently available."); 13 | } 14 | 15 | public WebSocketUnavailableException(String reason) { 16 | super("WebSocket not currently available. Reason: " + reason); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/EmptyResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal; 2 | 3 | /** 4 | * Indicates that no data is returned from a given service call. 5 | */ 6 | public enum EmptyResponse { 7 | INSTANCE 8 | } 9 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/HttpProxy.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration 2 | 3 | /** 4 | * HTTP Proxy configuration from Android OS configuration. 5 | */ 6 | class HttpProxy(val host: String, val port: Int) 7 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalCdnUrl.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.TrustStore; 5 | 6 | import okhttp3.ConnectionSpec; 7 | 8 | public class SignalCdnUrl extends SignalUrl { 9 | public SignalCdnUrl(String url, TrustStore trustStore) { 10 | super(url, trustStore); 11 | } 12 | 13 | public SignalCdnUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) { 14 | super(url, hostHeader, trustStore, connectionSpec); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalCdsiUrl.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.TrustStore; 5 | 6 | import okhttp3.ConnectionSpec; 7 | 8 | public class SignalCdsiUrl extends SignalUrl { 9 | 10 | public SignalCdsiUrl(String url, TrustStore trustStore) { 11 | super(url, trustStore); 12 | } 13 | 14 | public SignalCdsiUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) { 15 | super(url, hostHeader, trustStore, connectionSpec); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalProxy.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration; 2 | 3 | public class SignalProxy { 4 | private final String host; 5 | private final int port; 6 | 7 | public SignalProxy(String host, int port) { 8 | this.host = host; 9 | this.port = port; 10 | } 11 | 12 | public String getHost() { 13 | return host; 14 | } 15 | 16 | public int getPort() { 17 | return port; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalServiceUrl.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.TrustStore; 5 | 6 | import okhttp3.ConnectionSpec; 7 | 8 | public class SignalServiceUrl extends SignalUrl { 9 | 10 | public SignalServiceUrl(String url, TrustStore trustStore) { 11 | super(url, trustStore); 12 | } 13 | 14 | public SignalServiceUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) { 15 | super(url, hostHeader, trustStore, connectionSpec); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalStorageUrl.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.TrustStore; 5 | 6 | import okhttp3.ConnectionSpec; 7 | 8 | public class SignalStorageUrl extends SignalUrl { 9 | 10 | public SignalStorageUrl(String url, TrustStore trustStore) { 11 | super(url, trustStore); 12 | } 13 | 14 | public SignalStorageUrl(String url, String hostHeader, TrustStore trustStore, ConnectionSpec connectionSpec) { 15 | super(url, hostHeader, trustStore, connectionSpec); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalSvr2Url.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.configuration 2 | 3 | import okhttp3.ConnectionSpec 4 | import org.whispersystems.signalservice.api.push.TrustStore 5 | 6 | /** 7 | * Configuration for reach the SVR2 service. 8 | */ 9 | class SignalSvr2Url( 10 | url: String, 11 | trustStore: TrustStore, 12 | hostHeader: String? = null, 13 | connectionSpec: ConnectionSpec? = null 14 | ) : SignalUrl(url, hostHeader, trustStore, connectionSpec) 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/contacts/entities/KeyBackupResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.contacts.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import org.whispersystems.signalservice.internal.util.Hex; 6 | 7 | public class KeyBackupResponse { 8 | 9 | @JsonProperty 10 | private byte[] iv; 11 | 12 | @JsonProperty 13 | private byte[] data; 14 | 15 | @JsonProperty 16 | private byte[] mac; 17 | 18 | public KeyBackupResponse() {} 19 | 20 | public KeyBackupResponse(byte[] iv, byte[] data, byte[] mac) { 21 | this.iv = iv; 22 | this.data = data; 23 | this.mac = mac; 24 | } 25 | 26 | public byte[] getIv() { 27 | return iv; 28 | } 29 | 30 | public byte[] getData() { 31 | return data; 32 | } 33 | 34 | public byte[] getMac() { 35 | return mac; 36 | } 37 | 38 | public String toString() { 39 | return "{iv: " + (iv == null ? null : Hex.toString(iv)) + ", data: " + (data == null ? null: Hex.toString(data)) + ", mac: " + (mac == null ? null : Hex.toString(mac)) + "}"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/contacts/entities/MultiRemoteAttestationResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.contacts.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.Map; 6 | 7 | public class MultiRemoteAttestationResponse { 8 | 9 | @JsonProperty 10 | private Map attestations; 11 | 12 | public Map getAttestations() { 13 | return attestations; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/contacts/entities/QueryEnvelope.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.contacts.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class QueryEnvelope { 6 | 7 | @JsonProperty 8 | private byte[] requestId; 9 | 10 | @JsonProperty 11 | private byte[] iv; 12 | 13 | @JsonProperty 14 | private byte[] data; 15 | 16 | @JsonProperty 17 | private byte[] mac; 18 | 19 | public QueryEnvelope() { } 20 | 21 | public QueryEnvelope(byte[] requestId, byte[] iv, byte[] data, byte[] mac) { 22 | this.requestId = requestId; 23 | this.iv = iv; 24 | this.data = data; 25 | this.mac = mac; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/contacts/entities/TokenResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.contacts.entities; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class TokenResponse { 7 | 8 | @JsonProperty 9 | private byte[] backupId; 10 | 11 | @JsonProperty 12 | private byte[] token; 13 | 14 | @JsonProperty 15 | private int tries; 16 | 17 | @JsonCreator 18 | public TokenResponse() { 19 | } 20 | 21 | public TokenResponse(byte[] backupId, byte[] token, int tries) { 22 | this.backupId = backupId; 23 | this.token = token; 24 | this.tries = tries; 25 | } 26 | 27 | public byte[] getBackupId() { 28 | return backupId; 29 | } 30 | 31 | public byte[] getToken() { 32 | return token; 33 | } 34 | 35 | public int getTries() { 36 | return tries; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/crypto/AttachmentDigest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.crypto 7 | 8 | data class AttachmentDigest( 9 | val digest: ByteArray, 10 | val incrementalDigest: ByteArray?, 11 | val incrementalMacChunkSize: Int 12 | ) 13 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/AttachmentUploadForm.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | /** 6 | * Represents an attachment upload form that can be returned by various service endpoints. 7 | */ 8 | data class AttachmentUploadForm( 9 | @JvmField 10 | @JsonProperty 11 | val cdn: Int, 12 | 13 | @JvmField 14 | @JsonProperty 15 | val key: String, 16 | 17 | @JvmField 18 | @JsonProperty 19 | val headers: Map, 20 | 21 | @JvmField 22 | @JsonProperty 23 | val signedUploadLocation: String 24 | ) 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/AuthCredentials.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import okhttp3.Credentials; 6 | 7 | public class AuthCredentials { 8 | 9 | @JsonProperty 10 | private String username; 11 | 12 | @JsonProperty 13 | private String password; 14 | 15 | public static AuthCredentials create(String username, String password) { 16 | AuthCredentials authCredentials = new AuthCredentials(); 17 | authCredentials.username = username; 18 | authCredentials.password = password; 19 | return authCredentials; 20 | } 21 | 22 | public String asBasic() { 23 | return Credentials.basic(username, password); 24 | } 25 | 26 | public String username() { return username; } 27 | 28 | public String password() { return password; } 29 | 30 | @Override 31 | public String toString() { 32 | return "AuthCredentials(xxx)"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/BackupAuthCheckProcessor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import org.whispersystems.signalservice.internal.ServiceResponse 9 | import org.whispersystems.signalservice.internal.ServiceResponseProcessor 10 | 11 | /** 12 | * Processes a response from the verify stored KBS auth credentials request. 13 | */ 14 | class BackupAuthCheckProcessor(response: ServiceResponse) : ServiceResponseProcessor(response) { 15 | fun getInvalid(): List { 16 | return response.result.map { it.invalid }.orElse(emptyList()) 17 | } 18 | 19 | fun hasValidSvr2AuthCredential(): Boolean { 20 | return response.result.map { it.match }.orElse(null) != null 21 | } 22 | 23 | fun requireSvr2AuthCredential(): AuthCredentials { 24 | return response.result.get().match!! 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/BackupAuthCheckRequest.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | /** 6 | * Request body JSON for verifying stored KBS auth credentials. 7 | */ 8 | class BackupAuthCheckRequest( 9 | @JsonProperty 10 | val number: String?, 11 | 12 | @JsonProperty 13 | val passwords: List 14 | ) 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/BankMandate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import com.fasterxml.jackson.annotation.JsonProperty 10 | 11 | /** 12 | * Localized bank transfer mandate. 13 | */ 14 | class BankMandate @JsonCreator constructor(@JsonProperty("mandate") val mandate: String) 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ByteArrayDeserializerBase64.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.core.JsonParser 9 | import com.fasterxml.jackson.databind.DeserializationContext 10 | import com.fasterxml.jackson.databind.JsonDeserializer 11 | import org.signal.core.util.Base64 12 | 13 | /** 14 | * Deserializes any valid base64 (regardless of padding or url-safety) into a ByteArray. 15 | */ 16 | class ByteArrayDeserializerBase64 : JsonDeserializer() { 17 | override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ByteArray { 18 | return Base64.decode(p.valueAsString) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ByteArraySerializerBase64NoPadding.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.core.JsonGenerator 9 | import com.fasterxml.jackson.databind.JsonSerializer 10 | import com.fasterxml.jackson.databind.SerializerProvider 11 | import org.signal.core.util.Base64 12 | 13 | /** 14 | * JSON serializer to encode a ByteArray as a base64 string without padding. 15 | */ 16 | class ByteArraySerializerBase64NoPadding : JsonSerializer() { 17 | override fun serialize(value: ByteArray, gen: JsonGenerator, serializers: SerializerProvider) { 18 | gen.writeString(Base64.encodeWithoutPadding(value)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/CdsiAuthResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class CdsiAuthResponse { 6 | 7 | @JsonProperty 8 | private String username; 9 | 10 | @JsonProperty 11 | private String password; 12 | 13 | public String getUsername() { 14 | return username; 15 | } 16 | 17 | public String getPassword() { 18 | return password; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/CdsiResourceExhaustedResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * Response for {@link org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhaustedException} 7 | */ 8 | public class CdsiResourceExhaustedResponse { 9 | @JsonProperty("retry_after") 10 | private int retryAfter; 11 | 12 | public int getRetryAfter() { 13 | return retryAfter; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/CheckRepeatedUsedPreKeysRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty 9 | import com.fasterxml.jackson.databind.annotation.JsonSerialize 10 | 11 | /** 12 | * Request body to check if our prekeys match what's on the service. 13 | */ 14 | class CheckRepeatedUsedPreKeysRequest( 15 | @JsonProperty 16 | val identityType: String, 17 | 18 | @JsonProperty 19 | @JsonSerialize(using = ByteArraySerializerBase64NoPadding::class) 20 | val digest: ByteArray 21 | ) 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ConfirmUsernameRequest.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ConfirmUsernameRequest { 6 | @JsonProperty 7 | private String usernameHash; 8 | 9 | @JsonProperty 10 | private String zkProof; 11 | 12 | @JsonProperty 13 | private String encryptedUsername; 14 | 15 | public ConfirmUsernameRequest(String usernameHash, String zkProof, String encryptedUsername) { 16 | this.usernameHash = usernameHash; 17 | this.zkProof = zkProof; 18 | this.encryptedUsername = encryptedUsername; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ConfirmUsernameResponse.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize 5 | import org.whispersystems.signalservice.internal.util.JsonUtil 6 | import java.util.UUID 7 | 8 | /** Response body for confirming a username reservation. */ 9 | class ConfirmUsernameResponse( 10 | @JsonProperty 11 | val usernameHash: String, 12 | 13 | @JsonProperty 14 | @JsonDeserialize(using = JsonUtil.UuidDeserializer::class) 15 | val usernameLinkHandle: UUID 16 | ) 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ContactDiscoveryFailureReason.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ContactDiscoveryFailureReason { 6 | 7 | @JsonProperty 8 | private final String reason; 9 | 10 | public ContactDiscoveryFailureReason(String reason) { 11 | this.reason = reason == null ? "" : reason; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ContactTokenDetailsList.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.internal.push; 8 | 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | 11 | import org.whispersystems.signalservice.api.push.ContactTokenDetails; 12 | 13 | import java.util.List; 14 | 15 | public class ContactTokenDetailsList { 16 | 17 | @JsonProperty 18 | private List contacts; 19 | 20 | public ContactTokenDetailsList() {} 21 | 22 | public List getContacts() { 23 | return contacts; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/CreateCallLinkAuthRequest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import org.signal.core.util.Base64 10 | import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialRequest 11 | 12 | /** 13 | * Request body to create a call link credential response. 14 | */ 15 | data class CreateCallLinkAuthRequest @JsonCreator constructor( 16 | val createCallLinkCredentialRequest: String 17 | ) { 18 | companion object { 19 | @JvmStatic 20 | fun create(createCallLinkCredentialRequest: CreateCallLinkCredentialRequest): CreateCallLinkAuthRequest { 21 | return CreateCallLinkAuthRequest( 22 | Base64.encodeWithPadding(createCallLinkCredentialRequest.serialize()) 23 | ) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/CreateCallLinkAuthResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import com.fasterxml.jackson.annotation.JsonProperty 10 | import org.signal.core.util.Base64 11 | import org.signal.libsignal.zkgroup.calllinks.CreateCallLinkCredentialResponse 12 | 13 | /** 14 | * Response body for CreateCallLinkAuthResponse 15 | */ 16 | data class CreateCallLinkAuthResponse @JsonCreator constructor( 17 | @JsonProperty("credential") val credential: String 18 | ) { 19 | val createCallLinkCredentialResponse: CreateCallLinkCredentialResponse 20 | get() = CreateCallLinkCredentialResponse(Base64.decode(credential)) 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/DeviceId.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class DeviceId { 6 | 7 | @JsonProperty 8 | private int deviceId; 9 | 10 | public int getDeviceId() { 11 | return deviceId; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/DeviceInfoList.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo; 6 | 7 | import java.util.List; 8 | 9 | public class DeviceInfoList { 10 | 11 | @JsonProperty 12 | public List devices; 13 | 14 | public DeviceInfoList() {} 15 | 16 | public List getDevices() { 17 | return devices; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/DeviceLimit.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class DeviceLimit { 6 | 7 | @JsonProperty 8 | private int current; 9 | 10 | @JsonProperty 11 | private int max; 12 | 13 | public int getCurrent() { 14 | return current; 15 | } 16 | 17 | public int getMax() { 18 | return max; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/DeviceLimitExceededException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | public class DeviceLimitExceededException extends NonSuccessfulResponseCodeException { 6 | 7 | private final DeviceLimit deviceLimit; 8 | 9 | public DeviceLimitExceededException(DeviceLimit deviceLimit) { 10 | super(411); 11 | this.deviceLimit = deviceLimit; 12 | } 13 | 14 | public int getCurrent() { 15 | return deviceLimit.getCurrent(); 16 | } 17 | 18 | public int getMax() { 19 | return deviceLimit.getMax(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/DonationIntentResult.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class DonationIntentResult { 6 | @JsonProperty("id") 7 | private String id; 8 | 9 | @JsonProperty("client_secret") 10 | private String clientSecret; 11 | 12 | public DonationIntentResult(@JsonProperty("id") String id, @JsonProperty("client_secret") String clientSecret) { 13 | this.id = id; 14 | this.clientSecret = clientSecret; 15 | } 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public String getClientSecret() { 22 | return clientSecret; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/DonationProcessor.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * Represents the processor being used for a given payment, required when accessing 7 | * receipt credentials. 8 | */ 9 | public enum DonationProcessor { 10 | STRIPE("STRIPE"), 11 | PAYPAL("BRAINTREE"); 12 | 13 | private final String code; 14 | 15 | DonationProcessor(String code) { 16 | this.code = code; 17 | } 18 | 19 | public String getCode() { 20 | return code; 21 | } 22 | 23 | public static DonationProcessor fromCode(String code) { 24 | for (final DonationProcessor value : values()) { 25 | if (Objects.equals(code, value.code)) { 26 | return value; 27 | } 28 | } 29 | 30 | throw new IllegalArgumentException(code); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/GcmRegistrationId.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | package org.whispersystems.signalservice.internal.push 6 | 7 | import com.fasterxml.jackson.annotation.JsonProperty 8 | 9 | data class GcmRegistrationId( 10 | @JsonProperty val gcmRegistrationId: String, 11 | @JsonProperty val webSocketChannel: Boolean 12 | ) 13 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/GetAciByUsernameResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * JSON POJO that represents the returned ACI from a call to 7 | * /v1/account/username/[username] 8 | */ 9 | public class GetAciByUsernameResponse { 10 | @JsonProperty 11 | private String uuid; 12 | 13 | public GetAciByUsernameResponse() {} 14 | 15 | public String getUuid() { 16 | return uuid; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/GetCallingRelaysResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import com.fasterxml.jackson.annotation.JsonProperty 10 | import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo 11 | 12 | /** 13 | * Response body for GetCallingRelays 14 | */ 15 | data class GetCallingRelaysResponse @JsonCreator constructor( 16 | @JsonProperty("relays") val relays: List? 17 | ) 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/GetUsernameFromLinkResponseBody.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | /** Response body for looking up a username by link from the service. */ 6 | data class GetUsernameFromLinkResponseBody(@JsonProperty val usernameLinkEncryptedValue: String) 7 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/GroupMismatchedDevices.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * Represents the body of a 409 response from the service during a sender key send. 7 | */ 8 | public class GroupMismatchedDevices { 9 | @JsonProperty 10 | private String uuid; 11 | 12 | @JsonProperty 13 | private MismatchedDevices devices; 14 | 15 | public GroupMismatchedDevices() {} 16 | 17 | public String getUuid() { 18 | return uuid; 19 | } 20 | 21 | public MismatchedDevices getDevices() { 22 | return devices; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/GroupStaleDevices.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * Represents the body of a 410 response from the service during a sender key send. 7 | */ 8 | public class GroupStaleDevices { 9 | 10 | @JsonProperty 11 | private String uuid; 12 | 13 | @JsonProperty 14 | private StaleDevices devices; 15 | 16 | public String getUuid() { 17 | return uuid; 18 | } 19 | 20 | public StaleDevices getDevices() { 21 | return devices; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/LinkDeviceRequest.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import org.whispersystems.signalservice.api.account.AccountAttributes; 4 | import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; 5 | 6 | public record LinkDeviceRequest(String verificationCode, 7 | AccountAttributes accountAttributes, 8 | SignedPreKeyEntity aciSignedPreKey, 9 | SignedPreKeyEntity pniSignedPreKey, 10 | KyberPreKeyEntity aciPqLastResortPreKey, 11 | KyberPreKeyEntity pniPqLastResortPreKey 12 | ) { 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/MismatchedDevices.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.internal.push; 8 | 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | 11 | import java.util.List; 12 | 13 | public class MismatchedDevices { 14 | @JsonProperty 15 | public List missingDevices; 16 | 17 | @JsonProperty 18 | public List extraDevices; 19 | 20 | public List getMissingDevices() { 21 | return missingDevices; 22 | } 23 | 24 | public List getExtraDevices() { 25 | return extraDevices; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ProofRequiredResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public class ProofRequiredResponse { 8 | 9 | @JsonProperty 10 | public String token; 11 | 12 | @JsonProperty 13 | public List options; 14 | 15 | public ProofRequiredResponse() {} 16 | 17 | public String getToken() { 18 | return token; 19 | } 20 | 21 | public List getOptions() { 22 | return options; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/PushAttachmentData.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | package org.whispersystems.signalservice.internal.push 7 | 8 | import org.whispersystems.signalservice.api.messages.SignalServiceAttachment 9 | import org.whispersystems.signalservice.internal.push.http.CancelationSignal 10 | import org.whispersystems.signalservice.internal.push.http.OutputStreamFactory 11 | import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec 12 | import java.io.InputStream 13 | 14 | /** 15 | * A bundle of data needed to start an attachment upload. 16 | */ 17 | data class PushAttachmentData( 18 | val contentType: String?, 19 | val data: InputStream, 20 | val dataSize: Long, 21 | val incremental: Boolean, 22 | val outputStreamFactory: OutputStreamFactory, 23 | val listener: SignalServiceAttachment.ProgressListener?, 24 | val cancelationSignal: CancelationSignal?, 25 | val resumableUploadSpec: ResumableUploadSpec 26 | ) 27 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/RequestVerificationCodeResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | 4 | import java.util.Optional; 5 | 6 | public final class RequestVerificationCodeResponse { 7 | private final Optional fcmToken; 8 | 9 | public RequestVerificationCodeResponse(Optional fcmToken) { 10 | this.fcmToken = fcmToken; 11 | } 12 | 13 | public Optional getFcmToken() { 14 | return fcmToken; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ReserveUsernameRequest.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public class ReserveUsernameRequest { 8 | @JsonProperty 9 | private List usernameHashes; 10 | 11 | public ReserveUsernameRequest(List usernameHashes) { 12 | this.usernameHashes = usernameHashes; 13 | } 14 | 15 | List getUsernameHashes() { 16 | return usernameHashes; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/ReserveUsernameResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class ReserveUsernameResponse { 6 | @JsonProperty 7 | private String usernameHash; 8 | 9 | ReserveUsernameResponse() {} 10 | 11 | /** 12 | * Visible for testing. 13 | */ 14 | public ReserveUsernameResponse(String usernameHash) { 15 | this.usernameHash = usernameHash; 16 | } 17 | 18 | public String getUsernameHash() { 19 | return usernameHash; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/SendMessageResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class SendMessageResponse { 6 | 7 | @JsonProperty 8 | private boolean needsSync; 9 | 10 | private boolean sentUnidentfied; 11 | 12 | public SendMessageResponse() {} 13 | 14 | public SendMessageResponse(boolean needsSync, boolean sentUnidentified) { 15 | this.needsSync = needsSync; 16 | this.sentUnidentfied = sentUnidentified; 17 | } 18 | 19 | public boolean getNeedsSync() { 20 | return needsSync; 21 | } 22 | 23 | public boolean sentUnidentified() { 24 | return sentUnidentfied; 25 | } 26 | 27 | public void setSentUnidentfied(boolean value) { 28 | this.sentUnidentfied = value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/SetUsernameLinkRequestBody.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | /** Request body for setting a username link on the service. */ 6 | data class SetUsernameLinkRequestBody(@JsonProperty val usernameLinkEncryptedValue: String, @JsonProperty val keepLinkHandle: Boolean) 7 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/SetUsernameLinkResponseBody.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize 5 | import org.whispersystems.signalservice.internal.util.JsonUtil.UuidDeserializer 6 | import java.util.UUID 7 | 8 | /** Response body for setting a username link on the service. */ 9 | data class SetUsernameLinkResponseBody( 10 | @JsonProperty 11 | @JsonDeserialize(using = UuidDeserializer::class) 12 | val usernameLinkHandle: UUID 13 | ) 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/SetUsernameRequest.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | class SetUsernameRequest { 6 | @JsonProperty 7 | private String nickname; 8 | 9 | @JsonProperty 10 | private String existingUsername; 11 | 12 | SetUsernameRequest(String nickname, String existingUsername) { 13 | this.nickname = nickname; 14 | this.existingUsername = existingUsername; 15 | } 16 | 17 | String getNickname() { 18 | return nickname; 19 | } 20 | 21 | String getExistingUsername() { 22 | return existingUsername; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/SetUsernameResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | class SetUsernameResponse { 6 | @JsonProperty 7 | private String username; 8 | 9 | SetUsernameResponse() {} 10 | 11 | String getUsername() { 12 | return username; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/StaleDevices.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.internal.push; 8 | 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | 11 | import java.util.List; 12 | 13 | public class StaleDevices { 14 | 15 | @JsonProperty 16 | private List staleDevices; 17 | 18 | public List getStaleDevices() { 19 | return staleDevices; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/StickerUploadAttributesResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public class StickerUploadAttributesResponse { 8 | @JsonProperty 9 | private String packId; 10 | 11 | @JsonProperty 12 | private StickerUploadAttributes manifest; 13 | 14 | @JsonProperty 15 | private List stickers; 16 | 17 | public String getPackId() { 18 | return packId; 19 | } 20 | 21 | public StickerUploadAttributes getManifest() { 22 | return manifest; 23 | } 24 | 25 | public List getStickers() { 26 | return stickers; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/UpdateVerificationSessionRequestBody.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude 4 | import com.fasterxml.jackson.annotation.JsonProperty 5 | 6 | @JsonInclude(JsonInclude.Include.NON_NULL) 7 | data class UpdateVerificationSessionRequestBody( 8 | @JsonProperty val captcha: String?, 9 | @JsonProperty val pushToken: String?, 10 | @JsonProperty val pushChallenge: String?, 11 | @JsonProperty val mcc: String?, 12 | @JsonProperty val mnc: String? 13 | ) { 14 | @JsonProperty 15 | val pushTokenType: String? = if (pushToken != null) "fcm" else null 16 | } 17 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/VerificationCodeFailureResponseBody.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude 4 | import com.fasterxml.jackson.annotation.JsonProperty 5 | 6 | /** 7 | * Jackson parser for the response body from the server explaining a failure. 8 | * See also [org.whispersystems.signalservice.api.push.exceptions.ExternalServiceFailureException] 9 | */ 10 | @JsonInclude(JsonInclude.Include.NON_NULL) 11 | data class VerificationCodeFailureResponseBody( 12 | @JsonProperty("permanentFailure") val permanentFailure: Boolean, 13 | @JsonProperty("reason") val reason: String 14 | ) 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/VerificationSessionMetadataRequestBody.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude 4 | import com.fasterxml.jackson.annotation.JsonProperty 5 | 6 | @JsonInclude(JsonInclude.Include.NON_NULL) 7 | data class VerificationSessionMetadataRequestBody( 8 | @JsonProperty val number: String, 9 | @JsonProperty val pushToken: String?, 10 | @JsonProperty val mcc: String?, 11 | @JsonProperty val mnc: String? 12 | ) { 13 | @JsonProperty 14 | val pushTokenType: String? = if (pushToken != null) "fcm" else null 15 | } 16 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/VerifyAccountResponse.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | public class VerifyAccountResponse { 7 | @JsonProperty 8 | public String uuid; 9 | 10 | @JsonProperty 11 | public String pni; 12 | 13 | @JsonProperty 14 | public boolean storageCapable; 15 | 16 | @JsonProperty 17 | public String number; 18 | 19 | @JsonCreator 20 | public VerifyAccountResponse() {} 21 | 22 | public VerifyAccountResponse(String uuid, String pni, boolean storageCapable) { 23 | this.uuid = uuid; 24 | this.pni = pni; 25 | this.storageCapable = storageCapable; 26 | } 27 | 28 | public String getUuid() { 29 | return uuid; 30 | } 31 | 32 | public boolean isStorageCapable() { 33 | return storageCapable; 34 | } 35 | 36 | public String getPni() { 37 | return pni; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/CaptchaRejectedException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push.exceptions 7 | 8 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException 9 | 10 | /** 11 | * Indicates that the captcha we submitted was not accepted by the server. 12 | */ 13 | class CaptchaRejectedException : NonSuccessfulResponseCodeException(428, "Captcha rejected by server.") 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/ForbiddenException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 5 | 6 | import java.util.Optional; 7 | 8 | public final class ForbiddenException extends NonSuccessfulResponseCodeException { 9 | private Optional reason; 10 | 11 | public ForbiddenException() { 12 | this(Optional.empty()); 13 | } 14 | 15 | public ForbiddenException(Optional reason) { 16 | super(403); 17 | this.reason = reason; 18 | } 19 | 20 | public Optional getReason() { 21 | return reason; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/GroupExistsException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | public final class GroupExistsException extends NonSuccessfulResponseCodeException { 6 | public GroupExistsException() { 7 | super(409); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/GroupMismatchedDevicesException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | import org.whispersystems.signalservice.internal.push.GroupMismatchedDevices; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * Represents a 409 response from the service during a sender key send. 11 | */ 12 | public class GroupMismatchedDevicesException extends NonSuccessfulResponseCodeException { 13 | 14 | private final List mismatchedDevices; 15 | 16 | public GroupMismatchedDevicesException(GroupMismatchedDevices[] mismatchedDevices) { 17 | super(409); 18 | this.mismatchedDevices = Arrays.asList(mismatchedDevices); 19 | } 20 | 21 | public List getMismatchedDevices() { 22 | return mismatchedDevices; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/GroupNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | public final class GroupNotFoundException extends NonSuccessfulResponseCodeException { 6 | public GroupNotFoundException() { 7 | super(404); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/GroupPatchNotAcceptedException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | public final class GroupPatchNotAcceptedException extends NonSuccessfulResponseCodeException { 6 | public GroupPatchNotAcceptedException() { 7 | super(400); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/GroupStaleDevicesException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | import org.whispersystems.signalservice.internal.push.GroupStaleDevices; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * Represents a 410 response from the service during a sender key send. 11 | */ 12 | public class GroupStaleDevicesException extends NonSuccessfulResponseCodeException { 13 | 14 | private final List staleDevices; 15 | 16 | public GroupStaleDevicesException(GroupStaleDevices[] staleDevices) { 17 | super(410); 18 | this.staleDevices = Arrays.asList(staleDevices); 19 | } 20 | 21 | public List getStaleDevices() { 22 | return staleDevices; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/InAppPaymentReceiptCredentialError.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.push.exceptions 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator 9 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException 10 | import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription.ChargeFailure 11 | 12 | /** 13 | * HTTP 402 Exception when trying to submit credentials for a donation with 14 | * a failed payment. 15 | */ 16 | class InAppPaymentReceiptCredentialError @JsonCreator constructor( 17 | val chargeFailure: ChargeFailure 18 | ) : NonSuccessfulResponseCodeException(402) { 19 | override fun toString(): String { 20 | return """ 21 | DonationReceiptCredentialError (402) 22 | Charge Failure: $chargeFailure 23 | """.trimIndent() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/InvalidUnidentifiedAccessHeaderException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | /** 6 | * Indicates that the unidentified authorization header provided to the multi_recipient endpoint 7 | * was incorrect (i.e. one or more of your unauthorized access keys is invalid); 8 | */ 9 | public class InvalidUnidentifiedAccessHeaderException extends NonSuccessfulResponseCodeException { 10 | 11 | public InvalidUnidentifiedAccessHeaderException() { 12 | super(401); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/MismatchedDevicesException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.internal.push.exceptions; 8 | 9 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 10 | import org.whispersystems.signalservice.internal.push.MismatchedDevices; 11 | 12 | public class MismatchedDevicesException extends NonSuccessfulResponseCodeException { 13 | 14 | private final MismatchedDevices mismatchedDevices; 15 | 16 | public MismatchedDevicesException(MismatchedDevices mismatchedDevices) { 17 | super(409); 18 | this.mismatchedDevices = mismatchedDevices; 19 | } 20 | 21 | public MismatchedDevices getMismatchedDevices() { 22 | return mismatchedDevices; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/MissingCapabilitiesException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | public final class MissingCapabilitiesException extends NonSuccessfulResponseCodeException { 6 | public MissingCapabilitiesException() { 7 | super(409); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/NotInGroupException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | public final class NotInGroupException extends NonSuccessfulResponseCodeException { 6 | public NotInGroupException() { 7 | super(403); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/PaymentsRegionException.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.exceptions; 2 | 3 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 4 | 5 | import java.util.function.Function; 6 | 7 | import okhttp3.ResponseBody; 8 | 9 | public final class PaymentsRegionException extends NonSuccessfulResponseCodeException { 10 | public PaymentsRegionException(int code) { 11 | super(code); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/exceptions/StaleDevicesException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package org.whispersystems.signalservice.internal.push.exceptions; 8 | 9 | import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; 10 | import org.whispersystems.signalservice.internal.push.StaleDevices; 11 | 12 | public class StaleDevicesException extends NonSuccessfulResponseCodeException { 13 | 14 | private final StaleDevices staleDevices; 15 | 16 | public StaleDevicesException(StaleDevices staleDevices) { 17 | super(410); 18 | this.staleDevices = staleDevices; 19 | } 20 | 21 | public StaleDevices getStaleDevices() { 22 | return staleDevices; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/CancelationSignal.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | /** 4 | * Used to communicate to observers whether or not something is canceled. 5 | */ 6 | public interface CancelationSignal { 7 | boolean isCanceled(); 8 | } 9 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/NoCipherOutputStreamFactory.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | import org.whispersystems.signalservice.api.crypto.DigestingOutputStream; 4 | import org.whispersystems.signalservice.api.crypto.NoCipherOutputStream; 5 | 6 | import java.io.OutputStream; 7 | 8 | /** 9 | * See {@link NoCipherOutputStream}. 10 | */ 11 | public final class NoCipherOutputStreamFactory implements OutputStreamFactory { 12 | 13 | @Override 14 | public DigestingOutputStream createFor(OutputStream wrap) { 15 | return new NoCipherOutputStream(wrap); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/OutputStreamFactory.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | 4 | import org.whispersystems.signalservice.api.crypto.DigestingOutputStream; 5 | 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | 9 | public interface OutputStreamFactory { 10 | 11 | public DigestingOutputStream createFor(OutputStream wrap) throws IOException; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/PartialSendBatchCompleteListener.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | import org.whispersystems.signalservice.api.messages.SendMessageResult; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Used to let a listener know when a batch of sends in a collection of sends has been completed. 9 | */ 10 | public interface PartialSendBatchCompleteListener { 11 | void onPartialSendComplete(List results); 12 | } 13 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/PartialSendCompleteListener.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | import org.whispersystems.signalservice.api.messages.SendMessageResult; 4 | 5 | /** 6 | * Used to let a listener know when each individual send in a collection of sends has been completed. 7 | */ 8 | public interface PartialSendCompleteListener { 9 | void onPartialSendComplete(SendMessageResult result); 10 | } 11 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/ProfileCipherOutputStreamFactory.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | 4 | import org.signal.libsignal.zkgroup.profiles.ProfileKey; 5 | import org.whispersystems.signalservice.api.crypto.DigestingOutputStream; 6 | import org.whispersystems.signalservice.api.crypto.ProfileCipherOutputStream; 7 | 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | 11 | public class ProfileCipherOutputStreamFactory implements OutputStreamFactory { 12 | 13 | private final ProfileKey key; 14 | 15 | public ProfileCipherOutputStreamFactory(ProfileKey key) { 16 | this.key = key; 17 | } 18 | 19 | @Override 20 | public DigestingOutputStream createFor(OutputStream wrap) throws IOException { 21 | return new ProfileCipherOutputStream(wrap, key); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/push/http/StickerCipherOutputStreamFactory.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push.http; 2 | 3 | 4 | import org.whispersystems.signalservice.api.crypto.AttachmentCipherOutputStream; 5 | import org.whispersystems.signalservice.api.crypto.DigestingOutputStream; 6 | 7 | import java.io.IOException; 8 | import java.io.OutputStream; 9 | 10 | public class StickerCipherOutputStreamFactory implements OutputStreamFactory { 11 | 12 | private final byte[] key; 13 | 14 | public StickerCipherOutputStreamFactory(byte[] key) { 15 | this.key = key; 16 | } 17 | 18 | @Override 19 | public DigestingOutputStream createFor(OutputStream wrap) throws IOException { 20 | return new AttachmentCipherOutputStream(key, null, wrap); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/websocket/ErrorMapper.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.websocket; 2 | 3 | 4 | import org.whispersystems.signalservice.api.push.exceptions.MalformedResponseException; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Can map an API response to an appropriate {@link Throwable}. 10 | *

11 | * Unless you need to do something really special, you should only be implementing this to customize 12 | * {@link DefaultErrorMapper}. 13 | */ 14 | public interface ErrorMapper { 15 | Throwable parseError(int status, String body, Function getHeader) throws MalformedResponseException; 16 | 17 | default Throwable parseError(int status) throws MalformedResponseException { 18 | return parseError(status, "", s -> ""); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/signalservice/internal/websocket/LibSignalResponseExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.internal.websocket 7 | 8 | import org.signal.libsignal.net.ChatConnection.Response 9 | 10 | fun Response.toWebsocketResponse(isUnidentified: Boolean): WebsocketResponse { 11 | return WebsocketResponse( 12 | this.status, 13 | this.body.decodeToString(), 14 | this.headers, 15 | isUnidentified 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/util/ByteArrayUtil.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.util; 2 | 3 | public final class ByteArrayUtil { 4 | 5 | private ByteArrayUtil() { 6 | } 7 | 8 | public static byte[] xor(byte[] a, byte[] b) { 9 | if (a.length != b.length) { 10 | throw new AssertionError("XOR length mismatch"); 11 | } 12 | 13 | byte[] out = new byte[a.length]; 14 | 15 | for (int i = a.length - 1; i >= 0; i--) { 16 | out[i] = (byte) (a[i] ^ b[i]); 17 | } 18 | 19 | return out; 20 | } 21 | 22 | public static byte[] concat(byte[] a, byte[] b) { 23 | byte[] result = new byte[a.length + b.length]; 24 | System.arraycopy(a, 0, result, 0, a.length); 25 | System.arraycopy(b, 0, result, a.length, b.length); 26 | return result; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/src/main/java/org/whispersystems/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.util; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | public final class StringUtil { 6 | 7 | private StringUtil() { 8 | } 9 | 10 | public static byte[] utf8(String string) { 11 | return string.getBytes(StandardCharsets.UTF_8); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /service/src/main/protowire/DeviceName.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | syntax = "proto2"; 8 | 9 | package signalservice; 10 | 11 | option java_package = "org.whispersystems.signalservice.internal.devices"; 12 | option java_outer_classname = "DeviceNameProtos"; 13 | 14 | message DeviceName { 15 | optional bytes ephemeralPublic = 1; 16 | optional bytes syntheticIv = 2; 17 | optional bytes ciphertext = 3; 18 | } 19 | -------------------------------------------------------------------------------- /service/src/main/protowire/MessageProcessing.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2016 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | syntax = "proto2"; 8 | 9 | package signalservice; 10 | 11 | option java_package = "org.whispersystems.signalservice.api.crypto.protos"; 12 | 13 | message EnvelopeMetadata { 14 | required bytes sourceServiceId = 1; 15 | optional string sourceE164 = 2; 16 | required int32 sourceDeviceId = 3; 17 | required bool sealedSender = 4; 18 | optional bytes groupId = 5; 19 | required bytes destinationServiceId = 6; 20 | } 21 | 22 | message CompleteMessage { 23 | required bytes envelope = 1; 24 | required bytes content = 2; 25 | required EnvelopeMetadata metadata = 3; 26 | required int64 serverDeliveredTimestamp = 4; 27 | } 28 | -------------------------------------------------------------------------------- /service/src/main/protowire/RegistrationProvisioning.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "org.signal.registration.proto"; 5 | 6 | message RegistrationProvisionEnvelope { 7 | bytes publicKey = 1; 8 | bytes body = 2; // Encrypted RegistrationProvisionMessage 9 | } 10 | 11 | message RegistrationProvisionMessage { 12 | enum Platform { 13 | ANDROID = 0; 14 | IOS = 1; 15 | } 16 | 17 | enum Tier { 18 | FREE = 0; 19 | PAID = 1; 20 | } 21 | 22 | string e164 = 1; 23 | bytes aci = 2; 24 | string accountEntropyPool = 3; 25 | optional string pin = 4; 26 | Platform platform = 5; 27 | optional uint64 backupTimestampMs = 6; 28 | optional Tier tier = 7; 29 | optional uint64 backupSizeBytes = 8; 30 | string restoreMethodToken = 9; 31 | bytes aciIdentityKeyPublic = 10; 32 | bytes aciIdentityKeyPrivate = 11; 33 | bytes pniIdentityKeyPublic = 12; 34 | bytes pniIdentityKeyPrivate = 13; 35 | } 36 | -------------------------------------------------------------------------------- /service/src/main/protowire/ResumableUploads.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | syntax = "proto3"; 7 | 8 | option java_package = "org.signal.protos.resumableuploads"; 9 | 10 | message ResumableUpload { 11 | message Header { 12 | string key = 1; 13 | string value = 2; 14 | } 15 | 16 | bytes secretKey = 1; 17 | bytes iv = 2; 18 | string cdnKey = 3; 19 | uint32 cdnNumber = 4; 20 | string location = 5; 21 | uint64 timeout = 6; 22 | repeated Header headers = 7; 23 | } -------------------------------------------------------------------------------- /service/src/main/protowire/StickerResources.proto: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Open Whisper Systems 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | syntax = "proto2"; 7 | 8 | package signalservice; 9 | 10 | option java_package = "org.whispersystems.signalservice.internal.sticker"; 11 | option java_outer_classname = "StickerProtos"; 12 | 13 | message Pack { 14 | message Sticker { 15 | optional uint32 id = 1; 16 | optional string emoji = 2; 17 | optional string contentType = 3; 18 | } 19 | 20 | optional string title = 1; 21 | optional string author = 2; 22 | optional Sticker cover = 3; 23 | repeated Sticker stickers = 4; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /service/src/test/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherTestHelper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.crypto 7 | 8 | import org.whispersystems.signalservice.api.backup.MediaId 9 | import org.whispersystems.signalservice.api.backup.MediaRootBackupKey.MediaKeyMaterial 10 | import org.whispersystems.signalservice.internal.util.Util 11 | 12 | object AttachmentCipherTestHelper { 13 | 14 | /** 15 | * Needed to workaround this bug: 16 | * https://youtrack.jetbrains.com/issue/KT-60205/Java-class-has-private-access-in-class-constructor-with-inlinevalue-parameter 17 | */ 18 | @JvmStatic 19 | fun createMediaKeyMaterial(combinedKey: ByteArray): MediaKeyMaterial { 20 | val parts = Util.split(combinedKey, 32, 32) 21 | 22 | return MediaKeyMaterial( 23 | id = MediaId(Util.getSecretBytes(15)), 24 | macKey = parts[1], 25 | aesKey = parts[0] 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/src/test/java/org/whispersystems/signalservice/api/groupsv2/ProtobufTestUtils.java: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.api.groupsv2; 2 | 3 | import com.squareup.wire.Message; 4 | import com.squareup.wire.WireField; 5 | 6 | import java.util.stream.Stream; 7 | 8 | final class ProtobufTestUtils { 9 | 10 | /** 11 | * Finds the largest declared field number in the supplied protobuf class. 12 | */ 13 | static int getMaxDeclaredFieldNumber(Class> protobufClass) { 14 | return Stream.of(protobufClass.getFields()) 15 | .map(f -> f.getAnnotationsByType(WireField.class)) 16 | .filter(a -> a.length == 1) 17 | .map(a -> a[0].tag()) 18 | .max(Integer::compareTo) 19 | .orElse(0); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/src/test/java/org/whispersystems/signalservice/api/push/PushTransportDetailsTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Signal Messenger, LLC 3 | * SPDX-License-Identifier: AGPL-3.0-only 4 | */ 5 | 6 | package org.whispersystems.signalservice.api.push 7 | 8 | import assertk.assertThat 9 | import assertk.assertions.hasSize 10 | import org.junit.Test 11 | import org.whispersystems.signalservice.internal.push.PushTransportDetails 12 | 13 | class PushTransportDetailsTest { 14 | private val transportV3 = PushTransportDetails() 15 | 16 | @Test 17 | fun testV3Padding() { 18 | (0 until 159).forEach { i -> 19 | val message = ByteArray(i) 20 | assertThat(transportV3.getPaddedMessageBody(message)).hasSize(159) 21 | } 22 | 23 | (159 until 319).forEach { i -> 24 | val message = ByteArray(i) 25 | assertThat(transportV3.getPaddedMessageBody(message)).hasSize(319) 26 | } 27 | 28 | (319 until 479).forEach { i -> 29 | val message = ByteArray(i) 30 | assertThat(transportV3.getPaddedMessageBody(message)).hasSize(479) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /service/src/test/java/org/whispersystems/signalservice/internal/push/ContentRange_parse_withInvalidStrings_Test.kt: -------------------------------------------------------------------------------- 1 | package org.whispersystems.signalservice.internal.push 2 | 3 | import assertk.assertThat 4 | import assertk.assertions.isFalse 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.junit.runners.Parameterized 8 | 9 | @RunWith(Parameterized::class) 10 | class ContentRange_parse_withInvalidStrings_Test(private val input: String?) { 11 | @Test 12 | fun parse_should_be_absent() { 13 | assertThat(ContentRange.parse(input).isPresent).isFalse() 14 | } 15 | 16 | companion object { 17 | @JvmStatic 18 | @Parameterized.Parameters(name = "Content-Range: \"{0}\"") 19 | fun data(): List> { 20 | return listOf( 21 | arrayOf(null), 22 | arrayOf(""), 23 | arrayOf("23-45/67"), 24 | arrayOf("ersions 23-45/67"), 25 | arrayOf("versions 23-45"), 26 | arrayOf("versions a-b/c") 27 | ) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/src/test/resources/ias.cert: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turasa/libsignal-service-java/c95ad5823be36f55d605e895e604a2bfb70ecb7c/service/src/test/resources/ias.cert -------------------------------------------------------------------------------- /service/src/test/resources/ias.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turasa/libsignal-service-java/c95ad5823be36f55d605e895e604a2bfb70ecb7c/service/src/test/resources/ias.jks -------------------------------------------------------------------------------- /service/src/test/resources/ias.store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turasa/libsignal-service-java/c95ad5823be36f55d605e895e604a2bfb70ecb7c/service/src/test/resources/ias.store -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencyResolutionManagement { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | versionCatalogs { 7 | // libs.versions.toml is automatically registered. 8 | create("testLibs") { 9 | from(files("gradle/test-libs.versions.toml")) 10 | } 11 | } 12 | } 13 | 14 | include("signal-service-java") 15 | project(":signal-service-java").projectDir = file("service") 16 | 17 | include(":core-util-jvm") 18 | -------------------------------------------------------------------------------- /wire-handler/wire-handler-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turasa/libsignal-service-java/c95ad5823be36f55d605e895e604a2bfb70ecb7c/wire-handler/wire-handler-1.0.0.jar --------------------------------------------------------------------------------