├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── cobalt.iml ├── frida ├── README.md ├── mobile │ ├── android │ │ ├── integrity │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ └── server.js │ │ └── nodes │ │ │ └── index.js │ └── ios │ │ ├── integrity │ │ ├── README.md │ │ ├── package.json │ │ └── server.js │ │ └── nodes │ │ └── index.js └── web │ └── nodes │ └── index.js ├── mvnw ├── mvnw.cmd ├── pom.xml ├── proto ├── extractor │ ├── .gitignore │ ├── README.md │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── yarn.lock ├── signal.proto └── whatsapp.proto └── src ├── main ├── java │ ├── it │ │ └── auties │ │ │ └── whatsapp │ │ │ ├── api │ │ │ ├── AsyncVerificationCodeSupplier.java │ │ │ ├── ClientType.java │ │ │ ├── ConnectionBuilder.java │ │ │ ├── ConnectionType.java │ │ │ ├── DisconnectReason.java │ │ │ ├── Emoji.java │ │ │ ├── ErrorHandler.java │ │ │ ├── Listener.java │ │ │ ├── MediaProxySetting.java │ │ │ ├── MobileOptionsBuilder.java │ │ │ ├── MobileRegistrationBuilder.java │ │ │ ├── OptionsBuilder.java │ │ │ ├── PairingCodeHandler.java │ │ │ ├── QrHandler.java │ │ │ ├── SocketEvent.java │ │ │ ├── TextPreviewSetting.java │ │ │ ├── WebHistorySetting.java │ │ │ ├── WebOptionsBuilder.java │ │ │ ├── WebVerificationHandler.java │ │ │ ├── Whatsapp.java │ │ │ └── WhatsappCustomBuilder.java │ │ │ ├── controller │ │ │ ├── Controller.java │ │ │ ├── ControllerSerializer.java │ │ │ ├── DiscardingControllerSerializer.java │ │ │ ├── FileControllerSerializer.java │ │ │ ├── JsonControllerSerializer.java │ │ │ ├── Keys.java │ │ │ ├── ProtobufControllerSerializer.java │ │ │ ├── Store.java │ │ │ └── StoreKeysPair.java │ │ │ ├── crypto │ │ │ ├── AesCbc.java │ │ │ ├── AesGcm.java │ │ │ ├── CipheredMessageResult.java │ │ │ ├── GroupBuilder.java │ │ │ ├── GroupCipher.java │ │ │ ├── Hkdf.java │ │ │ ├── Hmac.java │ │ │ ├── LTHash.java │ │ │ ├── MD5.java │ │ │ ├── Pbkdf2.java │ │ │ ├── SessionBuilder.java │ │ │ ├── SessionCipher.java │ │ │ ├── Sha1.java │ │ │ └── Sha256.java │ │ │ ├── exception │ │ │ ├── HmacValidationException.java │ │ │ ├── RegistrationException.java │ │ │ └── RequestException.java │ │ │ ├── io │ │ │ ├── BinaryDecoder.java │ │ │ ├── BinaryEncoder.java │ │ │ ├── BinaryTag.java │ │ │ └── BinaryTokens.java │ │ │ ├── model │ │ │ ├── action │ │ │ │ ├── Action.java │ │ │ │ ├── AgentAction.java │ │ │ │ ├── AndroidUnsupportedActions.java │ │ │ │ ├── ArchiveChatAction.java │ │ │ │ ├── ChatAssignmentAction.java │ │ │ │ ├── ChatAssignmentOpenedStatusAction.java │ │ │ │ ├── ClearChatAction.java │ │ │ │ ├── ContactAction.java │ │ │ │ ├── DeleteChatAction.java │ │ │ │ ├── DeleteMessageForMeAction.java │ │ │ │ ├── LabelAssociationAction.java │ │ │ │ ├── LabelEditAction.java │ │ │ │ ├── MarkChatAsReadAction.java │ │ │ │ ├── MuteAction.java │ │ │ │ ├── NuxAction.java │ │ │ │ ├── PinAction.java │ │ │ │ ├── PrimaryVersionAction.java │ │ │ │ ├── QuickReplyAction.java │ │ │ │ ├── RecentEmojiWeightsAction.java │ │ │ │ ├── RemoveRecentStickerAction.java │ │ │ │ ├── StarAction.java │ │ │ │ ├── StickerAction.java │ │ │ │ ├── SubscriptionAction.java │ │ │ │ ├── TimeFormatAction.java │ │ │ │ └── UserStatusMuteAction.java │ │ │ ├── business │ │ │ │ ├── BusinessAccountPayload.java │ │ │ │ ├── BusinessCatalogEntry.java │ │ │ │ ├── BusinessCategory.java │ │ │ │ ├── BusinessCollectionEntry.java │ │ │ │ ├── BusinessHours.java │ │ │ │ ├── BusinessHoursEntry.java │ │ │ │ ├── BusinessItemAvailability.java │ │ │ │ ├── BusinessLocalizedName.java │ │ │ │ ├── BusinessPrivacyStatus.java │ │ │ │ ├── BusinessProfile.java │ │ │ │ ├── BusinessReviewStatus.java │ │ │ │ ├── BusinessVerifiedNameCertificate.java │ │ │ │ └── BusinessVerifiedNameDetails.java │ │ │ ├── button │ │ │ │ ├── base │ │ │ │ │ ├── Button.java │ │ │ │ │ ├── ButtonActionLink.java │ │ │ │ │ ├── ButtonBody.java │ │ │ │ │ ├── ButtonOpaqueData.java │ │ │ │ │ ├── ButtonRow.java │ │ │ │ │ ├── ButtonRowOpaqueData.java │ │ │ │ │ ├── ButtonSection.java │ │ │ │ │ ├── ButtonText.java │ │ │ │ │ ├── SingleSelectReplyButton.java │ │ │ │ │ └── TemplateFormatter.java │ │ │ │ ├── interactive │ │ │ │ │ ├── InteractiveBody.java │ │ │ │ │ ├── InteractiveButton.java │ │ │ │ │ ├── InteractiveCollection.java │ │ │ │ │ ├── InteractiveFooter.java │ │ │ │ │ ├── InteractiveHeader.java │ │ │ │ │ ├── InteractiveHeaderAttachment.java │ │ │ │ │ ├── InteractiveHeaderThumbnail.java │ │ │ │ │ ├── InteractiveLocation.java │ │ │ │ │ ├── InteractiveLocationAnnotation.java │ │ │ │ │ ├── InteractiveNativeFlow.java │ │ │ │ │ ├── InteractivePoint.java │ │ │ │ │ ├── InteractiveResponseBody.java │ │ │ │ │ └── InteractiveShop.java │ │ │ │ └── template │ │ │ │ │ ├── highlyStructured │ │ │ │ │ ├── HighlyStructuredButton.java │ │ │ │ │ ├── HighlyStructuredButtonTemplate.java │ │ │ │ │ ├── HighlyStructuredCallButton.java │ │ │ │ │ ├── HighlyStructuredCurrency.java │ │ │ │ │ ├── HighlyStructuredDateTime.java │ │ │ │ │ ├── HighlyStructuredDateTimeComponent.java │ │ │ │ │ ├── HighlyStructuredDateTimeUnixEpoch.java │ │ │ │ │ ├── HighlyStructuredDateTimeValue.java │ │ │ │ │ ├── HighlyStructuredFourRowTemplate.java │ │ │ │ │ ├── HighlyStructuredFourRowTemplateTitle.java │ │ │ │ │ ├── HighlyStructuredLocalizableParameter.java │ │ │ │ │ ├── HighlyStructuredLocalizableParameterValue.java │ │ │ │ │ ├── HighlyStructuredMessage.java │ │ │ │ │ ├── HighlyStructuredQuickReplyButton.java │ │ │ │ │ └── HighlyStructuredURLButton.java │ │ │ │ │ └── hydrated │ │ │ │ │ ├── HydratedButton.java │ │ │ │ │ ├── HydratedCallButton.java │ │ │ │ │ ├── HydratedFourRowTemplate.java │ │ │ │ │ ├── HydratedFourRowTemplateTextTitle.java │ │ │ │ │ ├── HydratedFourRowTemplateTitle.java │ │ │ │ │ ├── HydratedQuickReplyButton.java │ │ │ │ │ ├── HydratedTemplateButton.java │ │ │ │ │ └── HydratedURLButton.java │ │ │ ├── call │ │ │ │ ├── Call.java │ │ │ │ └── CallStatus.java │ │ │ ├── chat │ │ │ │ ├── Chat.java │ │ │ │ ├── ChatDisappear.java │ │ │ │ ├── ChatEphemeralTimer.java │ │ │ │ ├── ChatMetadata.java │ │ │ │ ├── ChatMute.java │ │ │ │ ├── ChatParticipant.java │ │ │ │ ├── ChatPastParticipant.java │ │ │ │ ├── ChatSetting.java │ │ │ │ ├── ChatSettingPolicy.java │ │ │ │ ├── ChatWallpaper.java │ │ │ │ ├── CommunityLinkedGroup.java │ │ │ │ ├── CommunityParticipant.java │ │ │ │ ├── CommunitySetting.java │ │ │ │ ├── GroupAction.java │ │ │ │ ├── GroupParticipant.java │ │ │ │ ├── GroupPastParticipants.java │ │ │ │ ├── GroupRole.java │ │ │ │ └── GroupSetting.java │ │ │ ├── companion │ │ │ │ ├── CompanionDevice.java │ │ │ │ ├── CompanionHashState.java │ │ │ │ ├── CompanionLinkResult.java │ │ │ │ ├── CompanionProperty.java │ │ │ │ └── CompanionSyncKey.java │ │ │ ├── contact │ │ │ │ ├── Contact.java │ │ │ │ ├── ContactCard.java │ │ │ │ └── ContactStatus.java │ │ │ ├── info │ │ │ │ ├── AdReplyInfo.java │ │ │ │ ├── BusinessAccountLinkInfo.java │ │ │ │ ├── BusinessIdentityInfo.java │ │ │ │ ├── ChatMessageInfo.java │ │ │ │ ├── ContextInfo.java │ │ │ │ ├── DeviceContextInfo.java │ │ │ │ ├── ExternalAdReplyInfo.java │ │ │ │ ├── Info.java │ │ │ │ ├── MessageIndexInfo.java │ │ │ │ ├── MessageInfo.java │ │ │ │ ├── MessageStatusInfo.java │ │ │ │ ├── NativeFlowInfo.java │ │ │ │ ├── NewsletterMessageInfo.java │ │ │ │ ├── NotificationMessageInfo.java │ │ │ │ ├── PaymentInfo.java │ │ │ │ ├── ProductListInfo.java │ │ │ │ ├── QuotedMessageInfo.java │ │ │ │ └── WebNotificationsInfo.java │ │ │ ├── jid │ │ │ │ ├── Jid.java │ │ │ │ ├── JidProvider.java │ │ │ │ ├── JidServer.java │ │ │ │ └── JidType.java │ │ │ ├── media │ │ │ │ ├── AttachmentType.java │ │ │ │ ├── MediaConnection.java │ │ │ │ ├── MediaData.java │ │ │ │ ├── MediaDimensions.java │ │ │ │ ├── MediaFile.java │ │ │ │ ├── MediaKeys.java │ │ │ │ ├── MediaUpload.java │ │ │ │ ├── MediaVisibility.java │ │ │ │ └── MutableAttachmentProvider.java │ │ │ ├── message │ │ │ │ ├── button │ │ │ │ │ ├── ButtonsMessage.java │ │ │ │ │ ├── ButtonsMessageHeader.java │ │ │ │ │ ├── ButtonsMessageHeaderText.java │ │ │ │ │ ├── ButtonsResponseMessage.java │ │ │ │ │ ├── InteractiveMessage.java │ │ │ │ │ ├── InteractiveMessageContent.java │ │ │ │ │ ├── InteractiveResponseMessage.java │ │ │ │ │ ├── ListMessage.java │ │ │ │ │ ├── ListResponseMessage.java │ │ │ │ │ ├── NativeFlowResponseMessage.java │ │ │ │ │ ├── TemplateMessage.java │ │ │ │ │ └── TemplateReplyMessage.java │ │ │ │ ├── model │ │ │ │ │ ├── ButtonMessage.java │ │ │ │ │ ├── ButtonReplyMessage.java │ │ │ │ │ ├── ChatMessageKey.java │ │ │ │ │ ├── ContextualMessage.java │ │ │ │ │ ├── EncryptedMessage.java │ │ │ │ │ ├── FutureMessageContainer.java │ │ │ │ │ ├── KeepInChat.java │ │ │ │ │ ├── KeepInChatType.java │ │ │ │ │ ├── MediaMessage.java │ │ │ │ │ ├── MediaMessageType.java │ │ │ │ │ ├── Message.java │ │ │ │ │ ├── MessageCategory.java │ │ │ │ │ ├── MessageContainer.java │ │ │ │ │ ├── MessageReceipt.java │ │ │ │ │ ├── MessageStatus.java │ │ │ │ │ ├── MessageType.java │ │ │ │ │ ├── PaymentMessage.java │ │ │ │ │ ├── PublicServiceAnnouncementStatus.java │ │ │ │ │ └── ServerMessage.java │ │ │ │ ├── payment │ │ │ │ │ ├── CancelPaymentRequestMessage.java │ │ │ │ │ ├── DeclinePaymentRequestMessage.java │ │ │ │ │ ├── PaymentInviteMessage.java │ │ │ │ │ ├── PaymentInvoiceMessage.java │ │ │ │ │ ├── PaymentOrderMessage.java │ │ │ │ │ ├── RequestPaymentMessage.java │ │ │ │ │ └── SendPaymentMessage.java │ │ │ │ ├── server │ │ │ │ │ ├── DeviceSentMessage.java │ │ │ │ │ ├── DeviceSyncMessage.java │ │ │ │ │ ├── ProtocolMessage.java │ │ │ │ │ ├── SenderKeyDistributionMessage.java │ │ │ │ │ └── StickerSyncRMRMessage.java │ │ │ │ └── standard │ │ │ │ │ ├── AudioMessage.java │ │ │ │ │ ├── CallMessage.java │ │ │ │ │ ├── ContactMessage.java │ │ │ │ │ ├── ContactsMessage.java │ │ │ │ │ ├── DocumentMessage.java │ │ │ │ │ ├── EmptyMessage.java │ │ │ │ │ ├── EncryptedReactionMessage.java │ │ │ │ │ ├── GroupInviteMessage.java │ │ │ │ │ ├── ImageMessage.java │ │ │ │ │ ├── KeepInChatMessage.java │ │ │ │ │ ├── LiveLocationMessage.java │ │ │ │ │ ├── LocationMessage.java │ │ │ │ │ ├── NewsletterAdminInviteMessage.java │ │ │ │ │ ├── PollCreationMessage.java │ │ │ │ │ ├── PollUpdateMessage.java │ │ │ │ │ ├── ProductMessage.java │ │ │ │ │ ├── ReactionMessage.java │ │ │ │ │ ├── RequestPhoneNumberMessage.java │ │ │ │ │ ├── StickerMessage.java │ │ │ │ │ ├── TextMessage.java │ │ │ │ │ └── VideoOrGifMessage.java │ │ │ ├── mobile │ │ │ │ ├── AccountInfo.java │ │ │ │ ├── CountryCode.java │ │ │ │ ├── CountryLocale.java │ │ │ │ ├── PhoneNumber.java │ │ │ │ ├── SixPartsKeys.java │ │ │ │ ├── VerificationCodeError.java │ │ │ │ ├── VerificationCodeMethod.java │ │ │ │ └── VerificationCodeStatus.java │ │ │ ├── newsletter │ │ │ │ ├── Newsletter.java │ │ │ │ ├── NewsletterDescription.java │ │ │ │ ├── NewsletterMetadata.java │ │ │ │ ├── NewsletterName.java │ │ │ │ ├── NewsletterPicture.java │ │ │ │ ├── NewsletterPreview.java │ │ │ │ ├── NewsletterReaction.java │ │ │ │ ├── NewsletterReactionSettings.java │ │ │ │ ├── NewsletterSettings.java │ │ │ │ ├── NewsletterState.java │ │ │ │ ├── NewsletterViewerMetadata.java │ │ │ │ └── NewsletterViewerRole.java │ │ │ ├── node │ │ │ │ ├── Attributes.java │ │ │ │ └── Node.java │ │ │ ├── payment │ │ │ │ ├── PaymentBackground.java │ │ │ │ ├── PaymentMediaData.java │ │ │ │ └── PaymentMoney.java │ │ │ ├── poll │ │ │ │ ├── PollAdditionalMetadata.java │ │ │ │ ├── PollOption.java │ │ │ │ ├── PollUpdate.java │ │ │ │ ├── PollUpdateEncryptedMetadata.java │ │ │ │ ├── PollUpdateEncryptedOptions.java │ │ │ │ ├── PollUpdateMessageMetadata.java │ │ │ │ └── SelectedPollOption.java │ │ │ ├── privacy │ │ │ │ ├── GdprAccountReport.java │ │ │ │ ├── PrivacySettingEntry.java │ │ │ │ ├── PrivacySettingType.java │ │ │ │ └── PrivacySettingValue.java │ │ │ ├── product │ │ │ │ ├── LeaveNewsletterRequest.java │ │ │ │ ├── Product.java │ │ │ │ ├── ProductCatalog.java │ │ │ │ ├── ProductListHeaderImage.java │ │ │ │ ├── ProductSection.java │ │ │ │ └── ProductSectionEntry.java │ │ │ ├── request │ │ │ │ ├── AcceptAdminInviteNewsletterRequest.java │ │ │ │ ├── CommunityLinkedGroupsRequest.java │ │ │ │ ├── CreateAdminInviteNewsletterRequest.java │ │ │ │ ├── CreateNewsletterRequest.java │ │ │ │ ├── JoinNewsletterRequest.java │ │ │ │ ├── LeaveNewsletterRequest.java │ │ │ │ ├── MessageSendRequest.java │ │ │ │ ├── NewsletterSubscribersRequest.java │ │ │ │ ├── QueryNewsletterRequest.java │ │ │ │ ├── RecommendedNewslettersRequest.java │ │ │ │ ├── RevokeAdminInviteNewsletterRequest.java │ │ │ │ ├── SubscribedNewslettersRequest.java │ │ │ │ ├── UpdateNewsletterRequest.java │ │ │ │ └── UserChosenNameRequest.java │ │ │ ├── response │ │ │ │ ├── AbPropsResponse.java │ │ │ │ ├── AcceptAdminInviteNewsletterResponse.java │ │ │ │ ├── CheckNumberResponse.java │ │ │ │ ├── CommunityLinkedGroupsResponse.java │ │ │ │ ├── ContactAboutResponse.java │ │ │ │ ├── CreateAdminInviteNewsletterResponse.java │ │ │ │ ├── HasWhatsappResponse.java │ │ │ │ ├── NewsletterLeaveResponse.java │ │ │ │ ├── NewsletterMuteResponse.java │ │ │ │ ├── NewsletterResponse.java │ │ │ │ ├── NewsletterStateResponse.java │ │ │ │ ├── NewsletterSubscribersResponse.java │ │ │ │ ├── RecommendedNewslettersResponse.java │ │ │ │ ├── RegistrationResponse.java │ │ │ │ ├── RevokeAdminInviteNewsletterResponse.java │ │ │ │ ├── SubscribedNewslettersResponse.java │ │ │ │ └── UserChosenNameResponse.java │ │ │ ├── setting │ │ │ │ ├── AutoDownloadSettings.java │ │ │ │ ├── AvatarUserSettings.java │ │ │ │ ├── EphemeralSettings.java │ │ │ │ ├── GlobalSettings.java │ │ │ │ ├── LocaleSettings.java │ │ │ │ ├── PushNameSettings.java │ │ │ │ ├── SecurityNotificationSettings.java │ │ │ │ ├── Setting.java │ │ │ │ └── UnarchiveChatsSettings.java │ │ │ ├── signal │ │ │ │ ├── auth │ │ │ │ │ ├── ClientFinish.java │ │ │ │ │ ├── ClientHello.java │ │ │ │ │ ├── ClientPayload.java │ │ │ │ │ ├── CompanionProperties.java │ │ │ │ │ ├── CompanionRegistrationData.java │ │ │ │ │ ├── DNSSource.java │ │ │ │ │ ├── DeviceIdentity.java │ │ │ │ │ ├── HandshakeMessage.java │ │ │ │ │ ├── KeyIndexList.java │ │ │ │ │ ├── NoiseCertificate.java │ │ │ │ │ ├── ServerHello.java │ │ │ │ │ ├── SignedDeviceIdentity.java │ │ │ │ │ ├── SignedDeviceIdentityHMAC.java │ │ │ │ │ ├── SignedKeyIndexList.java │ │ │ │ │ ├── UserAgent.java │ │ │ │ │ ├── Version.java │ │ │ │ │ ├── WebFeatures.java │ │ │ │ │ ├── WebInfo.java │ │ │ │ │ └── WebPayload.java │ │ │ │ ├── keypair │ │ │ │ │ ├── ISignalKeyPair.java │ │ │ │ │ ├── SignalKeyPair.java │ │ │ │ │ ├── SignalPreKeyPair.java │ │ │ │ │ └── SignalSignedKeyPair.java │ │ │ │ ├── message │ │ │ │ │ ├── SenderKeyMessage.java │ │ │ │ │ ├── SignalDistributionMessage.java │ │ │ │ │ ├── SignalMessage.java │ │ │ │ │ ├── SignalPreKeyMessage.java │ │ │ │ │ └── SignalProtocolMessage.java │ │ │ │ ├── sender │ │ │ │ │ ├── SenderChainKey.java │ │ │ │ │ ├── SenderKeyName.java │ │ │ │ │ ├── SenderKeyRecord.java │ │ │ │ │ ├── SenderKeyState.java │ │ │ │ │ ├── SenderMessageKey.java │ │ │ │ │ └── SenderPreKeys.java │ │ │ │ └── session │ │ │ │ │ ├── Session.java │ │ │ │ │ ├── SessionAddress.java │ │ │ │ │ ├── SessionChain.java │ │ │ │ │ ├── SessionPreKey.java │ │ │ │ │ └── SessionState.java │ │ │ └── sync │ │ │ │ ├── ActionDataSync.java │ │ │ │ ├── ActionMessageRangeSync.java │ │ │ │ ├── ActionValueSync.java │ │ │ │ ├── AppStateFatalExceptionNotification.java │ │ │ │ ├── AppStateSyncKey.java │ │ │ │ ├── AppStateSyncKeyData.java │ │ │ │ ├── AppStateSyncKeyFingerprint.java │ │ │ │ ├── AppStateSyncKeyId.java │ │ │ │ ├── AppStateSyncKeyRequest.java │ │ │ │ ├── AppStateSyncKeyShare.java │ │ │ │ ├── DeviceListMetadata.java │ │ │ │ ├── ExitCode.java │ │ │ │ ├── ExternalBlobReference.java │ │ │ │ ├── HistorySync.java │ │ │ │ ├── HistorySyncConfig.java │ │ │ │ ├── HistorySyncMessage.java │ │ │ │ ├── HistorySyncNotification.java │ │ │ │ ├── IndexSync.java │ │ │ │ ├── InitialSecurityNotificationSettingSync.java │ │ │ │ ├── KeyExpiration.java │ │ │ │ ├── KeyId.java │ │ │ │ ├── MediaRetryNotification.java │ │ │ │ ├── MutationKeys.java │ │ │ │ ├── MutationSync.java │ │ │ │ ├── MutationsSync.java │ │ │ │ ├── PatchRequest.java │ │ │ │ ├── PatchSync.java │ │ │ │ ├── PatchType.java │ │ │ │ ├── PhotoChange.java │ │ │ │ ├── PrimaryFeature.java │ │ │ │ ├── PushName.java │ │ │ │ ├── RecentEmojiWeight.java │ │ │ │ ├── RecordSync.java │ │ │ │ ├── ServerErrorReceipt.java │ │ │ │ ├── SnapshotSync.java │ │ │ │ ├── StickerMetadata.java │ │ │ │ ├── SyncActionMessage.java │ │ │ │ ├── Syncable.java │ │ │ │ ├── ValueSync.java │ │ │ │ └── VersionSync.java │ │ │ ├── socket │ │ │ ├── AppStateHandler.java │ │ │ ├── AuthHandler.java │ │ │ ├── MessageHandler.java │ │ │ ├── SocketHandler.java │ │ │ ├── SocketHandshake.java │ │ │ ├── SocketListener.java │ │ │ ├── SocketRequest.java │ │ │ ├── SocketSession.java │ │ │ ├── SocketState.java │ │ │ └── StreamHandler.java │ │ │ └── util │ │ │ ├── AppMetadata.java │ │ │ ├── Bytes.java │ │ │ ├── Clock.java │ │ │ ├── ConcurrentLinkedSet.java │ │ │ ├── Exceptions.java │ │ │ ├── ImmutableLinkedList.java │ │ │ ├── Json.java │ │ │ ├── Medias.java │ │ │ ├── MobileRegistration.java │ │ │ ├── Proxies.java │ │ │ └── SignalConstants.java │ └── module-info.java └── resources │ └── META-INF │ ├── native-image │ ├── jni-config.json │ ├── native-image.properties │ ├── predefined-classes-config.json │ ├── proxy-config.json │ ├── reflect-config.json │ ├── resource-config.json │ └── serialization-config.json │ └── services │ └── javax.annotation.processing.AbstractProcessor └── test ├── java └── it │ └── auties │ └── whatsapp │ ├── TestLibrary.java │ ├── example │ ├── MobileLoginExample.java │ ├── MobileRegistrationExample.java │ ├── WebPairingCodeLoginExample.java │ └── WebQrLoginExample.java │ ├── routine │ ├── GenerateListenersLambdas.java │ └── UpdateTokens.java │ └── util │ ├── ConfigUtils.java │ ├── GithubActions.java │ └── MediaUtils.java └── resources └── BinaryTokens.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | .test/ 3 | .idea/ 4 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Auties00/Cobalt/9e7860830830558a847fcafb4e376f53c927a4f9/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Alessandro Autiero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cobalt.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frida/README.md: -------------------------------------------------------------------------------- 1 | # Research Module 2 | 3 | This directory contains various research scripts I developed 4 | 5 | Integrity scripts run an HTTP server on top of the Whatsapp app to bypass functions that need device integrity 6 | 7 | None of this stuff is maintained, it's just public for people who love reverse engineering and want to see how I developed the library -------------------------------------------------------------------------------- /frida/mobile/android/integrity/README.md: -------------------------------------------------------------------------------- 1 | # Android middleware 2 | 3 | ### Requirements 4 | 5 | 1. Rooted android phone with Play Services 6 | 2. Magisk with Zygisk enabled and [PlayIntegrityFix module](https://github.com/chiteroman/PlayIntegrityFix) installed 7 | 3. [Frida server installed](https://frida.re/docs/android/) 8 | 4. Whatsapp and/or Whatsapp business installed on the phone **from the Play Store** (APKs don't work) 9 | 10 | ### How to run 11 | 12 | 1. Run `npm install` in the android directory 13 | 2. Open Whatsapp/Whatsapp Business and try to register a number (needed to load gpia components, won't work if you don't do it) 14 | 3. Run: 15 | - `frida -U "WhatsApp" -l server_with_dependencies.js` (WhatsApp) 16 | - `frida -U "WhatsApp Business" -l server_with_dependencies.js` (WhatsApp Business) -------------------------------------------------------------------------------- /frida/mobile/android/integrity/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "android", 3 | "version": "1.0.0", 4 | "description": "Example showing how to use frida-net's server functionality", 5 | "private": true, 6 | "main": "demo.js", 7 | "scripts": { 8 | "prepare": "npm run build", 9 | "build": "frida-compile server.js -o server_with_dependencies.js -c", 10 | "watch": "frida-compile server.js -o server_with_dependencies.js -w" 11 | }, 12 | "devDependencies": { 13 | "@types/frida-gum": "^18.5.1", 14 | "@types/node": "^18.19.3", 15 | "frida-compile": "^16.4.1" 16 | } 17 | } -------------------------------------------------------------------------------- /frida/mobile/android/nodes/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Auties00/Cobalt/9e7860830830558a847fcafb4e376f53c927a4f9/frida/mobile/android/nodes/index.js -------------------------------------------------------------------------------- /frida/mobile/ios/integrity/README.md: -------------------------------------------------------------------------------- 1 | # iOS middleware 2 | 3 | ### Requirements 4 | 5 | 1. iPhone with Jailbreak 6 | 2. [Frida server installed](https://frida.re/docs/ios/) 7 | 3. Whatsapp and/or Whatsapp Business installed from the App Store 8 | 9 | ### How to run 10 | 11 | 1. Run `npm install` in the ios directory 12 | 2. Disable sleep on your iPhone 13 | 3. Run: 14 | - `frida -U -l server_with_dependencies.js -f "net.whatsapp.WhatsApp"` (WhatsApp) 15 | - `frida -U -l server_with_dependencies.js -f "net.whatsapp.WhatsAppSMB"` (WhatsApp Business) -------------------------------------------------------------------------------- /frida/mobile/ios/integrity/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ios", 3 | "version": "1.0.0", 4 | "description": "Example showing how to use frida-net's server functionality", 5 | "private": true, 6 | "main": "demo.js", 7 | "scripts": { 8 | "prepare": "npm run build", 9 | "build": "frida-compile server.js -o server_with_dependencies.js -c", 10 | "watch": "frida-compile server.js -o server_with_dependencies.js -w" 11 | }, 12 | "devDependencies": { 13 | "@types/frida-gum": "^18.5.1", 14 | "@types/node": "^18.19.3", 15 | "frida-compile": "^16.4.1" 16 | } 17 | } -------------------------------------------------------------------------------- /frida/mobile/ios/nodes/index.js: -------------------------------------------------------------------------------- 1 | Interceptor.attach(Module.getExportByName("SharedModules", "mbedtls_gcm_update"), { 2 | onEnter(args) { 3 | console.log("[*] Called mbedtls_gcm_update", Memory.readUtf8String(args[2], args[1].toInt32())) 4 | } 5 | }) -------------------------------------------------------------------------------- /frida/web/nodes/index.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Auties00/CobaltAnalyzer -------------------------------------------------------------------------------- /proto/extractor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /proto/extractor/README.md: -------------------------------------------------------------------------------- 1 | # Proto Extract 2 | 3 | Derived initially from `whatseow`'s proto extract, this version generates a predictable diff friendly protobuf. It also does not rely on a hardcoded set of modules to look for but finds all proto modules on its own and extracts the proto from there. 4 | 5 | ## Usage 6 | 1. Install dependencies with `yarn` (or `npm install`) 7 | 2. `yarn start` 8 | 3. The script will update `../WAProto/WAProto.proto` (except if something is broken) 9 | -------------------------------------------------------------------------------- /proto/extractor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whatsapp-web-protobuf-extractor", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "start": "node index.js" 7 | }, 8 | "dependencies": { 9 | "acorn": "^6.4.1", 10 | "acorn-walk": "^6.1.1", 11 | "request": "^2.88.0", 12 | "request-promise-core": "^1.1.2", 13 | "request-promise-native": "^1.0.7" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/AsyncVerificationCodeSupplier.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.function.Supplier; 6 | 7 | /** 8 | * An interface to represent a supplier that returns a code wrapped in a CompletableFuture 9 | */ 10 | public interface AsyncVerificationCodeSupplier extends Supplier> { 11 | /** 12 | * Creates an asynchronous supplier from a synchronous one 13 | * 14 | * @param supplier a non-null supplier 15 | * @return a non-null async supplier 16 | */ 17 | static AsyncVerificationCodeSupplier of(Supplier supplier) { 18 | return () -> CompletableFuture.completedFuture(supplier.get()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/ClientType.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * The constants of this enumerated type describe the various types of API that can be used to make 8 | * {@link Whatsapp} work 9 | */ 10 | @ProtobufEnum 11 | public enum ClientType { 12 | /** 13 | * A standalone client that requires the QR code to be scanned by its companion on log-in Reversed 14 | * from Whatsapp Web Client 15 | */ 16 | WEB(0), 17 | /** 18 | * A standalone client that requires an SMS code sent to the companion's phone number on log-in 19 | * Reversed from KaiOS Mobile App 20 | */ 21 | MOBILE(1); 22 | 23 | final int index; 24 | 25 | ClientType(@ProtobufEnumIndex int index) { 26 | this.index = index; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/ConnectionType.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | /** 4 | * The constants of this enumerated type describe the various types of connections that can be initialized 5 | */ 6 | public enum ConnectionType { 7 | /** 8 | * Creates a new connection using a unique identifier 9 | * If no uuid is provided, a new connection will be created 10 | * If the connection doesn't exist, a new one will be created 11 | */ 12 | NEW, 13 | 14 | /** 15 | * Creates a new connection from the first session that was serialized 16 | * If no connection is available, a new one will be created 17 | */ 18 | FIRST, 19 | 20 | /** 21 | * Creates a new connection from the last session that was serialized 22 | * If no connection is available, a new one will be created 23 | */ 24 | LAST 25 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/DisconnectReason.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | /** 4 | * The constants of this enumerated type describe the various reasons for which a session can be 5 | * terminated 6 | */ 7 | public enum DisconnectReason { 8 | /** 9 | * Default errorReason 10 | */ 11 | DISCONNECTED, 12 | 13 | /** 14 | * Reconnect 15 | */ 16 | RECONNECTING, 17 | 18 | /** 19 | * Logged out 20 | */ 21 | LOGGED_OUT, 22 | 23 | /** 24 | * Session restore 25 | */ 26 | RESTORE, 27 | 28 | /** 29 | * Ban 30 | */ 31 | BANNED 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/MediaProxySetting.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * The constants of this enumerated type describe the various ways the proxy should be used when downloading or uploading a media to Whatsapp's servers 8 | * By default, ALL is used to protect the real IP address 9 | */ 10 | @ProtobufEnum 11 | public enum MediaProxySetting { 12 | NONE(0), 13 | DOWNLOADS(1), 14 | UPLOADS(2), 15 | ALL(3); 16 | 17 | final int index; 18 | 19 | MediaProxySetting(@ProtobufEnumIndex int index) { 20 | this.index = index; 21 | } 22 | 23 | public boolean allowsUploads() { 24 | return this == ALL || this == UPLOADS; 25 | } 26 | 27 | public boolean allowsDownloads() { 28 | return this == ALL || this == DOWNLOADS; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/PairingCodeHandler.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * This interface allows to consume a pairing code sent by WhatsappWeb 7 | */ 8 | @SuppressWarnings("unused") 9 | public non-sealed interface PairingCodeHandler extends Consumer, WebVerificationHandler { 10 | /** 11 | * Prints the pairing code to the terminal 12 | */ 13 | static PairingCodeHandler toTerminal() { 14 | return System.out::println; 15 | } 16 | 17 | /** 18 | * Discards the pairing code 19 | */ 20 | static PairingCodeHandler discarding() { 21 | return ignored -> {}; 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/SocketEvent.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | /** 4 | * The constants of this enumerated type describe the various types of events regarding a socket 5 | */ 6 | public enum SocketEvent { 7 | /** 8 | * Called when the socket is opened 9 | */ 10 | OPEN, 11 | 12 | /** 13 | * Called when the socket is closed 14 | */ 15 | CLOSE, 16 | 17 | /** 18 | * Called when an unexpected error is thrown, can be used as a safety mechanism 19 | */ 20 | ERROR, 21 | 22 | /** 23 | * Called when a ping is sent 24 | */ 25 | PING, 26 | 27 | /** 28 | * Called when the socket is paused because of a network issue 29 | */ 30 | PAUSED 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/TextPreviewSetting.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * The constants of this enumerated type describe the various types of text preview that can be 8 | * used 9 | */ 10 | @ProtobufEnum 11 | public enum TextPreviewSetting { 12 | /** 13 | * Link previews will be generated. If a message contains an url without a schema(for example 14 | * wikipedia.com), the message will be autocorrected to include it and a preview will be 15 | * generated 16 | */ 17 | ENABLED_WITH_INFERENCE(0), 18 | 19 | /** 20 | * Link previews will be generated. No inference will be used. 21 | */ 22 | ENABLED(1), 23 | 24 | /** 25 | * Link previews will not be generated 26 | */ 27 | DISABLED(2); 28 | 29 | final int index; 30 | 31 | TextPreviewSetting(@ProtobufEnumIndex int index) { 32 | this.index = index; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/api/WebVerificationHandler.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.api; 2 | 3 | /** 4 | * A utility sealed interface to represent methods that can be used to verify a WhatsappWeb Client 5 | */ 6 | public sealed interface WebVerificationHandler permits QrHandler, PairingCodeHandler { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/controller/StoreKeysPair.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.controller; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * A pair of Store and Keys with the same uuid 7 | */ 8 | public record StoreKeysPair(Store store, Keys keys) { 9 | public StoreKeysPair { 10 | if (!Objects.equals(store.uuid(), keys.uuid())) { 11 | throw new IllegalArgumentException("UUID mismatch between store and keys"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/crypto/CipheredMessageResult.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.crypto; 2 | 3 | public record CipheredMessageResult(byte[] message, String type) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/crypto/GroupBuilder.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.crypto; 2 | 3 | import it.auties.whatsapp.controller.Keys; 4 | import it.auties.whatsapp.model.signal.keypair.SignalKeyPair; 5 | import it.auties.whatsapp.model.signal.message.SignalDistributionMessage; 6 | import it.auties.whatsapp.model.signal.sender.SenderKeyName; 7 | import it.auties.whatsapp.util.Bytes; 8 | 9 | import java.util.concurrent.ThreadLocalRandom; 10 | 11 | public record GroupBuilder(Keys keys) { 12 | public byte[] createOutgoing(SenderKeyName name) { 13 | var record = keys.findSenderKeyByName(name); 14 | if (record.isEmpty()) { 15 | record.addState(ThreadLocalRandom.current().nextInt(), SignalKeyPair.random(), 0, Bytes.random(32)); 16 | } 17 | var state = record.firstState(); 18 | var message = new SignalDistributionMessage(state.id(), state.chainKey().iteration(), state.chainKey().seed(), state.signingKey().signalPublicKey()); 19 | return message.serialized(); 20 | } 21 | 22 | public void createIncoming(SenderKeyName name, SignalDistributionMessage message) { 23 | var record = keys.findSenderKeyByName(name); 24 | record.addState(message.id(), message.signingKey(), message.iteration(), message.chainKey()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/crypto/Hmac.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.crypto; 2 | 3 | 4 | import javax.crypto.Mac; 5 | import javax.crypto.spec.SecretKeySpec; 6 | import java.security.GeneralSecurityException; 7 | 8 | public final class Hmac { 9 | private static final String HMAC_SHA_256 = "HmacSHA256"; 10 | private static final String HMAC_SHA_512 = "HmacSHA512"; 11 | 12 | public static byte[] calculateSha256(byte[] plain, byte[] key) { 13 | return calculate(HMAC_SHA_256, plain, key); 14 | } 15 | 16 | public static byte[] calculateSha512(byte[] plain, byte[] key) { 17 | return calculate(HMAC_SHA_512, plain, key); 18 | } 19 | 20 | private static byte[] calculate(String algorithm, byte[] plain, byte[] key) { 21 | try { 22 | var localMac = Mac.getInstance(algorithm); 23 | localMac.init(new SecretKeySpec(key, algorithm)); 24 | return localMac.doFinal(plain); 25 | } catch (GeneralSecurityException exception) { 26 | throw new IllegalArgumentException("Cannot calculate hmac", exception); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/crypto/MD5.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.crypto; 2 | 3 | 4 | import java.nio.charset.StandardCharsets; 5 | import java.security.MessageDigest; 6 | import java.security.NoSuchAlgorithmException; 7 | 8 | public final class MD5 { 9 | private static final String MD5 = "MD5"; 10 | 11 | public static byte[] calculate(String data) { 12 | return calculate(data.getBytes(StandardCharsets.UTF_8)); 13 | } 14 | 15 | public static byte[] calculate(byte[] data) { 16 | try { 17 | var digest = MessageDigest.getInstance(MD5); 18 | digest.update(data); 19 | return digest.digest(); 20 | } catch (NoSuchAlgorithmException exception) { 21 | throw new UnsupportedOperationException("Missing md5 implementation", exception); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/crypto/Sha1.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.crypto; 2 | 3 | 4 | import java.nio.charset.StandardCharsets; 5 | import java.security.MessageDigest; 6 | import java.security.NoSuchAlgorithmException; 7 | 8 | public final class Sha1 { 9 | private static final String SHA_1 = "SHA-1"; 10 | 11 | public static byte[] calculate(String data) { 12 | return calculate(data.getBytes(StandardCharsets.UTF_8)); 13 | } 14 | 15 | public static byte[] calculate(byte[] data) { 16 | try { 17 | var digest = MessageDigest.getInstance(SHA_1); 18 | digest.update(data); 19 | return digest.digest(); 20 | } catch (NoSuchAlgorithmException exception) { 21 | throw new UnsupportedOperationException("Missing sha1 implementation"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/crypto/Sha256.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.crypto; 2 | 3 | 4 | import java.nio.charset.StandardCharsets; 5 | import java.security.MessageDigest; 6 | import java.security.NoSuchAlgorithmException; 7 | 8 | public final class Sha256 { 9 | private static final String SHA_256 = "SHA-256"; 10 | 11 | public static byte[] calculate(String data) { 12 | return calculate(data.getBytes(StandardCharsets.UTF_8)); 13 | } 14 | 15 | public static byte[] calculate(byte[] data) { 16 | return calculate(data, 0, data.length); 17 | } 18 | 19 | public static byte[] calculate(byte[] data, int offset, int length) { 20 | try { 21 | var digest = MessageDigest.getInstance(SHA_256); 22 | digest.update(data, offset, length); 23 | return digest.digest(); 24 | } catch (NoSuchAlgorithmException exception) { 25 | throw new UnsupportedOperationException("Missing sha256 implementation"); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/exception/HmacValidationException.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.exception; 2 | 3 | 4 | /** 5 | * An unchecked exception that is thrown when a hmac signature cannot be validated 6 | */ 7 | public class HmacValidationException extends SecurityException { 8 | public HmacValidationException(String location) { 9 | super(location); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/exception/RegistrationException.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.exception; 2 | 3 | import it.auties.whatsapp.model.response.RegistrationResponse; 4 | 5 | import java.util.Optional; 6 | 7 | /** 8 | * This exception is thrown when a phone number cannot be registered by the Whatsapp API 9 | */ 10 | public class RegistrationException extends RuntimeException { 11 | private final RegistrationResponse erroneousResponse; 12 | 13 | public RegistrationException(RegistrationResponse erroneousResponse, String message) { 14 | super(message); 15 | this.erroneousResponse = erroneousResponse; 16 | } 17 | 18 | public Optional erroneousResponse() { 19 | return Optional.ofNullable(erroneousResponse); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/exception/RequestException.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.exception; 2 | 3 | /** 4 | * This exception is thrown when a request cannot be sent to Whatsapp's socket 5 | */ 6 | public class RequestException extends RuntimeException { 7 | public RequestException(String message) { 8 | super(message, null); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/io/BinaryTag.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.io; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum BinaryTag { 6 | UNKNOWN(-1), 7 | LIST_EMPTY(0), 8 | STREAM_END(2), 9 | DICTIONARY_0(236), 10 | DICTIONARY_1(237), 11 | DICTIONARY_2(238), 12 | DICTIONARY_3(239), 13 | COMPANION_JID(247), 14 | LIST_8(248), 15 | LIST_16(249), 16 | JID_PAIR(250), 17 | HEX_8(251), 18 | BINARY_8(252), 19 | BINARY_20(253), 20 | BINARY_32(254), 21 | NIBBLE_8(255), 22 | SINGLE_BYTE_MAX(256), 23 | PACKED_MAX(254); 24 | 25 | private final int data; 26 | 27 | BinaryTag(int data) { 28 | this.data = data; 29 | } 30 | 31 | public static BinaryTag of(int data) { 32 | return Arrays.stream(values()).filter(entry -> entry.data() == data).findAny().orElse(UNKNOWN); 33 | } 34 | 35 | public boolean contentEquals(int number) { 36 | return number == this.data(); 37 | } 38 | 39 | public int data() { 40 | return this.data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/Action.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.whatsapp.model.sync.PatchType; 4 | 5 | /** 6 | * A model interface that represents an action 7 | */ 8 | public sealed interface Action permits AgentAction, AndroidUnsupportedActions, ArchiveChatAction, ChatAssignmentAction, ChatAssignmentOpenedStatusAction, ClearChatAction, ContactAction, DeleteChatAction, DeleteMessageForMeAction, LabelAssociationAction, LabelEditAction, MarkChatAsReadAction, MuteAction, NuxAction, PinAction, PrimaryVersionAction, QuickReplyAction, RecentEmojiWeightsAction, RemoveRecentStickerAction, StarAction, StickerAction, SubscriptionAction, TimeFormatAction, UserStatusMuteAction { 9 | /** 10 | * The name of this action 11 | * 12 | * @return a non-null string 13 | */ 14 | String indexName(); 15 | 16 | /** 17 | * The version of this action 18 | * 19 | * @return a non-null int 20 | */ 21 | int actionVersion(); 22 | 23 | /** 24 | * The type of this action 25 | * 26 | * @return a non-null type 27 | */ 28 | PatchType actionType(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/AndroidUnsupportedActions.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents unsupported actions for android 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.AndroidUnsupportedActions") 12 | public record AndroidUnsupportedActions( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean allowed 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "android_unsupported_actions"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 4; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/ChatAssignmentAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * A model clas that represents the assignment of a chat 12 | */ 13 | @ProtobufMessage(name = "SyncActionValue.ChatAssignmentAction") 14 | public record ChatAssignmentAction( 15 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 16 | Optional deviceAgentId 17 | ) implements Action { 18 | 19 | /** 20 | * The name of this action 21 | * 22 | * @return a non-null string 23 | */ 24 | @Override 25 | public String indexName() { 26 | return "agentChatAssignment"; 27 | } 28 | 29 | /** 30 | * The version of this action 31 | * 32 | * @return a non-null string 33 | */ 34 | @Override 35 | public int actionVersion() { 36 | return 7; 37 | } 38 | 39 | /** 40 | * The type of this action 41 | * 42 | * @return a non-null string 43 | */ 44 | @Override 45 | public PatchType actionType() { 46 | return null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/ChatAssignmentOpenedStatusAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents the assignment of a chat as opened 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.ChatAssignmentOpenedStatusAction") 12 | public record ChatAssignmentOpenedStatusAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean chatOpened 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "agentChatAssignmentOpenedStatus"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 7; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/LabelAssociationAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents a label association 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.LabelAssociationAction") 12 | public record LabelAssociationAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean labeled 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "label_message"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 3; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/NuxAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * Unknown 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.NuxAction") 12 | public record NuxAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean acknowledged 15 | ) implements Action { 16 | 17 | /** 18 | * The name of this action 19 | * 20 | * @return a non-null string 21 | */ 22 | @Override 23 | public String indexName() { 24 | return "nux"; 25 | } 26 | 27 | /** 28 | * The version of this action 29 | * 30 | * @return a non-null string 31 | */ 32 | @Override 33 | public int actionVersion() { 34 | return 7; 35 | } 36 | 37 | /** 38 | * The type of this action 39 | * 40 | * @return a non-null string 41 | */ 42 | @Override 43 | public PatchType actionType() { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/PinAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents a new pin status for a chat 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.PinAction") 12 | public record PinAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean pinned 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "pin_v1"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 5; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/PrimaryVersionAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model class that contains the main Whatsapp version being used 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.PrimaryVersionAction") 12 | public record PrimaryVersionAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 14 | String version 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "primary_version"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 7; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/StarAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents a new star status for a message 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.StarAction") 12 | public record StarAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean starred 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "star"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 2; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/TimeFormatAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents the time format used by the companion 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.TimeFormatAction") 12 | public record TimeFormatAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean twentyFourHourFormatEnabled 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "time_format"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 7; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/action/UserStatusMuteAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.action; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.sync.PatchType; 7 | 8 | /** 9 | * A model clas that represents whether a user was muted 10 | */ 11 | @ProtobufMessage(name = "SyncActionValue.UserStatusMuteAction") 12 | public record UserStatusMuteAction( 13 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 14 | boolean muted 15 | ) implements Action { 16 | /** 17 | * The name of this action 18 | * 19 | * @return a non-null string 20 | */ 21 | @Override 22 | public String indexName() { 23 | return "userStatusMute"; 24 | } 25 | 26 | /** 27 | * The version of this action 28 | * 29 | * @return a non-null string 30 | */ 31 | @Override 32 | public int actionVersion() { 33 | return 7; 34 | } 35 | 36 | /** 37 | * The type of this action 38 | * 39 | * @return a non-null string 40 | */ 41 | @Override 42 | public PatchType actionType() { 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessAccountPayload.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that holds a payload about a business account. 9 | */ 10 | @ProtobufMessage(name = "BizAccountPayload") 11 | public record BusinessAccountPayload( 12 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 13 | BusinessVerifiedNameCertificate certificate, 14 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 15 | byte[] info 16 | ) { 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessCategory.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.node.Node; 7 | 8 | import java.net.URLDecoder; 9 | import java.nio.charset.StandardCharsets; 10 | 11 | /** 12 | * A model class that represents a business category 13 | * 14 | * @param id the non-null id 15 | * @param name the non-null display name 16 | */ 17 | @ProtobufMessage 18 | public record BusinessCategory( 19 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 20 | String id, 21 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 22 | String name 23 | ) { 24 | /** 25 | * Constructs a category from a node 26 | * 27 | * @param node a non-null node 28 | * @return a non-null category 29 | */ 30 | public static BusinessCategory of(Node node) { 31 | var id = node.attributes().getRequiredString("id"); 32 | var name = URLDecoder.decode(node.contentAsString().orElseThrow(), StandardCharsets.UTF_8); 33 | return new BusinessCategory(id, name); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessHours.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | 4 | import java.util.List; 5 | 6 | /** 7 | * A business hours representation that contains the business' time zone and a list of business hour 8 | * entries. 9 | * 10 | * @param timeZone The time zone of the business. 11 | * @param entries A list of business hours entries that contains information about the hours of 12 | * operation for each day of the week. 13 | */ 14 | public record BusinessHours(String timeZone, List entries) { 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessItemAvailability.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import java.util.Arrays; 4 | import java.util.Locale; 5 | 6 | /** 7 | * An enumeration of possible Availabilities. 8 | */ 9 | public enum BusinessItemAvailability { 10 | /** 11 | * Indicates an unknown availability. 12 | */ 13 | UNKNOWN, 14 | /** 15 | * Indicates that the item is in stock. 16 | */ 17 | IN_STOCK, 18 | /** 19 | * Indicates that the item is out of stock. 20 | */ 21 | OUT_OF_STOCK; 22 | 23 | /** 24 | * Returns an Availability based on the given name. 25 | * 26 | * @param name the name of the Availability 27 | * @return an Availability 28 | */ 29 | public static BusinessItemAvailability of(String name) { 30 | return Arrays.stream(values()) 31 | .filter(entry -> entry.name().toLowerCase(Locale.ROOT).replaceAll("_", " ").equals(name)) 32 | .findFirst() 33 | .orElse(UNKNOWN); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessLocalizedName.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a time a localizable name 9 | */ 10 | @ProtobufMessage(name = "LocalizedName") 11 | public record BusinessLocalizedName( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String lg, 14 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 15 | String lc, 16 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 17 | String name 18 | ) { 19 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessPrivacyStatus.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * The constants of this enumerated type describe the various types of business privacy 8 | */ 9 | @ProtobufEnum(name = "WebMessageInfo.BizPrivacyStatus") 10 | public enum BusinessPrivacyStatus { 11 | /** 12 | * End-to-end encryption 13 | */ 14 | E2EE(0), 15 | /** 16 | * Bsp encryption 17 | */ 18 | BSP(1), 19 | /** 20 | * Facebook encryption 21 | */ 22 | FACEBOOK(2), 23 | /** 24 | * Facebook and bsp encryption 25 | */ 26 | BSP_AND_FB(3); 27 | 28 | final int index; 29 | 30 | BusinessPrivacyStatus(@ProtobufEnumIndex int index) { 31 | this.index = index; 32 | } 33 | 34 | public int index() { 35 | return index; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessReviewStatus.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import java.util.Locale; 4 | 5 | /** 6 | * An enumeration of possible ReviewStatuses. 7 | */ 8 | public enum BusinessReviewStatus { 9 | /** 10 | * Indicates that no review has been performed. 11 | */ 12 | NO_REVIEW, 13 | /** 14 | * Indicates that the review is pending. 15 | */ 16 | PENDING, 17 | /** 18 | * Indicates that the review was rejected. 19 | */ 20 | REJECTED, 21 | /** 22 | * Indicates that the review was approved. 23 | */ 24 | APPROVED, 25 | /** 26 | * Indicates that the review is outdated. 27 | */ 28 | OUTDATED; 29 | 30 | /** 31 | * Returns a ReviewStatus based on the given name. 32 | * 33 | * @param name the name of the ReviewStatus 34 | * @return a ReviewStatus 35 | */ 36 | public static BusinessReviewStatus of(String name) { 37 | return valueOf(name.toUpperCase(Locale.ROOT)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/business/BusinessVerifiedNameCertificate.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.business; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a business certificate 9 | */ 10 | @ProtobufMessage(name = "VerifiedNameCertificate") 11 | public record BusinessVerifiedNameCertificate( 12 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 13 | byte[] encodedDetails, 14 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 15 | byte[] signature, 16 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) 17 | byte[] serverSignature 18 | ) { 19 | public BusinessVerifiedNameDetails details() { 20 | return BusinessVerifiedNameDetailsSpec.decode(encodedDetails); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/ButtonActionLink.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * An action link for a button 9 | */ 10 | @ProtobufMessage(name = "ActionLink") 11 | public record ButtonActionLink( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String url, 14 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 15 | String buttonTitle 16 | ) { 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/ButtonBody.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | import it.auties.whatsapp.model.info.NativeFlowInfo; 6 | 7 | /** 8 | * A model that represents the body of a button 9 | */ 10 | public sealed interface ButtonBody permits ButtonText, NativeFlowInfo { 11 | /** 12 | * Returns the type of this body 13 | * 14 | * @return a non-null type 15 | */ 16 | Type bodyType(); 17 | 18 | @ProtobufEnum(name = "Message.ButtonsMessage.Button.Type") 19 | enum Type { 20 | UNKNOWN(0), 21 | TEXT(1), 22 | NATIVE_FLOW(2); 23 | 24 | final int index; 25 | 26 | Type(@ProtobufEnumIndex int index) { 27 | this.index = index; 28 | } 29 | 30 | public int index() { 31 | return index; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/ButtonRow.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.util.Bytes; 7 | 8 | import java.util.HexFormat; 9 | 10 | /** 11 | * A model class that represents a row of buttons 12 | */ 13 | @ProtobufMessage(name = "Message.ListMessage.Row") 14 | public record ButtonRow( 15 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 16 | String title, 17 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 18 | String description, 19 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 20 | String id 21 | ) { 22 | public static ButtonRow of(String title, String description) { 23 | return new ButtonRow(title, description, HexFormat.of().formatHex(Bytes.random(5))); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/ButtonRowOpaqueData.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * A model class that represents data about a row 11 | */ 12 | @ProtobufMessage(name = "MsgRowOpaqueData") 13 | public record ButtonRowOpaqueData( 14 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 15 | Optional currentMessage, 16 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 17 | Optional quotedMessage 18 | ) { 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/ButtonSection.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * A model class that represents a section of buttons 11 | */ 12 | @ProtobufMessage(name = "Message.ListMessage.Section") 13 | public record ButtonSection( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String title, 16 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 17 | List rows 18 | ) { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/ButtonText.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents the text of a button 9 | */ 10 | @ProtobufMessage 11 | public record ButtonText( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String content 14 | ) implements ButtonBody { 15 | @Override 16 | public Type bodyType() { 17 | return Type.TEXT; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/base/SingleSelectReplyButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.base; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents the selection of a row 9 | */ 10 | @ProtobufMessage(name = "Message.ListResponseMessage.SingleSelectReply") 11 | public record SingleSelectReplyButton( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String rowId 14 | ) { 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveBody.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * A model class that represents the body of a product 11 | */ 12 | @ProtobufMessage(name = "Message.InteractiveMessage.Body") 13 | public record InteractiveBody( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String content 16 | ) { 17 | public static Optional ofNullable(String content) { 18 | return Optional.ofNullable(content) 19 | .map(InteractiveBody::new); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * A model class that represents a native flow button 11 | */ 12 | @ProtobufMessage(name = "Message.InteractiveMessage.NativeFlowMessage.NativeFlowButton") 13 | public record InteractiveButton( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String name, 16 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 17 | Optional parameters 18 | ) { 19 | public InteractiveButton(String name, String parameters) { 20 | this(name, Optional.ofNullable(parameters)); 21 | } 22 | 23 | public InteractiveButton(String name) { 24 | this(name, Optional.empty()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveCollection.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | import it.auties.whatsapp.model.message.button.InteractiveMessageContent; 8 | 9 | /** 10 | * A model class that represents a business collection 11 | */ 12 | @ProtobufMessage(name = "Message.InteractiveMessage.CollectionMessage") 13 | public record InteractiveCollection( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | Jid business, 16 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 17 | String id, 18 | @ProtobufProperty(index = 3, type = ProtobufType.INT32) 19 | int version 20 | ) implements InteractiveMessageContent { 21 | 22 | 23 | @Override 24 | public Type contentType() { 25 | return Type.COLLECTION; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveFooter.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * A model class that represents the footer of a product 11 | */ 12 | @ProtobufMessage(name = "Message.InteractiveMessage.Footer") 13 | public record InteractiveFooter( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String content 16 | ) { 17 | 18 | public static Optional ofNullable(String content) { 19 | return Optional.ofNullable(content) 20 | .map(InteractiveFooter::new); 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveHeaderThumbnail.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufDeserializer; 4 | import it.auties.protobuf.annotation.ProtobufSerializer; 5 | 6 | /** 7 | * A model that represents the jpeg thumbnail of a {@link InteractiveHeader} 8 | * 9 | * @param thumbnail the non-null jpeg thumbnail 10 | */ 11 | public record InteractiveHeaderThumbnail(byte[] thumbnail) implements InteractiveHeaderAttachment { 12 | @ProtobufDeserializer(builderBehaviour = ProtobufDeserializer.BuilderBehaviour.DISCARD) 13 | public static InteractiveHeaderThumbnail of(byte[] thumbnail) { 14 | return new InteractiveHeaderThumbnail(thumbnail); 15 | } 16 | 17 | @ProtobufSerializer 18 | @Override 19 | public byte[] thumbnail() { 20 | return thumbnail; 21 | } 22 | 23 | @Override 24 | public Type interactiveHeaderType() { 25 | return Type.THUMBNAIL; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveLocation.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * This model class describes a Location 9 | */ 10 | @ProtobufMessage(name = "Location") 11 | public record InteractiveLocation( 12 | @ProtobufProperty(index = 1, type = ProtobufType.DOUBLE) 13 | double latitude, 14 | @ProtobufProperty(index = 2, type = ProtobufType.DOUBLE) 15 | double longitude, 16 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 17 | String name 18 | ) { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveNativeFlow.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.button.InteractiveMessageContent; 7 | 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * A model class that represents a native flow 13 | * Here> is an explanation on how to use this kind of message 14 | */ 15 | @ProtobufMessage(name = "Message.InteractiveMessage.NativeFlowMessage") 16 | public record InteractiveNativeFlow( 17 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 18 | List buttons, 19 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 20 | String parameters, 21 | @ProtobufProperty(index = 3, type = ProtobufType.INT32) 22 | int version 23 | ) implements InteractiveMessageContent { 24 | @Override 25 | public Type contentType() { 26 | return Type.NATIVE_FLOW; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractivePoint.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * This model class describes a Point in space 9 | */ 10 | @ProtobufMessage(name = "Point") 11 | public record InteractivePoint( 12 | @ProtobufProperty(index = 1, type = ProtobufType.INT32) 13 | @Deprecated 14 | int xDeprecated, 15 | @ProtobufProperty(index = 2, type = ProtobufType.INT32) 16 | @Deprecated 17 | int yDeprecated, 18 | @ProtobufProperty(index = 3, type = ProtobufType.DOUBLE) 19 | double x, 20 | @ProtobufProperty(index = 4, type = ProtobufType.DOUBLE) 21 | double y 22 | ) { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/interactive/InteractiveResponseBody.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.interactive; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * A model class that represents the body of a product 11 | */ 12 | @ProtobufMessage(name = "Message.InteractiveResponseMessage.Body") 13 | public record InteractiveResponseBody( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String content 16 | ) { 17 | public static Optional ofNullable(String content) { 18 | return Optional.ofNullable(content) 19 | .map(InteractiveResponseBody::new); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredCallButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a button that can start a phone call 9 | */ 10 | @ProtobufMessage(name = "TemplateButton.CallButton") 11 | public record HighlyStructuredCallButton( 12 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 13 | HighlyStructuredMessage text, 14 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 15 | HighlyStructuredMessage phoneNumber 16 | ) implements HighlyStructuredButton { 17 | @Override 18 | public Type buttonType() { 19 | return Type.CALL; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredCurrency.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a currency 9 | */ 10 | @ProtobufMessage(name = "Message.HighlyStructuredMessage.HSMLocalizableParameter.HSMCurrency") 11 | public record HighlyStructuredCurrency( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String currencyCode, 14 | @ProtobufProperty(index = 2, type = ProtobufType.INT64) 15 | long amount1000 16 | ) implements HighlyStructuredLocalizableParameterValue { 17 | @Override 18 | public Type parameterType() { 19 | return Type.CURRENCY; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredDateTimeUnixEpoch.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.util.Clock; 7 | 8 | import java.time.ZonedDateTime; 9 | import java.util.Optional; 10 | 11 | /** 12 | * A model class that represents a time as a unix epoch 13 | */ 14 | @ProtobufMessage(name = "Message.HighlyStructuredMessage.HSMLocalizableParameter.HSMDateTime.HSMDateTimeUnixEpoch") 15 | public record HighlyStructuredDateTimeUnixEpoch( 16 | @ProtobufProperty(index = 1, type = ProtobufType.INT64) 17 | long timestampSeconds 18 | ) implements HighlyStructuredDateTimeValue { 19 | 20 | /** 21 | * Returns the timestampSeconds as a zoned date time 22 | * 23 | * @return an optional 24 | */ 25 | public Optional timestamp() { 26 | return Clock.parseSeconds(timestampSeconds); 27 | } 28 | 29 | @Override 30 | public Type dateType() { 31 | return Type.UNIX_EPOCH; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredDateTimeValue.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * A model class that represents the value of a localizable parameter 8 | */ 9 | public sealed interface HighlyStructuredDateTimeValue permits HighlyStructuredDateTimeComponent, HighlyStructuredDateTimeUnixEpoch { 10 | /** 11 | * Returns the type of date 12 | * 13 | * @return a non-null type 14 | */ 15 | Type dateType(); 16 | 17 | 18 | /** 19 | * The constants of this enumerated type describe the various type of date types that a date time can wrap 20 | */ 21 | @ProtobufEnum 22 | enum Type { 23 | /** 24 | * No date 25 | */ 26 | NONE(0), 27 | /** 28 | * Component date 29 | */ 30 | COMPONENT(1), 31 | /** 32 | * Unix epoch date 33 | */ 34 | UNIX_EPOCH(2); 35 | 36 | 37 | final int index; 38 | 39 | Type(@ProtobufEnumIndex int index) { 40 | this.index = index; 41 | } 42 | 43 | public int index() { 44 | return index; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredLocalizableParameterValue.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * A model class that represents the value of a localizable parameter 8 | */ 9 | public sealed interface HighlyStructuredLocalizableParameterValue permits HighlyStructuredCurrency, HighlyStructuredDateTime { 10 | /** 11 | * Returns the type of parameter 12 | * 13 | * @return a non-null type 14 | */ 15 | Type parameterType(); 16 | 17 | @ProtobufEnum 18 | enum Type { 19 | /** 20 | * No parameter 21 | */ 22 | NONE(0), 23 | /** 24 | * Currency parameter 25 | */ 26 | CURRENCY(2), 27 | /** 28 | * Date time parameter 29 | */ 30 | DATE_TIME(3); 31 | 32 | final int index; 33 | 34 | Type(@ProtobufEnumIndex int index) { 35 | this.index = index; 36 | } 37 | 38 | public int index() { 39 | return index; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredQuickReplyButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a quick reply button 9 | */ 10 | @ProtobufMessage(name = "TemplateButton.QuickReplyButton") 11 | public record HighlyStructuredQuickReplyButton( 12 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 13 | HighlyStructuredMessage text, 14 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 15 | String id 16 | ) implements HighlyStructuredButton { 17 | public Type buttonType() { 18 | return Type.QUICK_REPLY; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/highlyStructured/HighlyStructuredURLButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.highlyStructured; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents an url button 9 | */ 10 | @ProtobufMessage(name = "TemplateButton.URLButton") 11 | public record HighlyStructuredURLButton( 12 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 13 | HighlyStructuredMessage text, 14 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 15 | HighlyStructuredMessage url 16 | ) implements HighlyStructuredButton { 17 | @Override 18 | public Type buttonType() { 19 | return Type.URL; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/hydrated/HydratedCallButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.hydrated; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a hydrated button that can start a phone call 9 | */ 10 | @ProtobufMessage(name = "HydratedTemplateButton.HydratedCallButton") 11 | public record HydratedCallButton( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String text, 14 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 15 | String phoneNumber 16 | ) implements HydratedButton { 17 | @Override 18 | public Type buttonType() { 19 | return Type.CALL; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/hydrated/HydratedFourRowTemplateTextTitle.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.hydrated; 2 | 3 | import it.auties.protobuf.annotation.ProtobufDeserializer; 4 | import it.auties.protobuf.annotation.ProtobufSerializer; 5 | 6 | /** 7 | * A model class that represents a hydrated four row template 8 | */ 9 | public record HydratedFourRowTemplateTextTitle( 10 | String text 11 | ) implements HydratedFourRowTemplateTitle { 12 | @ProtobufDeserializer 13 | public static HydratedFourRowTemplateTextTitle of(String text) { 14 | return new HydratedFourRowTemplateTextTitle(text); 15 | } 16 | 17 | @ProtobufSerializer 18 | public String text() { 19 | return text; 20 | } 21 | 22 | @Override 23 | public Type hydratedTitleType() { 24 | return Type.TEXT; 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/hydrated/HydratedQuickReplyButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.hydrated; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.util.Bytes; 7 | 8 | import java.util.HexFormat; 9 | 10 | /** 11 | * A model class that represents a hydrated quick reply button 12 | */ 13 | @ProtobufMessage(name = "HydratedTemplateButton.HydratedQuickReplyButton") 14 | public record HydratedQuickReplyButton( 15 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 16 | String text, 17 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 18 | String id 19 | ) implements HydratedButton { 20 | /** 21 | * Constructs a new HydratedQuickReplyButton from a text with a random id 22 | * 23 | * @param text the non-null text 24 | * @return a non-null HydratedQuickReplyButton 25 | */ 26 | public static HydratedQuickReplyButton of(String text) { 27 | var id = HexFormat.of().formatHex(Bytes.random(6)); 28 | return new HydratedQuickReplyButton(text, id); 29 | } 30 | 31 | @Override 32 | public Type buttonType() { 33 | return Type.QUICK_REPLY; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/button/template/hydrated/HydratedURLButton.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.button.template.hydrated; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a hydrated url button 9 | */ 10 | @ProtobufMessage(name = "HydratedTemplateButton.HydratedURLButton") 11 | public record HydratedURLButton( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String text, 14 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 15 | String url 16 | ) implements HydratedButton { 17 | @Override 18 | public Type buttonType() { 19 | return Type.URL; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/call/Call.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.call; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | 8 | @ProtobufMessage 9 | public record Call( 10 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 11 | Jid chat, 12 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 13 | Jid caller, 14 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 15 | String id, 16 | @ProtobufProperty(index = 4, type = ProtobufType.UINT64) 17 | long timestampSeconds, 18 | @ProtobufProperty(index = 5, type = ProtobufType.BOOL) 19 | boolean video, 20 | @ProtobufProperty(index = 6, type = ProtobufType.ENUM) 21 | CallStatus status, 22 | @ProtobufProperty(index = 7, type = ProtobufType.BOOL) 23 | boolean offline 24 | ) { 25 | 26 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/call/CallStatus.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.call; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | @ProtobufEnum 7 | public enum CallStatus { 8 | RINGING(0), 9 | ACCEPTED(1), 10 | REJECTED(2), 11 | TIMED_OUT(3); 12 | 13 | final int index; 14 | 15 | CallStatus(@ProtobufEnumIndex int index) { 16 | this.index = index; 17 | } 18 | 19 | public int index() { 20 | return index; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/ChatMetadata.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import it.auties.whatsapp.model.jid.Jid; 4 | 5 | import java.time.ZonedDateTime; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Optional; 9 | 10 | /** 11 | * This model class represents the metadata of a group or community 12 | */ 13 | public record ChatMetadata( 14 | Jid jid, 15 | String subject, 16 | Optional subjectAuthor, 17 | Optional subjectTimestamp, 18 | Optional foundationTimestamp, 19 | Optional founder, 20 | Optional description, 21 | Optional descriptionId, 22 | Map settings, 23 | List participants, 24 | List pastParticipants, 25 | Optional ephemeralExpiration, 26 | Optional parentCommunityJid, 27 | boolean isCommunity, 28 | List communityGroups 29 | ) { 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/ChatParticipant.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import it.auties.protobuf.annotation.ProtobufDeserializer; 4 | import it.auties.protobuf.annotation.ProtobufSerializer; 5 | import it.auties.protobuf.exception.ProtobufDeserializationException; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | 8 | public abstract sealed class ChatParticipant permits GroupParticipant, CommunityParticipant { 9 | public abstract Jid jid(); 10 | 11 | @ProtobufDeserializer 12 | public static ChatParticipant of(byte[] data) { 13 | try { 14 | return CommunityParticipantSpec.decode(data); 15 | }catch (ProtobufDeserializationException exception) { 16 | return GroupParticipantSpec.decode(data); 17 | } 18 | } 19 | 20 | @ProtobufSerializer 21 | public byte[] toBytes() { 22 | return switch (this) { 23 | case CommunityParticipant communityParticipant -> CommunityParticipantSpec.encode(communityParticipant); 24 | case GroupParticipant groupParticipant -> GroupParticipantSpec.encode(groupParticipant); 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/ChatSetting.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | /** 4 | * Common interface for chat settings 5 | */ 6 | public sealed interface ChatSetting permits GroupSetting, CommunitySetting { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/ChatSettingPolicy.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | /** 4 | * The constants of this enumerated type describe the various policies that can be enforced for a {@link GroupSetting} or {@link CommunitySetting} in a {@link Chat} 5 | */ 6 | public enum ChatSettingPolicy { 7 | /** 8 | * Allows both admins and users 9 | */ 10 | ANYONE, 11 | /** 12 | * Allows only admins 13 | */ 14 | ADMINS; 15 | 16 | /** 17 | * Returns a GroupPolicy based on a boolean value obtained from Whatsapp 18 | * 19 | * @param input the boolean value obtained from Whatsapp 20 | * @return a non-null GroupPolicy 21 | */ 22 | public static ChatSettingPolicy of(boolean input) { 23 | return input ? ADMINS : ANYONE; 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/ChatWallpaper.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents the wallpaper of a chat. 9 | */ 10 | @ProtobufMessage(name = "WallpaperSettings") 11 | public record ChatWallpaper( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String filename, 14 | @ProtobufProperty(index = 2, type = ProtobufType.UINT32) 15 | int opacity 16 | ) { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/CommunityLinkedGroup.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | import it.auties.whatsapp.model.jid.Jid; 8 | 9 | import java.util.OptionalInt; 10 | 11 | /** 12 | * A model class that represents a group linked to a community 13 | */ 14 | @ProtobufMessage(name = "CommunityLinkedGroup") 15 | public final class CommunityLinkedGroup { 16 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 17 | private final Jid jid; 18 | 19 | @ProtobufProperty(index = 2, type = ProtobufType.UINT32) 20 | private final Integer participants; 21 | 22 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 23 | public CommunityLinkedGroup(Jid jid, Integer participants) { 24 | this.jid = jid; 25 | this.participants = participants; 26 | } 27 | 28 | public Jid jid() { 29 | return jid; 30 | } 31 | 32 | public OptionalInt participants() { 33 | return OptionalInt.of(participants); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/CommunitySetting.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | /** 4 | * The constants of this enumerated type describe the various settings that can be toggled for a community 5 | */ 6 | public enum CommunitySetting implements ChatSetting { 7 | /** 8 | * Who can add/remove groups to/from a community 9 | */ 10 | MODIFY_GROUPS, 11 | /** 12 | * Who can add/remove participants to/from a community 13 | */ 14 | ADD_PARTICIPANTS 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/GroupAction.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import it.auties.whatsapp.api.Whatsapp; 4 | import it.auties.whatsapp.model.contact.Contact; 5 | 6 | /** 7 | * The constants of this enumerated type describe the various actions that can be executed on a 8 | * {@link Contact} in a {@link Chat}. Said chat should be a group: {@link Chat#isGroup()}. Said 9 | * actions can be executed using various methods in {@link Whatsapp}. 10 | */ 11 | public enum GroupAction { 12 | /** 13 | * Adds a contact to a group 14 | */ 15 | ADD, 16 | /** 17 | * Removes a contact from a group 18 | */ 19 | REMOVE, 20 | /** 21 | * Promotes a contact to admin in a group 22 | */ 23 | PROMOTE, 24 | /** 25 | * Demotes a contact to user in a group 26 | */ 27 | DEMOTE; 28 | 29 | /** 30 | * Returns the name of this enumerated constant 31 | * 32 | * @return a lowercase non-null String 33 | */ 34 | public String data() { 35 | return name().toLowerCase(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/GroupPastParticipants.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Class representing a list of past participants in a chat group 12 | */ 13 | @ProtobufMessage(name = "PastParticipants") 14 | public record GroupPastParticipants( 15 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 16 | Jid groupJid, 17 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 18 | List pastParticipants 19 | ) { 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/chat/GroupSetting.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.chat; 2 | 3 | import it.auties.whatsapp.api.Whatsapp; 4 | 5 | /** 6 | * The constants of this enumerated type describe the various settings that can be toggled for a 7 | * group. Said settings can be changed using various methods in {@link Whatsapp}. 8 | */ 9 | public enum GroupSetting implements ChatSetting { 10 | /** 11 | * Who can edit the metadata of a group 12 | */ 13 | EDIT_GROUP_INFO, 14 | 15 | /** 16 | * Who can send messages in a group 17 | */ 18 | SEND_MESSAGES, 19 | 20 | /** 21 | * Who can add new members 22 | */ 23 | ADD_PARTICIPANTS, 24 | 25 | /** 26 | * Who can accept new members 27 | */ 28 | APPROVE_PARTICIPANTS 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/companion/CompanionLinkResult.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.companion; 2 | 3 | /** 4 | * The constants of this enumeration describe the various types of recommendedChannels that can be yielded by a new device's registration through the mobile api 5 | */ 6 | public enum CompanionLinkResult { 7 | /** 8 | * The device was successfully linked 9 | */ 10 | SUCCESS, 11 | 12 | /** 13 | * The limit of devices, as of now four, has already been reached 14 | */ 15 | MAX_DEVICES_ERROR, 16 | 17 | /** 18 | * The device couldn't be linked because of an unknown error 19 | * This usually means that the qr code is no longer valid 20 | */ 21 | RETRY_ERROR 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/companion/CompanionProperty.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.companion; 2 | 3 | /** 4 | * A model that represents an immutable property associated with the linked device 5 | * 6 | * @param name the name of the property 7 | * @param code an id that represents the property 8 | * @param value the value associated with this property 9 | * @param defaultValue the default value for this property 10 | */ 11 | public record CompanionProperty(String name, double code, Object value, Object defaultValue) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/companion/CompanionSyncKey.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.companion; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | import it.auties.whatsapp.model.sync.AppStateSyncKey; 8 | 9 | import java.util.LinkedList; 10 | 11 | @ProtobufMessage 12 | public record CompanionSyncKey( 13 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 14 | Jid companion, 15 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 16 | LinkedList keys 17 | ) { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/Info.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | public sealed interface Info permits AdReplyInfo, BusinessIdentityInfo, ContextInfo, DeviceContextInfo, ExternalAdReplyInfo, MessageIndexInfo, MessageInfo, MessageStatusInfo, NativeFlowInfo, NotificationMessageInfo, PaymentInfo, ProductListInfo, WebNotificationsInfo { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/MessageInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | import it.auties.whatsapp.model.jid.Jid; 4 | import it.auties.whatsapp.model.message.model.MessageContainer; 5 | import it.auties.whatsapp.util.Json; 6 | 7 | import java.util.OptionalLong; 8 | 9 | public sealed interface MessageInfo> extends Info permits ChatMessageInfo, NewsletterMessageInfo, MessageStatusInfo, QuotedMessageInfo { 10 | Jid parentJid(); 11 | 12 | Jid senderJid(); 13 | 14 | String id(); 15 | 16 | MessageContainer message(); 17 | 18 | T setMessage(MessageContainer message); 19 | 20 | OptionalLong timestampSeconds(); 21 | 22 | default String toJson() { 23 | return Json.writeValueAsString(this, true); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/MessageStatusInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | import it.auties.whatsapp.model.message.model.MessageStatus; 4 | 5 | public sealed interface MessageStatusInfo> extends Info, MessageInfo permits ChatMessageInfo, NewsletterMessageInfo { 6 | MessageStatus status(); 7 | 8 | T setStatus(MessageStatus status); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/NativeFlowInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.button.base.ButtonBody; 7 | 8 | /** 9 | * A model class that holds the information related to a native flow. 10 | */ 11 | @ProtobufMessage(name = "Message.ButtonsMessage.Button.NativeFlowInfo") 12 | public record NativeFlowInfo( 13 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 14 | String name, 15 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 16 | String parameters 17 | ) implements Info, ButtonBody { 18 | @Override 19 | public Type bodyType() { 20 | return Type.NATIVE_FLOW; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/NotificationMessageInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.ChatMessageKey; 7 | import it.auties.whatsapp.model.message.model.MessageContainer; 8 | import it.auties.whatsapp.util.Clock; 9 | 10 | import java.time.ZonedDateTime; 11 | import java.util.Optional; 12 | 13 | @ProtobufMessage(name = "NotificationMessageInfo") 14 | public record NotificationMessageInfo( 15 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 16 | ChatMessageKey key, 17 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 18 | MessageContainer message, 19 | @ProtobufProperty(index = 3, type = ProtobufType.UINT64) 20 | long messageTimestampSeconds, 21 | @ProtobufProperty(index = 4, type = ProtobufType.STRING) 22 | Optional participant 23 | ) implements Info { 24 | /** 25 | * Returns when the message was sent 26 | * 27 | * @return an optional 28 | */ 29 | public Optional messageTimestamp() { 30 | return Clock.parseSeconds(messageTimestampSeconds); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/ProductListInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | import it.auties.whatsapp.model.product.ProductListHeaderImage; 8 | import it.auties.whatsapp.model.product.ProductSection; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * A model class that holds the information related to a list of products. 14 | */ 15 | @ProtobufMessage(name = "Message.ListMessage.ProductListInfo") 16 | public record ProductListInfo( 17 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 18 | List productSections, 19 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 20 | ProductListHeaderImage headerImage, 21 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 22 | Jid seller 23 | ) implements Info { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/info/WebNotificationsInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.info; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.util.Clock; 7 | 8 | import java.time.ZonedDateTime; 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | @ProtobufMessage(name = "WebNotificationsInfo") 13 | public record WebNotificationsInfo( 14 | @ProtobufProperty(index = 2, type = ProtobufType.UINT64) 15 | long timestampSeconds, 16 | @ProtobufProperty(index = 3, type = ProtobufType.UINT32) 17 | int unreadChats, 18 | @ProtobufProperty(index = 4, type = ProtobufType.UINT32) 19 | int notifyMessageCount, 20 | @ProtobufProperty(index = 5, type = ProtobufType.MESSAGE) 21 | List notifyMessages 22 | ) implements Info { 23 | /** 24 | * Returns when the notification was sent 25 | * 26 | * @return an optional 27 | */ 28 | public Optional timestamp() { 29 | return Clock.parseSeconds(timestampSeconds); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/jid/JidProvider.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.jid; 2 | 3 | import it.auties.whatsapp.model.chat.Chat; 4 | import it.auties.whatsapp.model.contact.Contact; 5 | import it.auties.whatsapp.model.newsletter.Newsletter; 6 | 7 | /** 8 | * Utility interface to make providing a jid easier 9 | */ 10 | public sealed interface JidProvider permits Chat, Contact, Jid, JidServer, Newsletter { 11 | /** 12 | * Returns this object as a jid 13 | * 14 | * @return a non-null jid 15 | */ 16 | Jid toJid(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaConnection.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | 4 | import java.util.List; 5 | 6 | public record MediaConnection(String auth, int ttl, int maxBuckets, long timestamp, List hosts) { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaData.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | 8 | @ProtobufMessage(name = "MediaData") 9 | public record MediaData( 10 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 11 | String localPath 12 | ) { 13 | 14 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaDimensions.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public record MediaDimensions(@JsonProperty("width") int width, @JsonProperty("height") int height) { 6 | private static final MediaDimensions DEFAULT = new MediaDimensions(128, 128); 7 | 8 | public static MediaDimensions defaultDimensions() { 9 | return DEFAULT; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaFile.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | public record MediaFile(byte[] encryptedFile, byte[] fileSha256, byte[] fileEncSha256, byte[] mediaKey, long fileLength, 4 | String directPath, String url, String handle, Long timestamp) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaKeys.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | import it.auties.whatsapp.crypto.Hkdf; 4 | import it.auties.whatsapp.util.Bytes; 5 | 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.Arrays; 8 | 9 | import static it.auties.whatsapp.util.SignalConstants.IV_LENGTH; 10 | import static it.auties.whatsapp.util.SignalConstants.KEY_LENGTH; 11 | 12 | public record MediaKeys(byte[] mediaKey, byte[] iv, byte[] cipherKey, byte[] macKey, byte[] ref) { 13 | private static final int EXPANDED_SIZE = 112; 14 | 15 | public static MediaKeys random(String type) { 16 | return of(Bytes.random(32), type); 17 | } 18 | 19 | public static MediaKeys of(byte[] key, String type) { 20 | var keyName = type.getBytes(StandardCharsets.UTF_8); 21 | var expanded = Hkdf.extractAndExpand(key, keyName, EXPANDED_SIZE); 22 | var iv = Arrays.copyOfRange(expanded, 0, IV_LENGTH); 23 | var cipherKey = Arrays.copyOfRange(expanded, IV_LENGTH, IV_LENGTH + KEY_LENGTH); 24 | var macKey = Arrays.copyOfRange(expanded, IV_LENGTH + KEY_LENGTH, IV_LENGTH + KEY_LENGTH * 2); 25 | var ref = Arrays.copyOfRange(expanded, IV_LENGTH + KEY_LENGTH * 2, expanded.length); 26 | return new MediaKeys(key, iv, cipherKey, macKey, ref); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaUpload.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public record MediaUpload(@JsonProperty("direct_path") String directPath, @JsonProperty("url") String url, 6 | @JsonProperty("handle") String handle) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/media/MediaVisibility.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.media; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | /** 7 | * The constants of this enumerated type describe the various types of media visibility that can be 8 | * set for a chat 9 | */ 10 | @ProtobufEnum(name = "MediaVisibility") 11 | public enum MediaVisibility { 12 | /** 13 | * Default 14 | */ 15 | DEFAULT(0), 16 | /** 17 | * Off 18 | */ 19 | OFF(1), 20 | /** 21 | * On 22 | */ 23 | ON(2); 24 | 25 | final int index; 26 | 27 | MediaVisibility(@ProtobufEnumIndex int index) { 28 | this.index = index; 29 | } 30 | 31 | public int index() { 32 | return index; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/button/ButtonsMessageHeaderText.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.button; 2 | 3 | import it.auties.protobuf.annotation.ProtobufDeserializer; 4 | import it.auties.protobuf.annotation.ProtobufSerializer; 5 | 6 | public record ButtonsMessageHeaderText(String text) implements ButtonsMessageHeader { 7 | @ProtobufDeserializer 8 | public static ButtonsMessageHeaderText of(String text) { 9 | return new ButtonsMessageHeaderText(text); 10 | } 11 | 12 | @ProtobufSerializer 13 | public String text() { 14 | return text; 15 | } 16 | 17 | @Override 18 | public Type buttonHeaderType() { 19 | return Type.TEXT; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/button/NativeFlowResponseMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.button; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.ButtonMessage; 7 | import it.auties.whatsapp.model.message.model.MessageType; 8 | 9 | @ProtobufMessage(name = "Message.InteractiveResponseMessage.NativeFlowResponseMessage") 10 | public record NativeFlowResponseMessage( 11 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 12 | String name, 13 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 14 | String paramsJson, 15 | @ProtobufProperty(index = 3, type = ProtobufType.INT32) 16 | int version 17 | ) implements ButtonMessage { 18 | @Override 19 | public MessageType type() { 20 | return MessageType.NATIVE_FLOW_RESPONSE; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/ButtonMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.button.template.highlyStructured.HighlyStructuredMessage; 4 | import it.auties.whatsapp.model.message.button.*; 5 | import it.auties.whatsapp.model.message.standard.ProductMessage; 6 | 7 | /** 8 | * A model interface that represents a button message 9 | */ 10 | public sealed interface ButtonMessage extends Message permits ButtonsMessage, HighlyStructuredMessage, ListMessage, NativeFlowResponseMessage, TemplateMessage, ButtonReplyMessage, InteractiveMessage, ProductMessage { 11 | @Override 12 | default MessageCategory category() { 13 | return MessageCategory.BUTTON; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/ButtonReplyMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.message.button.ButtonsResponseMessage; 4 | import it.auties.whatsapp.model.message.button.ListResponseMessage; 5 | import it.auties.whatsapp.model.message.button.TemplateReplyMessage; 6 | 7 | /** 8 | * A model interface that represents a reply to a button message 9 | */ 10 | public sealed interface ButtonReplyMessage> extends ContextualMessage, ButtonMessage permits ListResponseMessage, TemplateReplyMessage, ButtonsResponseMessage { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/ContextualMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.info.ContextInfo; 4 | import it.auties.whatsapp.model.message.button.*; 5 | import it.auties.whatsapp.model.message.payment.PaymentOrderMessage; 6 | import it.auties.whatsapp.model.message.standard.*; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * A model interface that represents a message sent by a contact that provides a context. Classes 12 | * that implement this interface must provide an accessor named contextInfo to access said 13 | * property. 14 | */ 15 | public sealed interface ContextualMessage> extends Message 16 | permits ButtonsMessage, InteractiveMessage, InteractiveResponseMessage, ListMessage, 17 | TemplateMessage, ButtonReplyMessage, MediaMessage, PaymentOrderMessage, ContactMessage, ContactsMessage, 18 | GroupInviteMessage, LiveLocationMessage, LocationMessage, PollCreationMessage, ProductMessage, RequestPhoneNumberMessage, TextMessage { 19 | Optional contextInfo(); 20 | 21 | T setContextInfo(ContextInfo contextInfo); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/EncryptedMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.message.standard.EncryptedReactionMessage; 4 | import it.auties.whatsapp.model.message.standard.PollUpdateMessage; 5 | 6 | public sealed interface EncryptedMessage permits EncryptedReactionMessage, PollUpdateMessage { 7 | String secretName(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/FutureMessageContainer.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A container for a future message 9 | */ 10 | @ProtobufMessage(name = "Message.FutureProofMessage") 11 | public record FutureMessageContainer( 12 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 13 | MessageContainer content 14 | ) { 15 | static FutureMessageContainer of(Message message) { 16 | return new FutureMessageContainer(MessageContainer.of(message)); 17 | } 18 | 19 | static FutureMessageContainer of(MessageContainer container) { 20 | return new FutureMessageContainer(container); 21 | } 22 | 23 | Message unbox() { 24 | return content.content(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/KeepInChatType.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | @ProtobufEnum(name = "KeepType") 7 | public enum KeepInChatType { 8 | UNKNOWN(0), 9 | KEEP_FOR_ALL(1), 10 | UNDO_KEEP_FOR_ALL(2); 11 | 12 | final int index; 13 | 14 | KeepInChatType(@ProtobufEnumIndex int index) { 15 | this.index = index; 16 | } 17 | 18 | public int index() { 19 | return this.index; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/Message.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.message.standard.*; 4 | 5 | /** 6 | * A model interface that represents a message sent by a contact or by Whatsapp. 7 | */ 8 | public sealed interface Message permits ButtonMessage, ContextualMessage, PaymentMessage, ServerMessage, CallMessage, EmptyMessage, KeepInChatMessage, NewsletterAdminInviteMessage, PollUpdateMessage, ReactionMessage { 9 | /** 10 | * Return message type 11 | * 12 | * @return a non-null message type 13 | */ 14 | MessageType type(); 15 | 16 | /** 17 | * Return message category 18 | * 19 | * @return a non-null message category 20 | */ 21 | MessageCategory category(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/MessageCategory.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | /** 4 | * The constants of this enumerated type describe the various categories of messages that a 5 | * {@link MessageContainer} can wrap 6 | */ 7 | public enum MessageCategory { 8 | /** 9 | * Device message 10 | */ 11 | BUTTON, 12 | /** 13 | * Payment message 14 | */ 15 | PAYMENT, 16 | /** 17 | * Payment message 18 | */ 19 | MEDIA, 20 | /** 21 | * Server message 22 | */ 23 | SERVER, 24 | /** 25 | * Device message 26 | */ 27 | DEVICE, 28 | /** 29 | * Standard message 30 | */ 31 | STANDARD 32 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/PaymentMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.message.payment.*; 4 | 5 | /** 6 | * A model interface that represents a message regarding a payment 7 | */ 8 | public sealed interface PaymentMessage extends Message permits CancelPaymentRequestMessage, DeclinePaymentRequestMessage, PaymentInviteMessage, PaymentInvoiceMessage, PaymentOrderMessage, RequestPaymentMessage, SendPaymentMessage { 9 | @Override 10 | default MessageCategory category() { 11 | return MessageCategory.PAYMENT; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/PublicServiceAnnouncementStatus.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.util.Clock; 7 | 8 | import java.time.ZonedDateTime; 9 | import java.util.Optional; 10 | 11 | @ProtobufMessage(name = "StatusPSA") 12 | public record PublicServiceAnnouncementStatus( 13 | @ProtobufProperty(index = 44, type = ProtobufType.STRING) 14 | String campaignId, 15 | @ProtobufProperty(index = 45, type = ProtobufType.UINT64) 16 | long campaignExpirationTimestampSeconds 17 | ) { 18 | public Optional campaignExpirationTimestamp() { 19 | return Clock.parseSeconds(campaignExpirationTimestampSeconds); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/model/ServerMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.model; 2 | 3 | import it.auties.whatsapp.model.message.server.*; 4 | import it.auties.whatsapp.model.message.standard.EncryptedReactionMessage; 5 | 6 | /** 7 | * A model interface that represents a message sent by a WhatsappWeb's server 8 | */ 9 | public sealed interface ServerMessage extends Message permits DeviceSentMessage, DeviceSyncMessage, EncryptedReactionMessage, ProtocolMessage, SenderKeyDistributionMessage, StickerSyncRMRMessage { 10 | @Override 11 | default MessageCategory category() { 12 | return MessageCategory.SERVER; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/payment/CancelPaymentRequestMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.payment; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.ChatMessageKey; 7 | import it.auties.whatsapp.model.message.model.MessageType; 8 | import it.auties.whatsapp.model.message.model.PaymentMessage; 9 | 10 | /** 11 | * A model class that represents a message that cancels a {@link RequestPaymentMessage}. 12 | */ 13 | @ProtobufMessage(name = "Message.CancelPaymentRequestMessage") 14 | public record CancelPaymentRequestMessage( 15 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 16 | ChatMessageKey key 17 | ) implements PaymentMessage { 18 | @Override 19 | public MessageType type() { 20 | return MessageType.CANCEL_PAYMENT_REQUEST; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/payment/DeclinePaymentRequestMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.payment; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.ChatMessageKey; 7 | import it.auties.whatsapp.model.message.model.MessageType; 8 | import it.auties.whatsapp.model.message.model.PaymentMessage; 9 | 10 | /** 11 | * A model class that represents a message to decline a {@link RequestPaymentMessage}. 12 | */ 13 | @ProtobufMessage(name = "Message.DeclinePaymentRequestMessage") 14 | public record DeclinePaymentRequestMessage( 15 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 16 | ChatMessageKey key 17 | ) implements PaymentMessage { 18 | @Override 19 | public MessageType type() { 20 | return MessageType.DECLINE_PAYMENT_REQUEST; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/server/DeviceSentMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.server; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | import it.auties.whatsapp.model.message.model.MessageContainer; 8 | import it.auties.whatsapp.model.message.model.MessageType; 9 | import it.auties.whatsapp.model.message.model.ServerMessage; 10 | 11 | import java.util.Optional; 12 | 13 | /** 14 | * A model class that represents a message that refers to a message sent by the device paired with 15 | * the active WhatsappWeb session. 16 | */ 17 | @ProtobufMessage(name = "Message.DeviceSentMessage") 18 | public record DeviceSentMessage( 19 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 20 | Jid destinationJid, 21 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 22 | MessageContainer message, 23 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 24 | Optional phash 25 | ) implements ServerMessage { 26 | 27 | @Override 28 | public MessageType type() { 29 | return MessageType.DEVICE_SENT; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/server/DeviceSyncMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.server; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.MessageType; 7 | import it.auties.whatsapp.model.message.model.ServerMessage; 8 | 9 | /** 10 | * A model class that represents a message that refers to a message sent by the device paired with 11 | * the active WhatsappWeb session to dataSync. 12 | */ 13 | @ProtobufMessage(name = "Message.DeviceSyncMessage") 14 | public record DeviceSyncMessage( 15 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 16 | byte[] serializedXmlBytes 17 | ) implements ServerMessage { 18 | @Override 19 | public MessageType type() { 20 | return MessageType.DEVICE_SYNC; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/server/SenderKeyDistributionMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.server; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.MessageType; 7 | import it.auties.whatsapp.model.message.model.ServerMessage; 8 | 9 | /** 10 | * A model class that represents a message sent by WhatsappWeb for security purposes. Whatsapp 11 | * follows the Signal Standard, for more information about this message visit their 13 | * documentation 14 | */ 15 | @ProtobufMessage(name = "Message.SenderKeyDistributionMessage") 16 | public record SenderKeyDistributionMessage( 17 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 18 | String groupId, 19 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 20 | byte[] data 21 | ) implements ServerMessage { 22 | @Override 23 | public MessageType type() { 24 | return MessageType.SENDER_KEY_DISTRIBUTION; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/server/StickerSyncRMRMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.server; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.MessageType; 7 | import it.auties.whatsapp.model.message.model.ServerMessage; 8 | 9 | import java.util.List; 10 | 11 | @ProtobufMessage(name = "Message.StickerSyncRMRMessage") 12 | public record StickerSyncRMRMessage( 13 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 14 | List hash, 15 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 16 | String rmrSource, 17 | @ProtobufProperty(index = 3, type = ProtobufType.INT64) 18 | long requestTimestamp 19 | ) implements ServerMessage { 20 | @Override 21 | public MessageType type() { 22 | return MessageType.STICKER_SYNC; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/standard/CallMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.standard; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.Message; 7 | import it.auties.whatsapp.model.message.model.MessageCategory; 8 | import it.auties.whatsapp.model.message.model.MessageType; 9 | 10 | 11 | /** 12 | * A message that contains information related to a call 13 | */ 14 | @ProtobufMessage(name = "Message.Call") 15 | public record CallMessage( 16 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 17 | byte[] key, 18 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 19 | String source, 20 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) 21 | byte[] data, 22 | @ProtobufProperty(index = 4, type = ProtobufType.UINT32) 23 | int delay 24 | ) implements Message { 25 | @Override 26 | public MessageType type() { 27 | return MessageType.CALL; 28 | } 29 | 30 | @Override 31 | public MessageCategory category() { 32 | return MessageCategory.STANDARD; 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/standard/EmptyMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.standard; 2 | 3 | import it.auties.whatsapp.model.message.model.Message; 4 | import it.auties.whatsapp.model.message.model.MessageCategory; 5 | import it.auties.whatsapp.model.message.model.MessageType; 6 | 7 | /** 8 | * A model class that represents an empty message. Used to prevent NPEs from empty messages sent by 9 | * Whatsapp. Consider this a stub type. 10 | */ 11 | public final class EmptyMessage implements Message { 12 | @Override 13 | public MessageType type() { 14 | return MessageType.EMPTY; 15 | } 16 | 17 | @Override 18 | public MessageCategory category() { 19 | return MessageCategory.STANDARD; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/standard/EncryptedReactionMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.standard; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.ChatMessageKey; 7 | import it.auties.whatsapp.model.message.model.EncryptedMessage; 8 | import it.auties.whatsapp.model.message.model.MessageType; 9 | import it.auties.whatsapp.model.message.model.ServerMessage; 10 | 11 | @ProtobufMessage(name = "Message.EncReactionMessage") 12 | public record EncryptedReactionMessage( 13 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 14 | ChatMessageKey targetMessageKey, 15 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 16 | byte[] encPayload, 17 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) 18 | byte[] encIv 19 | ) implements ServerMessage, EncryptedMessage { 20 | public String secretName() { 21 | return "Enc Reaction"; 22 | } 23 | 24 | @Override 25 | public MessageType type() { 26 | return MessageType.ENCRYPTED_REACTION; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/message/standard/KeepInChatMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.message.standard; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.*; 7 | 8 | 9 | @ProtobufMessage(name = "Message.KeepInChatMessage") 10 | public record KeepInChatMessage( 11 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 12 | ChatMessageKey key, 13 | @ProtobufProperty(index = 2, type = ProtobufType.ENUM) 14 | KeepInChatType keepType, 15 | @ProtobufProperty(index = 3, type = ProtobufType.INT64) 16 | long timestampMilliseconds 17 | ) implements Message { 18 | @Override 19 | public MessageType type() { 20 | return MessageType.KEEP_IN_CHAT; 21 | } 22 | 23 | @Override 24 | public MessageCategory category() { 25 | return MessageCategory.STANDARD; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/mobile/AccountInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.mobile; 2 | 3 | import java.time.ZonedDateTime; 4 | 5 | public record AccountInfo(ZonedDateTime lastRegistrationTimestamp, ZonedDateTime creationTimestamp) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/mobile/VerificationCodeStatus.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.mobile; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | 5 | public enum VerificationCodeStatus { 6 | SUCCESS, 7 | ERROR; 8 | 9 | @JsonCreator 10 | public static VerificationCodeStatus of(String name) { 11 | return name.equalsIgnoreCase("ok") 12 | || name.equalsIgnoreCase("sent") 13 | || name.equalsIgnoreCase("verified") ? SUCCESS : ERROR; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterDescription.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | import it.auties.whatsapp.util.Clock; 8 | 9 | import java.time.ZonedDateTime; 10 | import java.util.Optional; 11 | 12 | @ProtobufMessage 13 | public record NewsletterDescription( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String id, 16 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 17 | String text, 18 | @ProtobufProperty(index = 3, type = ProtobufType.UINT64) 19 | @JsonProperty("update_time") 20 | long updateTimeSeconds 21 | ) { 22 | public Optional updateTime() { 23 | return Clock.parseSeconds(updateTimeSeconds); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterName.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | import it.auties.whatsapp.util.Clock; 8 | 9 | import java.time.ZonedDateTime; 10 | import java.util.Optional; 11 | 12 | @ProtobufMessage 13 | public record NewsletterName( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String id, 16 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 17 | String text, 18 | @ProtobufProperty(index = 3, type = ProtobufType.UINT64) 19 | @JsonProperty("update_time") 20 | long updateTimeSeconds 21 | ) { 22 | public Optional updateTime() { 23 | return Clock.parseSeconds(updateTimeSeconds); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterPicture.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | 8 | @ProtobufMessage 9 | public record NewsletterPicture( 10 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 11 | String id, 12 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 13 | String type, 14 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 15 | @JsonProperty("direct_path") String directPath 16 | ) { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterPreview.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public record NewsletterPreview(String id, String type, @JsonProperty("direct_path") String directPath) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | 8 | @ProtobufMessage 9 | public record NewsletterSettings( 10 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 11 | @JsonProperty("reaction_codes") 12 | NewsletterReactionSettings reactionCodes 13 | ) { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterState.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | 8 | import java.util.Objects; 9 | 10 | @ProtobufMessage 11 | public final class NewsletterState { 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | private String type; 14 | 15 | @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) 16 | public NewsletterState(String type) { 17 | this.type = type; 18 | } 19 | 20 | public String type() { 21 | return type; 22 | } 23 | 24 | public NewsletterState setType(String type) { 25 | this.type = type; 26 | return this; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "NewsletterState{" + 32 | "type='" + type + '\'' + 33 | '}'; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | return o instanceof NewsletterState that && Objects.equals(type, that.type); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return Objects.hash(type); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/newsletter/NewsletterViewerRole.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.newsletter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonValue; 4 | import it.auties.protobuf.annotation.ProtobufEnum; 5 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 6 | 7 | import java.util.Arrays; 8 | 9 | @ProtobufEnum 10 | public enum NewsletterViewerRole { 11 | UNKNOWN(0), 12 | OWNER(1), 13 | SUBSCRIBER(2), 14 | ADMIN(3), 15 | GUEST(4); 16 | 17 | final int index; 18 | 19 | NewsletterViewerRole(@ProtobufEnumIndex int index) { 20 | this.index = index; 21 | } 22 | 23 | public int index() { 24 | return index; 25 | } 26 | 27 | public static NewsletterViewerRole of(int index) { 28 | return index >= values().length ? UNKNOWN : values()[index]; 29 | } 30 | 31 | public static NewsletterViewerRole of(String name) { 32 | return Arrays.stream(values()) 33 | .filter(entry -> entry.name().equalsIgnoreCase(name)) 34 | .findFirst() 35 | .orElse(UNKNOWN); 36 | } 37 | 38 | @JsonValue 39 | @Override 40 | public String toString() { 41 | return name(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/payment/PaymentMediaData.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.payment; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | 8 | @ProtobufMessage(name = "PaymentBackground.MediaData") 9 | public record PaymentMediaData( 10 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 11 | byte[] mediaKey, 12 | @ProtobufProperty(index = 2, type = ProtobufType.INT64) 13 | long mediaKeyTimestamp, 14 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) 15 | byte[] mediaSha256, 16 | @ProtobufProperty(index = 4, type = ProtobufType.BYTES) 17 | byte[] mediaEncryptedSha256, 18 | @ProtobufProperty(index = 5, type = ProtobufType.STRING) 19 | String mediaDirectPath 20 | ) { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/payment/PaymentMoney.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.payment; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "Money") 8 | public record PaymentMoney( 9 | @ProtobufProperty(index = 1, type = ProtobufType.INT64) 10 | long money, 11 | @ProtobufProperty(index = 2, type = ProtobufType.UINT32) 12 | int offset, 13 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 14 | String currencyCode 15 | ) { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/PollAdditionalMetadata.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents additional metadata about a {@link it.auties.whatsapp.model.message.standard.PollCreationMessage} 9 | */ 10 | @ProtobufMessage(name = "PollAdditionalMetadata") 11 | public record PollAdditionalMetadata( 12 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 13 | boolean pollInvalidated 14 | ) { 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/PollOption.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents an option in a 9 | * {@link it.auties.whatsapp.model.message.standard.PollCreationMessage} 10 | */ 11 | @ProtobufMessage(name = "MsgOpaqueData.PollOption") 12 | public record PollOption( 13 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 14 | String name 15 | ) { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/PollUpdate.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.model.ChatMessageKey; 7 | import it.auties.whatsapp.util.Clock; 8 | 9 | import java.time.ZonedDateTime; 10 | import java.util.Optional; 11 | 12 | /** 13 | * A model class that represents metadata about a 14 | * {@link it.auties.whatsapp.model.message.standard.PollUpdateMessage} Not currently used, so it's 15 | * package private 16 | */ 17 | @ProtobufMessage(name = "PollUpdate") 18 | public record PollUpdate( 19 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 20 | ChatMessageKey pollUpdateMessageKey, 21 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 22 | PollUpdateEncryptedOptions vote, 23 | @ProtobufProperty(index = 3, type = ProtobufType.INT64) 24 | long senderTimestampMilliseconds 25 | ) { 26 | /** 27 | * Returns when the update was sent 28 | * 29 | * @return an optional 30 | */ 31 | public Optional senderTimestamp() { 32 | return Clock.parseMilliseconds(senderTimestampMilliseconds); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/PollUpdateEncryptedMetadata.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | 8 | /** 9 | * A model class that represents the cypher data to decode a 10 | * {@link it.auties.whatsapp.model.message.standard.PollUpdateMessage} 11 | */ 12 | @ProtobufMessage(name = "PollEncValue") 13 | public record PollUpdateEncryptedMetadata( 14 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 15 | byte[] payload, 16 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 17 | byte[] iv 18 | ) { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/PollUpdateEncryptedOptions.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * A model class that represents the cypher data to decode the votes of a user inside {@link it.auties.whatsapp.model.message.standard.PollUpdateMessage} 11 | */ 12 | @ProtobufMessage(name = "Message.PollVoteMessage") 13 | public record PollUpdateEncryptedOptions( 14 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 15 | List selectedOptions 16 | ) { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/PollUpdateMessageMetadata.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | 5 | /** 6 | * A model class that represents additional metadata about a 7 | * {@link it.auties.whatsapp.model.message.standard.PollUpdateMessage} Currently empty 8 | */ 9 | @ProtobufMessage(name = "Message.PollUpdateMessageMetadata") 10 | public record PollUpdateMessageMetadata( 11 | 12 | ) { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/poll/SelectedPollOption.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.poll; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.jid.Jid; 7 | 8 | /** 9 | * A model class that represents a selected option in a {@link it.auties.whatsapp.model.message.standard.PollCreationMessage} 10 | */ 11 | @ProtobufMessage 12 | public record SelectedPollOption( 13 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 14 | Jid jid, 15 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 16 | String name 17 | ) { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/product/LeaveNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.product; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record LeaveNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid) { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/product/ProductCatalog.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.product; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.message.standard.ImageMessage; 7 | 8 | /** 9 | * A model class that represents a product catalog 10 | */ 11 | @ProtobufMessage(name = "Message.ProductMessage.CatalogSnapshot") 12 | public record ProductCatalog( 13 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 14 | ImageMessage catalogImage, 15 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 16 | String title, 17 | @ProtobufProperty(index = 3, type = ProtobufType.STRING) 18 | String description 19 | ) { 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/product/ProductListHeaderImage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.product; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents the header of a product list 9 | */ 10 | @ProtobufMessage(name = "Message.ListMessage.ProductListHeaderImage") 11 | public record ProductListHeaderImage( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String id, 14 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 15 | byte[] thumbnail 16 | ) { 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/product/ProductSection.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.product; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * A model class that represents a section inside a list of products 11 | */ 12 | @ProtobufMessage(name = "Message.ListMessage.ProductSection") 13 | public record ProductSection( 14 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 15 | String title, 16 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 17 | List products 18 | ) { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/product/ProductSectionEntry.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.product; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | /** 8 | * A model class that represents a product 9 | */ 10 | @ProtobufMessage(name = "Message.ListMessage.Product") 11 | public record ProductSectionEntry( 12 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 13 | String id 14 | ) { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/AcceptAdminInviteNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record AcceptAdminInviteNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid) { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/CommunityLinkedGroupsRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record CommunityLinkedGroupsRequest(Variable variables) { 7 | public record Variable(Input input) { 8 | 9 | } 10 | 11 | public record Input(@JsonProperty("group_jid") Jid groupJid, @JsonProperty("query_context") String context) { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/CreateAdminInviteNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record CreateAdminInviteNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid, @JsonProperty("user_id") Jid admin) { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/CreateNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public record CreateNewsletterRequest(Variable variables) { 6 | public record Variable(@JsonProperty("input") NewsletterInput newsletterInput) { 7 | 8 | } 9 | 10 | public record NewsletterInput(String name, String description, String picture) { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/JoinNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record JoinNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid) { 8 | 9 | } 10 | 11 | public record UpdatePayload(String description) { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/LeaveNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record LeaveNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid, UpdatePayload updates) { 8 | 9 | } 10 | 11 | public record UpdatePayload(String description) { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/MessageSendRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import it.auties.whatsapp.model.info.ChatMessageInfo; 4 | import it.auties.whatsapp.model.info.NewsletterMessageInfo; 5 | import it.auties.whatsapp.model.jid.Jid; 6 | 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | public sealed interface MessageSendRequest permits MessageSendRequest.Chat, MessageSendRequest.Newsletter { 11 | record Chat(ChatMessageInfo info, Set recipients, boolean force, boolean peer, 12 | Map additionalAttributes) implements MessageSendRequest { 13 | public Chat(ChatMessageInfo info) { 14 | this(info, null, false, false, null); 15 | } 16 | 17 | public boolean hasRecipientOverride() { 18 | return recipients != null && !recipients.isEmpty(); 19 | } 20 | } 21 | 22 | record Newsletter(NewsletterMessageInfo info, Map additionalAttributes) implements MessageSendRequest { 23 | public Newsletter(NewsletterMessageInfo info) { 24 | this(info, null); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/NewsletterSubscribersRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import it.auties.whatsapp.model.jid.Jid; 4 | 5 | public record NewsletterSubscribersRequest(Variable variables) { 6 | public record Variable(Input input) { 7 | 8 | } 9 | 10 | public record Input(Jid key, String type, String role) { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/QueryNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | import it.auties.whatsapp.model.newsletter.NewsletterViewerRole; 6 | 7 | public record QueryNewsletterRequest(Variable variables) { 8 | public record Variable(Input input, @JsonProperty("fetch_viewer_metadata") boolean fetchViewerMetadata, 9 | @JsonProperty("fetch_full_image") boolean fetchFullImage, 10 | @JsonProperty("fetch_creation_time") boolean fetchCreationTime) { 11 | 12 | } 13 | 14 | public record Input(Jid key, String type, @JsonProperty("view_role") NewsletterViewerRole viewRole) { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/RecommendedNewslettersRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public record RecommendedNewslettersRequest(Variable variables) { 8 | public record Variable(Input input) { 9 | 10 | } 11 | 12 | public record Input(String view, Filters filters, int limit) { 13 | 14 | } 15 | 16 | public record Filters(@JsonProperty("country_codes") List countyCodes) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/RevokeAdminInviteNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record RevokeAdminInviteNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid, @JsonProperty("user_id") Jid admin) { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/SubscribedNewslettersRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | public record SubscribedNewslettersRequest(Variable variables) { 4 | public record Variable() { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/UpdateNewsletterRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | 6 | public record UpdateNewsletterRequest(Variable variables) { 7 | public record Variable(@JsonProperty("newsletter_id") Jid jid, UpdatePayload updates) { 8 | 9 | } 10 | 11 | public record UpdatePayload(String description) { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/request/UserChosenNameRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public record UserChosenNameRequest(List variables) { 8 | public record Variable(@JsonProperty("user_id") String userId) { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/AbPropsResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public record AbPropsResponse(@JsonProperty("ab_hash") String abHash) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/AcceptAdminInviteNewsletterResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import it.auties.whatsapp.model.jid.Jid; 6 | import it.auties.whatsapp.util.Json; 7 | 8 | import java.util.Map; 9 | import java.util.Optional; 10 | 11 | public record AcceptAdminInviteNewsletterResponse(@JsonProperty("id") Jid jid) { 12 | @JsonCreator 13 | AcceptAdminInviteNewsletterResponse(Map json) { 14 | this(Jid.of(json.get("id"))); 15 | } 16 | 17 | public static Optional ofJson(String json) { 18 | return Json.readValue(json, JsonData.class) 19 | .data() 20 | .map(JsonResponse::response); 21 | } 22 | 23 | private record JsonData(Optional data) { 24 | 25 | } 26 | 27 | private record JsonResponse( 28 | @JsonProperty("xwa2_newsletter_admin_invite_accept") AcceptAdminInviteNewsletterResponse response) { 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/CheckNumberResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | public record CheckNumberResponse(boolean hasWhatsapp, boolean hasBan, RegistrationResponse metadata) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/CreateAdminInviteNewsletterResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import it.auties.whatsapp.model.jid.Jid; 6 | import it.auties.whatsapp.util.Json; 7 | 8 | import java.util.Map; 9 | import java.util.Optional; 10 | 11 | public record CreateAdminInviteNewsletterResponse(@JsonProperty("id") Jid jid, @JsonProperty("mute") Long mute) { 12 | @JsonCreator 13 | CreateAdminInviteNewsletterResponse(Map json) { 14 | this(Jid.of(json.get("id")), Long.parseLong(json.get("invite_expiration_time"))); 15 | } 16 | 17 | public static Optional ofJson(String json) { 18 | return Json.readValue(json, JsonData.class) 19 | .data() 20 | .map(JsonResponse::response); 21 | } 22 | 23 | private record JsonData(Optional data) { 24 | 25 | } 26 | 27 | private record JsonResponse( 28 | @JsonProperty("xwa2_newsletter_admin_invite_create") CreateAdminInviteNewsletterResponse response) { 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/HasWhatsappResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import it.auties.whatsapp.model.jid.Jid; 4 | 5 | public record HasWhatsappResponse(Jid contact, boolean hasWhatsapp) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/NewsletterLeaveResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | import it.auties.whatsapp.util.Json; 6 | 7 | import java.util.Optional; 8 | 9 | public record NewsletterLeaveResponse(@JsonProperty("id") Jid jid) { 10 | public static Optional ofJson(String json) { 11 | return Json.readValue(json, JsonResponse.class) 12 | .data() 13 | .map(JsonData::response); 14 | } 15 | 16 | private record JsonResponse(Optional data) { 17 | 18 | } 19 | 20 | private record JsonData(@JsonProperty("xwa2_notify_newsletter_on_leave") NewsletterLeaveResponse response) { 21 | 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/NewsletterMuteResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import it.auties.whatsapp.model.jid.Jid; 6 | import it.auties.whatsapp.util.Json; 7 | 8 | import java.util.Map; 9 | import java.util.Objects; 10 | import java.util.Optional; 11 | 12 | public record NewsletterMuteResponse(@JsonProperty("id") Jid jid, @JsonProperty("mute") boolean mute) { 13 | @JsonCreator 14 | NewsletterMuteResponse(Map json) { 15 | this(Jid.of(json.get("id")), Objects.equals(json.get("mute"), "ON")); 16 | } 17 | 18 | public static Optional ofJson(String json) { 19 | return Json.readValue(json, JsonData.class) 20 | .data() 21 | .map(JsonResponse::response); 22 | } 23 | 24 | private record JsonData(Optional data) { 25 | 26 | } 27 | 28 | private record JsonResponse( 29 | @JsonProperty("xwa2_notify_newsletter_on_mute_change") NewsletterMuteResponse response) { 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/NewsletterResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import it.auties.whatsapp.model.newsletter.Newsletter; 5 | import it.auties.whatsapp.util.Json; 6 | 7 | import java.util.Map; 8 | import java.util.NoSuchElementException; 9 | import java.util.Optional; 10 | 11 | public record NewsletterResponse(Newsletter newsletter) { 12 | @JsonCreator 13 | NewsletterResponse(Map json) { 14 | this(json.values() 15 | .stream() 16 | .findFirst() 17 | .orElseThrow(() -> new NoSuchElementException("Missing newsletter"))); 18 | } 19 | 20 | public static Optional ofJson(String json) { 21 | return Json.readValue(json, JsonResponse.class).data(); 22 | } 23 | 24 | private record JsonResponse(Optional data) { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/NewsletterStateResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.model.jid.Jid; 5 | import it.auties.whatsapp.model.newsletter.NewsletterState; 6 | import it.auties.whatsapp.util.Json; 7 | 8 | import java.util.Optional; 9 | 10 | public record NewsletterStateResponse(@JsonProperty("id") Jid jid, @JsonProperty("is_requestor") boolean isRequestor, 11 | NewsletterState state) { 12 | public static Optional ofJson(String json) { 13 | return Json.readValue(json, JsonResponse.class) 14 | .data() 15 | .map(JsonData::response); 16 | } 17 | 18 | private record JsonResponse(Optional data) { 19 | 20 | } 21 | 22 | private record JsonData(@JsonProperty("xwa2_notify_newsletter_on_state_change") NewsletterStateResponse response) { 23 | 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/NewsletterSubscribersResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import it.auties.whatsapp.util.Json; 5 | 6 | import java.util.Optional; 7 | 8 | public record NewsletterSubscribersResponse(@JsonProperty("subscribers_count") Long subscribersCount) { 9 | public static Optional ofJson(String json) { 10 | return Json.readValue(json, JsonResponse.class) 11 | .data() 12 | .map(response -> response.result().response()); 13 | } 14 | 15 | private record JsonResponse(Optional data) { 16 | 17 | } 18 | 19 | private record JsonData(@JsonProperty("xwa2_newsletter") WrappedResult result) { 20 | 21 | } 22 | 23 | private record WrappedResult(@JsonProperty("thread_metadata") NewsletterSubscribersResponse response) { 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/RecommendedNewslettersResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAlias; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import it.auties.whatsapp.model.newsletter.Newsletter; 6 | import it.auties.whatsapp.util.Json; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | public record RecommendedNewslettersResponse(@JsonProperty("result") List newsletters) { 12 | public static Optional ofJson(String json) { 13 | return Json.readValue(json, JsonResponse.class) 14 | .data() 15 | .map(JsonData::response); 16 | } 17 | 18 | private record JsonResponse(Optional data) { 19 | 20 | } 21 | 22 | private record JsonData( 23 | @JsonAlias({"xwa2_newsletter_update", "xwa2_newsletter_create", "xwa2_newsletter_subscribed", "xwa2_newsletters_directory_list"}) RecommendedNewslettersResponse response) { 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/RevokeAdminInviteNewsletterResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import it.auties.whatsapp.model.jid.Jid; 6 | import it.auties.whatsapp.util.Json; 7 | 8 | import java.util.Map; 9 | import java.util.Optional; 10 | 11 | public record RevokeAdminInviteNewsletterResponse(@JsonProperty("id") Jid jid) { 12 | @JsonCreator 13 | RevokeAdminInviteNewsletterResponse(Map json) { 14 | this(Jid.of(json.get("id"))); 15 | } 16 | 17 | public static Optional ofJson(String json) { 18 | return Json.readValue(json, JsonData.class) 19 | .data() 20 | .map(JsonResponse::response); 21 | } 22 | 23 | private record JsonData(Optional data) { 24 | 25 | } 26 | 27 | private record JsonResponse( 28 | @JsonProperty("xwa2_newsletter_admin_invite_revoke") RevokeAdminInviteNewsletterResponse response) { 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/SubscribedNewslettersResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import it.auties.whatsapp.model.newsletter.Newsletter; 5 | import it.auties.whatsapp.util.Json; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.NoSuchElementException; 10 | import java.util.Optional; 11 | 12 | public record SubscribedNewslettersResponse(List newsletters) { 13 | @JsonCreator 14 | SubscribedNewslettersResponse(Map> json) { 15 | this(json.values() 16 | .stream() 17 | .findFirst() 18 | .orElseThrow(() -> new NoSuchElementException("Missing newsletters"))); 19 | } 20 | 21 | public static Optional ofJson(String json) { 22 | return Json.readValue(json, JsonResponse.class).data(); 23 | } 24 | 25 | private record JsonResponse(Optional data) { 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/response/UserChosenNameResponse.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.response; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import it.auties.whatsapp.util.Json; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Optional; 9 | 10 | public record UserChosenNameResponse(Optional name) { 11 | 12 | @SuppressWarnings("unchecked") 13 | public static Optional ofJson(String json) { 14 | try { 15 | var parsedJson = Json.readValue(json, new TypeReference>() { 16 | }); 17 | var data = (Map) parsedJson.get("data"); 18 | var updates = (List) data.get("xwa2_users_updates_since"); 19 | var latestUpdate = (Map) updates.getFirst(); 20 | var updatesData = (List) latestUpdate.get("updates"); 21 | var latestUpdateData = (Map) updatesData.getFirst(); 22 | return Optional.of(new UserChosenNameResponse(Optional.ofNullable((String) latestUpdateData.get("text")))); 23 | } catch (Throwable throwable) { 24 | return Optional.empty(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/AutoDownloadSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "AutoDownloadSettings") 8 | public record AutoDownloadSettings( 9 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 10 | boolean downloadImages, 11 | @ProtobufProperty(index = 2, type = ProtobufType.BOOL) 12 | boolean downloadAudio, 13 | @ProtobufProperty(index = 3, type = ProtobufType.BOOL) 14 | boolean downloadVideo, 15 | @ProtobufProperty(index = 4, type = ProtobufType.BOOL) 16 | boolean downloadDocuments 17 | ) implements Setting { 18 | @Override 19 | public int settingVersion() { 20 | return -1; 21 | } 22 | 23 | @Override 24 | public String indexName() { 25 | throw new UnsupportedOperationException("Cannot send setting: no index name"); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/AvatarUserSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "AvatarUserSettings") 8 | public record AvatarUserSettings( 9 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 10 | String facebookId, 11 | @ProtobufProperty(index = 2, type = ProtobufType.STRING) 12 | String password 13 | ) implements Setting { 14 | @Override 15 | public int settingVersion() { 16 | return -1; 17 | } 18 | 19 | @Override 20 | public String indexName() { 21 | throw new UnsupportedOperationException("Cannot send setting: no index name"); 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/EphemeralSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.util.Clock; 7 | 8 | import java.time.ZonedDateTime; 9 | import java.util.Optional; 10 | 11 | @ProtobufMessage(name = "AvatarUserSetting") 12 | public record EphemeralSettings( 13 | @ProtobufProperty(index = 1, type = ProtobufType.SFIXED32) 14 | int duration, 15 | @ProtobufProperty(index = 2, type = ProtobufType.SFIXED64) 16 | long timestampSeconds 17 | ) implements Setting { 18 | /** 19 | * Returns when this setting was toggled 20 | * 21 | * @return an optional 22 | */ 23 | public Optional timestamp() { 24 | return Clock.parseSeconds(timestampSeconds); 25 | } 26 | 27 | @Override 28 | public int settingVersion() { 29 | return -1; 30 | } 31 | 32 | @Override 33 | public String indexName() { 34 | throw new UnsupportedOperationException("Cannot send setting: no index name"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/LocaleSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "LocaleSetting") 8 | public record LocaleSettings( 9 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 10 | String locale 11 | ) implements Setting { 12 | @Override 13 | public int settingVersion() { 14 | return 3; 15 | } 16 | 17 | @Override 18 | public String indexName() { 19 | return "setting_locale"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/PushNameSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncActionValue.PushNameSetting") 8 | public record PushNameSettings( 9 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 10 | String name 11 | ) implements Setting { 12 | @Override 13 | public int settingVersion() { 14 | return 1; 15 | } 16 | 17 | @Override 18 | public String indexName() { 19 | return "setting_pushName"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/SecurityNotificationSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncActionValue.SecurityNotificationSetting") 8 | public record SecurityNotificationSettings( 9 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 10 | boolean showNotification 11 | ) implements Setting { 12 | @Override 13 | public int settingVersion() { 14 | return -1; 15 | } 16 | 17 | @Override 18 | public String indexName() { 19 | throw new UnsupportedOperationException("Cannot send setting: no index name"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/Setting.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | public sealed interface Setting permits AutoDownloadSettings, AvatarUserSettings, EphemeralSettings, LocaleSettings, PushNameSettings, SecurityNotificationSettings, UnarchiveChatsSettings { 4 | int settingVersion(); 5 | String indexName(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/setting/UnarchiveChatsSettings.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.setting; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncActionValue.UnarchiveChatsSetting") 8 | public record UnarchiveChatsSettings( 9 | @ProtobufProperty(index = 1, type = ProtobufType.BOOL) 10 | boolean unarchiveChats 11 | ) implements Setting { 12 | @Override 13 | public int settingVersion() { 14 | return 4; 15 | } 16 | 17 | @Override 18 | public String indexName() { 19 | return "setting_unarchiveChats"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/ClientFinish.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BYTES; 7 | 8 | @ProtobufMessage(name = "HandshakeMessage.ClientFinish") 9 | public record ClientFinish(@ProtobufProperty(index = 1, type = BYTES) byte[] _static, 10 | @ProtobufProperty(index = 2, type = BYTES) byte[] payload) { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/ClientHello.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BYTES; 7 | 8 | @ProtobufMessage(name = "HandshakeMessage.ClientHello") 9 | public record ClientHello(@ProtobufProperty(index = 1, type = BYTES) byte[] ephemeral, 10 | @ProtobufProperty(index = 2, type = BYTES) byte[] _static, 11 | @ProtobufProperty(index = 3, type = BYTES) byte[] payload) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/CompanionRegistrationData.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "ClientPayload.DevicePairingRegistrationData") 8 | public record CompanionRegistrationData(@ProtobufProperty(index = 1, type = ProtobufType.BYTES) byte[] eRegid, 9 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) byte[] eKeytype, 10 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) byte[] eIdent, 11 | @ProtobufProperty(index = 4, type = ProtobufType.BYTES) byte[] eSkeyId, 12 | @ProtobufProperty(index = 5, type = ProtobufType.BYTES) byte[] eSkeyVal, 13 | @ProtobufProperty(index = 6, type = ProtobufType.BYTES) byte[] eSkeySig, 14 | @ProtobufProperty(index = 7, type = ProtobufType.BYTES) byte[] buildHash, 15 | @ProtobufProperty(index = 8, type = ProtobufType.BYTES) byte[] companionProps) { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/DNSSource.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | import it.auties.protobuf.annotation.ProtobufMessage; 6 | import it.auties.protobuf.annotation.ProtobufProperty; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.BOOL; 9 | import static it.auties.protobuf.model.ProtobufType.ENUM; 10 | 11 | @ProtobufMessage(name = "ClientPayload.DNSSource") 12 | public record DNSSource(@ProtobufProperty(index = 15, type = ENUM) ResolutionMethod dnsMethod, 13 | @ProtobufProperty(index = 16, type = BOOL) boolean appCached) { 14 | 15 | @ProtobufEnum(name = "ClientPayload.DNSSource.DNSResolutionMethod") 16 | public enum ResolutionMethod { 17 | SYSTEM(0), 18 | GOOGLE(1), 19 | HARDCODED(2), 20 | OVERRIDE(3), 21 | FALLBACK(4); 22 | 23 | ResolutionMethod(@ProtobufEnumIndex int index) { 24 | this.index = index; 25 | } 26 | 27 | final int index; 28 | 29 | public int index() { 30 | return this.index; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/DeviceIdentity.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "ADVDeviceIdentity") 8 | public record DeviceIdentity(@ProtobufProperty(index = 1, type = ProtobufType.UINT32) 9 | int rawId, 10 | @ProtobufProperty(index = 2, type = ProtobufType.UINT64) 11 | long timestamp, 12 | @ProtobufProperty(index = 3, type = ProtobufType.UINT32) 13 | int keyIndex) { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/HandshakeMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.MESSAGE; 7 | 8 | @ProtobufMessage(name = "HandshakeMessage") 9 | public record HandshakeMessage(@ProtobufProperty(index = 2, type = MESSAGE) ClientHello clientHello, 10 | @ProtobufProperty(index = 3, type = MESSAGE) ServerHello serverHello, 11 | @ProtobufProperty(index = 4, type = MESSAGE) ClientFinish clientFinish) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/KeyIndexList.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | @ProtobufMessage(name = "ADVKeyIndexList") 10 | public record KeyIndexList(@ProtobufProperty(index = 1, type = ProtobufType.UINT32) int rawId, 11 | @ProtobufProperty(index = 2, type = ProtobufType.UINT64) long timestamp, 12 | @ProtobufProperty(index = 3, type = ProtobufType.UINT32) int currentIndex, 13 | @ProtobufProperty(index = 4, type = ProtobufType.UINT32) List validIndexes) { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/NoiseCertificate.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "NoiseCertificate") 8 | public record NoiseCertificate(@ProtobufProperty(index = 1, type = ProtobufType.BYTES) byte[] details, 9 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) byte[] signature) { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/ServerHello.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BYTES; 7 | 8 | @ProtobufMessage(name = "HandshakeMessage.ServerHello") 9 | public record ServerHello(@ProtobufProperty(index = 1, type = BYTES) byte[] ephemeral, 10 | @ProtobufProperty(index = 2, type = BYTES) byte[] staticText, 11 | @ProtobufProperty(index = 3, type = BYTES) byte[] payload) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/SignedDeviceIdentity.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "ADVSignedDeviceIdentity") 8 | public record SignedDeviceIdentity(@ProtobufProperty(index = 1, type = ProtobufType.BYTES) byte[] details, 9 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) byte[] accountSignatureKey, 10 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) byte[] accountSignature, 11 | @ProtobufProperty(index = 4, type = ProtobufType.BYTES) byte[] deviceSignature) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/SignedDeviceIdentityHMAC.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "ADVSignedDeviceIdentityHMAC") 8 | public record SignedDeviceIdentityHMAC(@ProtobufProperty(index = 1, type = ProtobufType.BYTES) byte[] details, 9 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) byte[] hmac) { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/SignedKeyIndexList.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "ADVSignedKeyIndexList") 8 | public record SignedKeyIndexList(@ProtobufProperty(index = 1, type = ProtobufType.BYTES) byte[] details, 9 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) byte[] accountSignature) { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/auth/WebInfo.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.auth; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | import it.auties.protobuf.annotation.ProtobufMessage; 6 | import it.auties.protobuf.annotation.ProtobufProperty; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.*; 9 | 10 | @ProtobufMessage(name = "ClientPayload.WebInfo") 11 | public record WebInfo(@ProtobufProperty(index = 1, type = STRING) String refToken, 12 | @ProtobufProperty(index = 2, type = STRING) String version, 13 | @ProtobufProperty(index = 3, type = MESSAGE) WebPayload webPayload, 14 | @ProtobufProperty(index = 4, type = ENUM) Platform webSubPlatform) { 15 | 16 | @ProtobufEnum(name = "ClientPayload.UserAgent.Platform") 17 | public enum Platform { 18 | WEB_BROWSER(0), 19 | APP_STORE(1), 20 | WIN_STORE(2), 21 | DARWIN(3), 22 | WIN32(4); 23 | 24 | Platform(@ProtobufEnumIndex int index) { 25 | this.index = index; 26 | } 27 | 28 | final int index; 29 | 30 | public int index() { 31 | return this.index; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/message/SignalProtocolMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.message; 2 | 3 | import it.auties.whatsapp.util.Bytes; 4 | import it.auties.whatsapp.util.SignalConstants; 5 | 6 | public abstract sealed class SignalProtocolMessage> permits SenderKeyMessage, SignalDistributionMessage, SignalMessage, SignalPreKeyMessage { 7 | protected byte[] serialized; 8 | private int version; 9 | 10 | public SignalProtocolMessage() { 11 | this.version = SignalConstants.CURRENT_VERSION; 12 | } 13 | 14 | public SignalProtocolMessage(int version, byte[] serialized) { 15 | this.version = version; 16 | this.serialized = serialized; 17 | } 18 | 19 | public int version() { 20 | return version; 21 | } 22 | 23 | @SuppressWarnings("unchecked") 24 | public T setVersion(int version) { 25 | this.version = version; 26 | return (T) this; 27 | } 28 | 29 | public byte serializedVersion() { 30 | return Bytes.versionToBytes(version); 31 | } 32 | 33 | @SuppressWarnings("unchecked") 34 | public T setSerialized(byte[] serialized) { 35 | this.serialized = serialized; 36 | return (T) this; 37 | } 38 | 39 | public abstract byte[] serialized(); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/sender/SenderChainKey.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.sender; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.crypto.Hmac; 7 | 8 | @ProtobufMessage 9 | public record SenderChainKey( 10 | @ProtobufProperty(index = 1, type = ProtobufType.INT32) 11 | int iteration, 12 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 13 | byte[] seed 14 | ) { 15 | private static final byte[] MESSAGE_KEY_SEED = {0x01}; 16 | private static final byte[] CHAIN_KEY_SEED = {0x02}; 17 | 18 | public SenderMessageKey toMessageKey() { 19 | var hmac = Hmac.calculateSha256(MESSAGE_KEY_SEED, seed); 20 | return new SenderMessageKey(iteration, hmac); 21 | } 22 | 23 | public SenderChainKey next() { 24 | var hmac = Hmac.calculateSha256(CHAIN_KEY_SEED, seed); 25 | return new SenderChainKey(iteration + 1, hmac); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/sender/SenderKeyName.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.sender; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import it.auties.protobuf.annotation.ProtobufDeserializer; 6 | import it.auties.protobuf.annotation.ProtobufSerializer; 7 | import it.auties.whatsapp.model.signal.session.SessionAddress; 8 | 9 | public record SenderKeyName(String groupId, SessionAddress sender) { 10 | @JsonCreator 11 | @ProtobufDeserializer 12 | public static SenderKeyName of(String serialized) { 13 | var split = serialized.split("::", 3); 14 | var address = new SessionAddress(split[1], Integer.parseUnsignedInt(split[2])); 15 | return new SenderKeyName(split[0], address); 16 | } 17 | 18 | @JsonValue 19 | @ProtobufSerializer 20 | @Override 21 | public String toString() { 22 | return "%s::%s::%s".formatted(groupId(), sender().name(), sender().id()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/session/SessionAddress.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.session; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import it.auties.protobuf.annotation.ProtobufDeserializer; 6 | import it.auties.protobuf.annotation.ProtobufSerializer; 7 | 8 | import java.util.Objects; 9 | 10 | public record SessionAddress(String name, int id) { 11 | @JsonCreator 12 | @ProtobufDeserializer 13 | public static SessionAddress of(String serialized) { 14 | var split = serialized.split(":", 2); 15 | if (split.length != 2) { 16 | throw new IllegalArgumentException("Malformed address: " + serialized); 17 | } 18 | return new SessionAddress(split[0], Integer.parseInt(split[1])); 19 | } 20 | 21 | @JsonValue 22 | @ProtobufSerializer 23 | @Override 24 | public String toString() { 25 | return "%s:%s".formatted(name(), id()); 26 | } 27 | 28 | @Override 29 | public int hashCode() { 30 | return Objects.hash(name, id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/session/SessionChain.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.session; 2 | 3 | 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | 8 | import java.util.concurrent.ConcurrentHashMap; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | import java.util.concurrent.atomic.AtomicReference; 11 | 12 | @ProtobufMessage 13 | public record SessionChain( 14 | @ProtobufProperty(index = 1, type = ProtobufType.INT32) 15 | AtomicInteger counter, 16 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 17 | AtomicReference key, 18 | @ProtobufProperty(index = 3, type = ProtobufType.MAP, mapKeyType = ProtobufType.INT32, mapValueType = ProtobufType.BYTES) 19 | ConcurrentHashMap messageKeys 20 | ) { 21 | public SessionChain(int counter, byte[] key) { 22 | this(new AtomicInteger(counter), new AtomicReference<>(key), new ConcurrentHashMap<>()); 23 | } 24 | 25 | public boolean hasMessageKey(int counter) { 26 | return messageKeys.containsKey(counter); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/signal/session/SessionPreKey.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.signal.session; 2 | 3 | 4 | import it.auties.protobuf.annotation.ProtobufMessage; 5 | import it.auties.protobuf.annotation.ProtobufProperty; 6 | import it.auties.protobuf.model.ProtobufType; 7 | 8 | @ProtobufMessage 9 | public record SessionPreKey( 10 | @ProtobufProperty(index = 1, type = ProtobufType.INT32) 11 | Integer preKeyId, 12 | @ProtobufProperty(index = 2, type = ProtobufType.BYTES) 13 | byte[] baseKey, 14 | @ProtobufProperty(index = 3, type = ProtobufType.INT32) 15 | int signedKeyId 16 | ) { 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/ActionDataSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.info.MessageIndexInfo; 7 | 8 | import java.nio.charset.StandardCharsets; 9 | 10 | @ProtobufMessage(name = "SyncActionData") 11 | public record ActionDataSync( 12 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 13 | byte[] index, 14 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 15 | ActionValueSync value, 16 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) 17 | byte[] padding, 18 | @ProtobufProperty(index = 4, type = ProtobufType.INT32) 19 | Integer version 20 | ) { 21 | public MessageIndexInfo messageIndex() { 22 | var jsonIndex = new String(index, StandardCharsets.UTF_8); 23 | return MessageIndexInfo.ofJson(jsonIndex); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateFatalExceptionNotification.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import java.util.List; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.INT64; 9 | import static it.auties.protobuf.model.ProtobufType.STRING; 10 | 11 | @ProtobufMessage(name = "Message.AppStateFatalExceptionNotification") 12 | public record AppStateFatalExceptionNotification( 13 | @ProtobufProperty(index = 1, type = STRING) List collectionNames, 14 | @ProtobufProperty(index = 2, type = INT64) Long timestamp) { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateSyncKey.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.MESSAGE; 7 | 8 | @ProtobufMessage(name = "Message.AppStateSyncKey") 9 | public record AppStateSyncKey( 10 | @ProtobufProperty(index = 1, type = MESSAGE) AppStateSyncKeyId keyId, 11 | @ProtobufProperty(index = 2, type = MESSAGE) AppStateSyncKeyData keyData 12 | ) { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateSyncKeyData.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.*; 7 | 8 | @ProtobufMessage(name = "Message.AppStateSyncKeyData") 9 | public record AppStateSyncKeyData(@ProtobufProperty(index = 1, type = BYTES) byte[] keyData, 10 | @ProtobufProperty(index = 2, type = MESSAGE) AppStateSyncKeyFingerprint fingerprint, 11 | @ProtobufProperty(index = 3, type = INT64) Long timestamp) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateSyncKeyFingerprint.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import java.util.List; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.UINT32; 9 | 10 | @ProtobufMessage(name = "Message.AppStateSyncKeyFingerprint") 11 | public record AppStateSyncKeyFingerprint(@ProtobufProperty(index = 1, type = UINT32) Integer rawId, 12 | @ProtobufProperty(index = 2, type = UINT32) Integer currentIndex, 13 | @ProtobufProperty(index = 3, type = UINT32, packed = true) List deviceIndexes) { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateSyncKeyId.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BYTES; 7 | 8 | @ProtobufMessage(name = "Message.AppStateSyncKeyId") 9 | public record AppStateSyncKeyId( 10 | @ProtobufProperty(index = 1, type = BYTES) byte[] keyId 11 | ) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateSyncKeyRequest.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import java.util.List; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.MESSAGE; 9 | 10 | @ProtobufMessage(name = "Message.AppStateSyncKeyRequest") 11 | public record AppStateSyncKeyRequest( 12 | @ProtobufProperty(index = 1, type = MESSAGE) List keyIds) { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/AppStateSyncKeyShare.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import java.util.List; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.MESSAGE; 9 | 10 | @ProtobufMessage(name = "Message.AppStateSyncKeyShare") 11 | public record AppStateSyncKeyShare( 12 | @ProtobufProperty(index = 1, type = MESSAGE) List keys) { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/DeviceListMetadata.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import java.util.List; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.*; 9 | 10 | @ProtobufMessage(name = "DeviceListMetadata") 11 | public record DeviceListMetadata(@ProtobufProperty(index = 1, type = BYTES) byte[] senderKeyHash, 12 | @ProtobufProperty(index = 2, type = UINT64) Long senderTimestamp, 13 | @ProtobufProperty(index = 3, type = UINT32, packed = true) List senderKeyIndexes, 14 | @ProtobufProperty(index = 8, type = BYTES) byte[] recipientKeyHash, 15 | @ProtobufProperty(index = 9, type = UINT64) Long recipientTimestamp, 16 | @ProtobufProperty(index = 10, type = UINT32, packed = true) List recipientKeyIndexes) { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/ExitCode.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.STRING; 7 | import static it.auties.protobuf.model.ProtobufType.UINT64; 8 | 9 | @ProtobufMessage(name = "ExitCode") 10 | public record ExitCode(@ProtobufProperty(index = 1, type = UINT64) long code, 11 | @ProtobufProperty(index = 2, type = STRING) String text) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/HistorySyncConfig.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "DeviceProps.HistorySyncConfig") 8 | public record HistorySyncConfig( 9 | @ProtobufProperty(index = 1, type = ProtobufType.UINT32) 10 | Integer fullSyncDaysLimit, 11 | @ProtobufProperty(index = 2, type = ProtobufType.UINT32) 12 | Integer fullSyncSizeMbLimit, 13 | @ProtobufProperty(index = 3, type = ProtobufType.UINT32) 14 | Integer storageQuotaMb, 15 | @ProtobufProperty(index = 4, type = ProtobufType.BOOL) 16 | Boolean inlineInitialPayloadInE2EeMsg, 17 | @ProtobufProperty(index = 5, type = ProtobufType.UINT32) 18 | Integer recentSyncDaysLimit, 19 | @ProtobufProperty(index = 6, type = ProtobufType.BOOL) 20 | Boolean supportCallLogHistory, 21 | @ProtobufProperty(index = 7, type = ProtobufType.BOOL) 22 | Boolean supportBotUserAgentChatHistory 23 | ) { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/HistorySyncMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | import it.auties.whatsapp.model.info.ChatMessageInfo; 7 | 8 | import java.util.Objects; 9 | 10 | @ProtobufMessage(name = "HistorySyncMsg") 11 | public record HistorySyncMessage( 12 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 13 | ChatMessageInfo messageInfo, 14 | @ProtobufProperty(index = 2, type = ProtobufType.UINT64) 15 | long messageOrderId 16 | ) { 17 | @Override 18 | public boolean equals(Object obj) { 19 | return obj instanceof HistorySyncMessage that && Objects.equals(messageInfo, that.messageInfo()); 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return Objects.hashCode(messageInfo); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/IndexSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncdIndex") 8 | public record IndexSync( 9 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 10 | byte[] blob 11 | ) { 12 | 13 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/InitialSecurityNotificationSettingSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BOOL; 7 | 8 | @ProtobufMessage(name = "Message.InitialSecurityNotificationSettingSync") 9 | public record InitialSecurityNotificationSettingSync( 10 | @ProtobufProperty(index = 1, type = BOOL) boolean securityNotificationEnabled) { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/KeyExpiration.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.INT32; 7 | 8 | @ProtobufMessage(name = "SyncActionValue.KeyExpiration") 9 | public record KeyExpiration( 10 | @ProtobufProperty(index = 1, type = INT32) Integer expiredKeyEpoch) { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/KeyId.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BYTES; 7 | 8 | @ProtobufMessage(name = "KeyId") 9 | public record KeyId(@ProtobufProperty(index = 1, type = BYTES) byte[] id) { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/MutationSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncdMutation") 8 | public record MutationSync( 9 | @ProtobufProperty(index = 1, type = ProtobufType.ENUM) 10 | RecordSync.Operation operation, 11 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 12 | RecordSync record 13 | ) implements Syncable { 14 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/MutationsSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | @ProtobufMessage(name = "SyncdMutations") 10 | public record MutationsSync( 11 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 12 | List mutations 13 | ) { 14 | 15 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/PatchType.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufEnum; 4 | import it.auties.protobuf.annotation.ProtobufEnumIndex; 5 | 6 | import java.util.Arrays; 7 | import java.util.Locale; 8 | import java.util.NoSuchElementException; 9 | 10 | @ProtobufEnum 11 | public enum PatchType { 12 | CRITICAL_BLOCK(0), 13 | CRITICAL_UNBLOCK_LOW(1), 14 | REGULAR_HIGH(2), 15 | REGULAR_LOW(3), 16 | REGULAR(4); 17 | 18 | final int index; 19 | 20 | PatchType(@ProtobufEnumIndex int index) { 21 | this.index = index; 22 | } 23 | 24 | public int index() { 25 | return index; 26 | } 27 | 28 | public static PatchType of(String name) { 29 | return Arrays.stream(values()) 30 | .filter(entry -> entry.toString().equals(name)) 31 | .findAny() 32 | .orElseThrow(() -> new NoSuchElementException("No sync matches %s".formatted(name))); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return name().toLowerCase(Locale.ROOT); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/PhotoChange.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.BYTES; 7 | import static it.auties.protobuf.model.ProtobufType.UINT32; 8 | 9 | @ProtobufMessage(name = "PhotoChange") 10 | public record PhotoChange(@ProtobufProperty(index = 1, type = BYTES) byte[] oldPhoto, 11 | @ProtobufProperty(index = 2, type = BYTES) byte[] newPhoto, 12 | @ProtobufProperty(index = 3, type = UINT32) Integer newPhotoId) { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/PrimaryFeature.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | @ProtobufMessage(name = "SyncActionValue.PrimaryFeature") 10 | public record PrimaryFeature( 11 | @ProtobufProperty(index = 1, type = ProtobufType.STRING) 12 | List flags 13 | ) { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/PushName.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import java.util.Optional; 7 | 8 | import static it.auties.protobuf.model.ProtobufType.STRING; 9 | 10 | @ProtobufMessage(name = "Pushname") 11 | public record PushName(@ProtobufProperty(index = 1, type = STRING) String id, 12 | @ProtobufProperty(index = 2, type = STRING) Optional name) { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/RecentEmojiWeight.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.FLOAT; 7 | import static it.auties.protobuf.model.ProtobufType.STRING; 8 | 9 | @ProtobufMessage(name = "RecentEmojiWeight") 10 | public record RecentEmojiWeight(@ProtobufProperty(index = 1, type = STRING) String emoji, 11 | @ProtobufProperty(index = 2, type = FLOAT) Float weight) { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/ServerErrorReceipt.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | 6 | import static it.auties.protobuf.model.ProtobufType.STRING; 7 | 8 | @ProtobufMessage(name = "ServerErrorReceipt") 9 | public record ServerErrorReceipt( 10 | @ProtobufProperty(index = 1, type = STRING) String stanzaId 11 | ) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/SnapshotSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | import java.util.List; 8 | 9 | @ProtobufMessage(name = "SyncdSnapshot") 10 | public record SnapshotSync( 11 | @ProtobufProperty(index = 1, type = ProtobufType.MESSAGE) 12 | VersionSync version, 13 | @ProtobufProperty(index = 2, type = ProtobufType.MESSAGE) 14 | List records, 15 | @ProtobufProperty(index = 3, type = ProtobufType.BYTES) 16 | byte[] mac, 17 | @ProtobufProperty(index = 4, type = ProtobufType.MESSAGE) 18 | KeyId keyId 19 | ) { 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/SyncActionMessage.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.whatsapp.model.message.model.ChatMessageKey; 6 | 7 | import static it.auties.protobuf.model.ProtobufType.INT64; 8 | import static it.auties.protobuf.model.ProtobufType.MESSAGE; 9 | 10 | @ProtobufMessage(name = "SyncActionMessage") 11 | public record SyncActionMessage(@ProtobufProperty(index = 1, type = MESSAGE) ChatMessageKey key, 12 | @ProtobufProperty(index = 2, type = INT64) Long timestamp) { 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/Syncable.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | public sealed interface Syncable permits RecordSync, MutationSync { 4 | RecordSync.Operation operation(); 5 | 6 | RecordSync record(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/ValueSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncdValue") 8 | public record ValueSync( 9 | @ProtobufProperty(index = 1, type = ProtobufType.BYTES) 10 | byte[] blob 11 | ) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/model/sync/VersionSync.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.model.sync; 2 | 3 | import it.auties.protobuf.annotation.ProtobufMessage; 4 | import it.auties.protobuf.annotation.ProtobufProperty; 5 | import it.auties.protobuf.model.ProtobufType; 6 | 7 | @ProtobufMessage(name = "SyncdVersion") 8 | public record VersionSync( 9 | @ProtobufProperty(index = 1, type = ProtobufType.UINT64) 10 | Long version 11 | ) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/socket/SocketListener.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.socket; 2 | 3 | interface SocketListener { 4 | void onOpen(SocketSession session); 5 | 6 | void onMessage(byte[] message); 7 | 8 | void onClose(); 9 | 10 | void onError(Throwable throwable); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/socket/SocketState.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.socket; 2 | 3 | import it.auties.whatsapp.api.DisconnectReason; 4 | 5 | public enum SocketState { 6 | WAITING, 7 | HANDSHAKE, 8 | CONNECTED, 9 | DISCONNECTED, 10 | RECONNECTING, 11 | LOGGED_OUT, 12 | RESTORE, 13 | BANNED, 14 | PAUSED; 15 | 16 | static SocketState of(DisconnectReason reason) { 17 | return switch (reason) { 18 | case DISCONNECTED -> DISCONNECTED; 19 | case RECONNECTING -> RECONNECTING; 20 | case LOGGED_OUT -> LOGGED_OUT; 21 | case BANNED -> BANNED; 22 | case RESTORE -> RESTORE; 23 | }; 24 | } 25 | 26 | DisconnectReason toReason() { 27 | return switch (this) { 28 | case CONNECTED, RECONNECTING -> DisconnectReason.RECONNECTING; 29 | case WAITING, HANDSHAKE, DISCONNECTED, PAUSED -> DisconnectReason.DISCONNECTED; 30 | case LOGGED_OUT -> DisconnectReason.LOGGED_OUT; 31 | case RESTORE -> DisconnectReason.RESTORE; 32 | case BANNED -> DisconnectReason.BANNED; 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/it/auties/whatsapp/util/SignalConstants.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.util; 2 | 3 | public final class SignalConstants { 4 | public static final int CURRENT_VERSION = 3; 5 | public static final int IV_LENGTH = 16; 6 | public static final int KEY_LENGTH = 32; 7 | public static final int MAC_LENGTH = 8; 8 | public static final int SIGNATURE_LENGTH = 64; 9 | public static final int KEY_TYPE = 5; 10 | public static final byte[] KEY_BUNDLE_TYPE = new byte[]{5}; 11 | public static final int MAX_MESSAGES = 2000; 12 | public static final String SKMSG = "skmsg"; 13 | public static final String PKMSG = "pkmsg"; 14 | public static final String MSG = "msg"; 15 | public static final String UNAVAILABLE = "unavailable"; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/native-image/jni-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"java.lang.Boolean", 4 | "methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }] 5 | }, 6 | { 7 | "name":"java.lang.InternalError", 8 | "methods":[{"name":"","parameterTypes":["java.lang.String"] }] 9 | }, 10 | { 11 | "name":"sun.instrument.InstrumentationImpl", 12 | "methods":[{"name":"","parameterTypes":["long","boolean","boolean","boolean"] }, {"name":"loadClassAndCallAgentmain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"loadClassAndCallPremain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"transform","parameterTypes":["java.lang.Module","java.lang.ClassLoader","java.lang.String","java.lang.Class","java.security.ProtectionDomain","byte[]","boolean"] }] 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/native-image/native-image.properties: -------------------------------------------------------------------------------- 1 | Args = --enable-url-protocols=https,http -Djdk.http.auth.proxying.disabledSchemes= -Djdk.http.auth.tunneling.disabledSchemes= -------------------------------------------------------------------------------- /src/main/resources/META-INF/native-image/predefined-classes-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type":"agent-extracted", 4 | "classes":[ 5 | ] 6 | } 7 | ] 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/native-image/proxy-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] 3 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/native-image/resource-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "includes": [ 4 | { 5 | "pattern": "\\QMETA-INF/services/java.lang.System$LoggerFinder\\E" 6 | }, 7 | { 8 | "pattern": "\\QMETA-INF/services/java.net.spi.InetAddressResolverProvider\\E" 9 | }, 10 | { 11 | "pattern": "\\QMETA-INF/services/java.net.spi.URLStreamHandlerProvider\\E" 12 | }, 13 | { 14 | "pattern": "\\QMETA-INF/services/java.nio.channels.spi.SelectorProvider\\E" 15 | }, 16 | { 17 | "pattern": "\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E" 18 | }, 19 | { 20 | "pattern": "\\QMETA-INF/services/javax.xml.parsers.DocumentBuilderFactory\\E" 21 | }, 22 | { 23 | "pattern": ".*/phonenumbers/data/.*" 24 | }, 25 | { 26 | "pattern": "java.base:\\Qjdk/internal/icu/impl/data/icudt72b/nfkc.nrm\\E" 27 | }, 28 | { 29 | "pattern": "java.base:\\Qjdk/internal/icu/impl/data/icudt72b/uprops.icu\\E" 30 | }, 31 | { 32 | "pattern": "java.base:\\Qsun/net/idn/uidna.spp\\E" 33 | } 34 | ] 35 | }, 36 | "bundles": [] 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/native-image/serialization-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "types":[ 3 | ], 4 | "lambdaCapturingTypes":[ 5 | ], 6 | "proxies":[ 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/javax.annotation.processing.AbstractProcessor: -------------------------------------------------------------------------------- 1 | it.auties.whatsapp.listener.RegisterListenerProcessor -------------------------------------------------------------------------------- /src/test/java/it/auties/whatsapp/util/ConfigUtils.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.util; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.util.Properties; 8 | 9 | public final class ConfigUtils { 10 | private static final String CONFIG_PATH = "/.test/config.properties"; 11 | 12 | public static Properties loadConfiguration() throws IOException { 13 | var config = loadConfigFile(); 14 | return createProperties(config); 15 | } 16 | 17 | private static Path loadConfigFile() throws IOException { 18 | var config = Path.of("./" + CONFIG_PATH).toAbsolutePath(); 19 | if (Files.notExists(config)) { 20 | throw new FileNotFoundException("Before running any unit test please create a config file at %s".formatted(config)); 21 | } 22 | return config; 23 | } 24 | 25 | private static Properties createProperties(Path config) throws IOException { 26 | var props = new Properties(); 27 | props.load(Files.newBufferedReader(config)); 28 | return props; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/it/auties/whatsapp/util/GithubActions.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.util; 2 | 3 | public final class GithubActions { 4 | public static final String CONTACT_NAME = "WHATSAPP_CONTACT"; 5 | public static final String ACCOUNT = "ACCOUNT"; 6 | private static final String GITHUB_ACTIONS = "GITHUB_ACTIONS"; 7 | 8 | public static boolean isActionsEnvironment() { 9 | return Boolean.parseBoolean(System.getenv(GITHUB_ACTIONS)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/it/auties/whatsapp/util/MediaUtils.java: -------------------------------------------------------------------------------- 1 | package it.auties.whatsapp.util; 2 | 3 | import java.io.IOException; 4 | import java.io.UncheckedIOException; 5 | import java.net.URI; 6 | 7 | public class MediaUtils { 8 | public static byte[] readBytes(String url) { 9 | try(var stream = URI.create(url).toURL().openStream()) { 10 | return stream.readAllBytes(); 11 | } catch (IOException exception) { 12 | throw new UncheckedIOException("Cannot download media", exception); 13 | } 14 | } 15 | } --------------------------------------------------------------------------------