Skip to content

Commit

Permalink
More work for API stability
Browse files Browse the repository at this point in the history
  • Loading branch information
Auties00 committed Oct 22, 2023
1 parent 9ff0bb6 commit f8d4b0d
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 29 deletions.
3 changes: 2 additions & 1 deletion src/main/java/it/auties/whatsapp/controller/Store.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import it.auties.whatsapp.model.message.model.ContextualMessage;
import it.auties.whatsapp.model.mobile.PhoneNumber;
import it.auties.whatsapp.model.newsletter.Newsletter;
import it.auties.whatsapp.model.newsletter.NewsletterName;
import it.auties.whatsapp.model.node.Node;
import it.auties.whatsapp.model.privacy.PrivacySettingEntry;
import it.auties.whatsapp.model.privacy.PrivacySettingType;
Expand Down Expand Up @@ -546,7 +547,7 @@ private Stream<Chat> findChatsByNameStream(String name) {
private Stream<Newsletter> findNewslettersByNameStream(String name) {
return name == null ? Stream.empty() : newsletters.values()
.parallelStream()
.filter(chat -> chat.metadata().name().text().equalsIgnoreCase(name));
.filter(newsletter -> name.equalsIgnoreCase(newsletter.metadata().name().map(NewsletterName::text).orElse(null)));
}

/**
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/it/auties/whatsapp/model/newsletter/Newsletter.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

public final class Newsletter implements JidProvider {
private final Jid jid;
private final NewsletterState state;
private final NewsletterMetadata metadata;
private NewsletterState state;
private NewsletterMetadata metadata;
private final NewsletterViewerMetadata viewerMetadata;
private final Messages<NewsletterMessageInfo> messages;

Expand Down Expand Up @@ -84,6 +84,16 @@ public Optional<NewsletterState> state() {
return Optional.ofNullable(state);
}

public Newsletter setState(NewsletterState state) {
this.state = state;
return this;
}

public Newsletter setMetadata(NewsletterMetadata metadata) {
this.metadata = metadata;
return this;
}

public NewsletterMetadata metadata() {
return metadata;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@
import it.auties.whatsapp.util.Clock;

import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;

public record NewsletterMetadata(
NewsletterName name,
NewsletterDescription description,
Optional<NewsletterName> name,
Optional<NewsletterDescription> description,
Optional<NewsletterPicture> picture,
Optional<String> handle,
Optional<NewsletterSettings> settings,
String invite,
Optional<String> invite,
OptionalLong subscribers,
boolean verification,
Optional<Boolean> verification,
OptionalLong creationTimestampSeconds
) {
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
Expand All @@ -35,14 +34,14 @@ public record NewsletterMetadata(
Long creationTimestampSeconds
) {
this(
name,
description,
Optional.ofNullable(name),
Optional.ofNullable(description),
Optional.ofNullable(picture),
Optional.ofNullable(handle),
Optional.ofNullable(settings),
invite,
Optional.ofNullable(invite),
subscribers == null ? OptionalLong.empty() : OptionalLong.of(subscribers),
Objects.equals(verification, "VERIFIED"),
verification == null ? Optional.empty() : Optional.of(verification.equals("VERIFIED")),
creationTimestampSeconds == null ? OptionalLong.empty() : OptionalLong.of(creationTimestampSeconds)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package it.auties.whatsapp.model.newsletter;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import it.auties.whatsapp.util.Clock;

import java.util.Arrays;
import java.util.List;
import java.util.*;

public record NewsletterReactionSettings(Type value, List<String> blockedCodes, OptionalLong enabledTimestampSeconds) {
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public NewsletterReactionSettings(Type value, @JsonProperty("blocked_codes") List<String> blockedCodes, @JsonProperty("enabled_ts_sec") Long enabledTimestampSeconds) {
this(
value,
Objects.requireNonNullElseGet(blockedCodes, ArrayList::new),
Clock.parseTimestamp(enabledTimestampSeconds)
);
}

public record NewsletterReactionSettings(Type value, @JsonProperty("blocked_codes") List<String> blockedCodes,
@JsonProperty("enabled_ts_sec") long enabledTimestampSeconds) {
public enum Type {
UNKNOWN,
ALL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@

public record NewsletterLeaveResponse(@JsonProperty("id") Jid jid) {
public static Optional<NewsletterLeaveResponse> ofJson(String json) {
return Json.readValue(json, JsonResponse.class).data();
return Json.readValue(json, JsonResponse.class)
.data()
.map(JsonData::response);
}

private record JsonResponse(
@JsonProperty("xwa2_notify_newsletter_on_leave") Optional<NewsletterLeaveResponse> data) {
private record JsonResponse(Optional<JsonData> data) {

}

private record JsonData(@JsonProperty("xwa2_notify_newsletter_on_leave") NewsletterLeaveResponse response) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@
public record NewsletterMuteResponse(@JsonProperty("id") Jid jid, @JsonProperty("mute") boolean mute) {
@JsonCreator
NewsletterMuteResponse(Map<String, String> json) {
this(Jid.of(json.get("jid")), Objects.equals(json.get("mute"), "ON"));
this(Jid.of(json.get("id")), Objects.equals(json.get("mute"), "ON"));
}

public static Optional<NewsletterMuteResponse> ofJson(String json) {
return Json.readValue(json, JsonResponse.class).data();
return Json.readValue(json, JsonData.class)
.data()
.map(JsonResponse::response);
}

private record JsonResponse(
@JsonProperty("xwa2_notify_newsletter_on_mute_change") Optional<NewsletterMuteResponse> data) {
private record JsonData(Optional<JsonResponse> data) {

}

private record JsonResponse(@JsonProperty("xwa2_notify_newsletter_on_mute_change") NewsletterMuteResponse response) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package it.auties.whatsapp.model.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import it.auties.whatsapp.model.jid.Jid;
import it.auties.whatsapp.model.newsletter.NewsletterState;
import it.auties.whatsapp.util.Json;

import java.util.Optional;

public record NewsletterStateResponse(@JsonProperty("id") Jid jid, @JsonProperty("is_requestor") boolean isRequestor, NewsletterState state) {
public static Optional<NewsletterStateResponse> ofJson(String json) {
return Json.readValue(json, JsonResponse.class)
.data()
.map(JsonData::response);
}

private record JsonResponse(Optional<JsonData> data) {

}

private record JsonData(@JsonProperty("xwa2_notify_newsletter_on_state_change") NewsletterStateResponse response) {

}
}
18 changes: 16 additions & 2 deletions src/main/java/it/auties/whatsapp/socket/SocketHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,16 +179,30 @@ public void onMessage(byte[] message) {
return;
}

try(var decoder = new BinaryDecoder(AesGcm.decrypt(keys.readCounter(true), message, readKey.get()))) {
var decipheredMessage = decipherMessage(message, readKey.get());
if(decipheredMessage == null) {
return;
}

try(var decoder = new BinaryDecoder(decipheredMessage)) {
var node = decoder.decode();
onNodeReceived(node);
store.resolvePendingRequest(node, false);
streamHandler.digest(node);
} catch (Throwable throwable) {
handleFailure(CRYPTOGRAPHY, throwable);
handleFailure(STREAM, throwable);
}
}

private byte[] decipherMessage(byte[] message, byte[] readKey) {
try {
return AesGcm.decrypt(keys.readCounter(true), message, readKey);
} catch (Throwable throwable) {
return handleFailure(CRYPTOGRAPHY, throwable);
}
}


private void onNodeReceived(Node deciphered) {
callListenersAsync(listener -> {
listener.onNodeReceived(whatsapp, deciphered);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/it/auties/whatsapp/socket/SocketSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,13 @@ public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean
var remaining = length;
while (remaining > 0) {
var inputPartSize = inputPart.remaining();
inputPart.get(result, length - remaining, Math.min(inputPartSize, length));
var readLength = Math.min(inputPartSize, length);
inputPart.get(result, length - remaining, readLength);
if(inputPartSize < remaining) {
inputPart = inputParts.get(++inputPartsCounter);
}

remaining -= inputPartSize;
remaining -= readLength;
}

try {
Expand Down
41 changes: 39 additions & 2 deletions src/main/java/it/auties/whatsapp/socket/StreamHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import it.auties.whatsapp.model.message.model.ChatMessageKeyBuilder;
import it.auties.whatsapp.model.message.model.MessageStatus;
import it.auties.whatsapp.model.mobile.PhoneNumber;
import it.auties.whatsapp.model.newsletter.NewsletterMetadata;
import it.auties.whatsapp.model.node.Attributes;
import it.auties.whatsapp.model.node.Node;
import it.auties.whatsapp.model.privacy.PrivacySettingEntry;
Expand Down Expand Up @@ -414,11 +415,47 @@ private void handleMexNamespace(Node node) {
case "NotificationNewsletterJoin" -> handleNewsletterJoin(update);
case "NotificationNewsletterMuteChange" -> handleNewsletterMute(update);
case "NotificationNewsletterLeave" -> handleNewsletterLeave(update);
case "NotificationNewsletterStateChange", "NotificationNewsletterAdminMetadataUpdate", "NotificationNewsletterUpdate" -> {
}
case "NotificationNewsletterUpdate" -> handleNewsletterMetadataUpdate(update);
case "NotificationNewsletterStateChange" -> handleNewsletterStateUpdate(update);
case "NotificationNewsletterAdminMetadataUpdate" -> {}
}
}

private void handleNewsletterStateUpdate(Node update) {
var updatePayload = update.contentAsString()
.orElseThrow(() -> new NoSuchElementException("Missing state update payload"));
var updateJson = NewsletterStateResponse.ofJson(updatePayload)
.orElseThrow(() -> new NoSuchElementException("Malformed state update payload"));
var newsletter = socketHandler.store()
.findNewsletterByJid(updateJson.jid())
.orElseThrow(() -> new NoSuchElementException("Missing newsletter"));
newsletter.setState(updateJson.state());
}

private void handleNewsletterMetadataUpdate(Node update) {
var updatePayload = update.contentAsString()
.orElseThrow(() -> new NoSuchElementException("Missing update payload"));
var updateJson = NewsletterResponse.ofJson(updatePayload)
.orElseThrow(() -> new NoSuchElementException("Malformed update payload"));
var newsletter = socketHandler.store()
.findNewsletterByJid(updateJson.newsletter().jid())
.orElseThrow(() -> new NoSuchElementException("Missing newsletter"));
var oldMetadata = newsletter.metadata();
var updatedMetadata = updateJson.newsletter().metadata();
var mergedMetadata = new NewsletterMetadata(
updatedMetadata.name().or(oldMetadata::name),
updatedMetadata.description().or(oldMetadata::description),
updatedMetadata.picture().or(oldMetadata::picture),
updatedMetadata.handle().or(oldMetadata::handle),
updatedMetadata.settings().or(oldMetadata::settings),
updatedMetadata.invite().or(oldMetadata::invite),
updatedMetadata.subscribers().isPresent() ? updatedMetadata.subscribers() : oldMetadata.subscribers(),
updatedMetadata.verification().or(oldMetadata::verification),
updatedMetadata.creationTimestampSeconds().isPresent() ? updatedMetadata.creationTimestampSeconds() : oldMetadata.creationTimestampSeconds()
);
newsletter.setMetadata(mergedMetadata);
}

private void handleNewsletterJoin(Node update) {
var joinPayload = update.contentAsString()
.orElseThrow(() -> new NoSuchElementException("Missing join payload"));
Expand Down

0 comments on commit f8d4b0d

Please sign in to comment.