<emptyLine />
</value>
</option>
+ <option name="RECORD_COMPONENTS_WRAP" value="5" />
+ <option name="NEW_LINE_AFTER_LPAREN_IN_RECORD_HEADER" value="true" />
+ <option name="RPAREN_ON_NEW_LINE_IN_RECORD_HEADER" value="true" />
<option name="JD_P_AT_EMPTY_LINES" value="false" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
- <XML>
- <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
- </XML>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+ <option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
<option name="ENUM_CONSTANTS_WRAP" value="2" />
</codeStyleSettings>
<codeStyleSettings language="XML">
dependencies {
api("com.github.turasa:signal-service-java:2.15.3_unofficial_31")
+ api("com.fasterxml.jackson.core", "jackson-databind", "2.13.0")
implementation("com.google.protobuf:protobuf-javalite:3.10.0")
implementation("org.bouncycastle:bcprov-jdk15on:1.69")
implementation("org.slf4j:slf4j-api:1.7.32")
import static org.whispersystems.signalservice.internal.util.Util.isEmpty;
-public class DeviceLinkInfo {
-
- final String deviceIdentifier;
- final ECPublicKey deviceKey;
+public record DeviceLinkInfo(String deviceIdentifier, ECPublicKey deviceKey) {
public static DeviceLinkInfo parseDeviceLinkUri(URI linkUri) throws InvalidKeyException {
final var rawQuery = linkUri.getRawQuery();
return map;
}
- public DeviceLinkInfo(final String deviceIdentifier, final ECPublicKey deviceKey) {
- this.deviceIdentifier = deviceIdentifier;
- this.deviceKey = deviceKey;
- }
-
public URI createDeviceLinkUri() {
final var deviceKeyString = Base64.getEncoder().encodeToString(deviceKey.serialize()).replace("=", "");
try {
package org.asamk.signal.manager;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import java.util.List;
-public class JsonStickerPack {
-
- @JsonProperty
- public String title;
-
- @JsonProperty
- public String author;
-
- @JsonProperty
- public JsonSticker cover;
-
- @JsonProperty
- public List<JsonSticker> stickers;
-
- // For deserialization
- private JsonStickerPack() {
- }
-
- public JsonStickerPack(
- final String title, final String author, final JsonSticker cover, final List<JsonSticker> stickers
- ) {
- this.title = title;
- this.author = author;
- this.cover = cover;
- this.stickers = stickers;
- }
-
- public static class JsonSticker {
-
- @JsonProperty
- public String emoji;
-
- @JsonProperty
- public String file;
-
- @JsonProperty
- public String contentType;
-
- // For deserialization
- private JsonSticker() {
- }
+public record JsonStickerPack(String title, String author, JsonSticker cover, List<JsonSticker> stickers) {
- public JsonSticker(final String emoji, final String file, final String contentType) {
- this.emoji = emoji;
- this.file = file;
- this.contentType = contentType;
- }
- }
+ public record JsonSticker(String emoji, String file, String contentType) {}
}
) throws IOException, NotRegisteredException {
var pathConfig = PathConfig.createDefault(settingsPath);
- if (!SignalAccount.userExists(pathConfig.getDataPath(), number)) {
+ if (!SignalAccount.userExists(pathConfig.dataPath(), number)) {
throw new NotRegisteredException();
}
- var account = SignalAccount.load(pathConfig.getDataPath(), number, true, trustNewIdentity);
+ var account = SignalAccount.load(pathConfig.dataPath(), number, true, trustNewIdentity);
if (!account.isRegistered()) {
throw new NotRegisteredException();
static List<String> getAllLocalNumbers(File settingsPath) {
var pathConfig = PathConfig.createDefault(settingsPath);
- final var dataPath = pathConfig.getDataPath();
+ final var dataPath = pathConfig.dataPath();
final var files = dataPath.listFiles();
if (files == null) {
account.getSignalProtocolStore(),
executor,
sessionLock);
- final var avatarStore = new AvatarStore(pathConfig.getAvatarsPath());
- final var attachmentStore = new AttachmentStore(pathConfig.getAttachmentsPath());
- final var stickerPackStore = new StickerPackStore(pathConfig.getStickerPacksPath());
+ final var avatarStore = new AvatarStore(pathConfig.avatarsPath());
+ final var attachmentStore = new AttachmentStore(pathConfig.attachmentsPath());
+ final var stickerPackStore = new StickerPackStore(pathConfig.stickerPacksPath());
this.attachmentHelper = new AttachmentHelper(dependencies, attachmentStore);
this.pinHelper = new PinHelper(dependencies.getKeyBackupService());
public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException {
var info = DeviceLinkInfo.parseDeviceLinkUri(linkUri);
- addDevice(info.deviceIdentifier, info.deviceKey);
+ addDevice(info.deviceIdentifier(), info.deviceKey());
}
private void addDevice(String deviceIdentifier, ECPublicKey deviceKey) throws IOException, InvalidKeyException {
private void applyMessage(
final SignalServiceDataMessage.Builder messageBuilder, final Message message
) throws AttachmentInvalidException, IOException {
- messageBuilder.withBody(message.getMessageText());
- final var attachments = message.getAttachments();
+ messageBuilder.withBody(message.messageText());
+ final var attachments = message.attachments();
if (attachments != null) {
messageBuilder.withAttachments(attachmentHelper.uploadAttachments(attachments));
}
import java.io.File;
-public class PathConfig {
-
- private final File dataPath;
- private final File attachmentsPath;
- private final File avatarsPath;
- private final File stickerPacksPath;
+public record PathConfig(
+ File dataPath, File attachmentsPath, File avatarsPath, File stickerPacksPath
+) {
public static PathConfig createDefault(final File settingsPath) {
return new PathConfig(new File(settingsPath, "data"),
new File(settingsPath, "avatars"),
new File(settingsPath, "stickers"));
}
-
- private PathConfig(
- final File dataPath, final File attachmentsPath, final File avatarsPath, final File stickerPacksPath
- ) {
- this.dataPath = dataPath;
- this.attachmentsPath = attachmentsPath;
- this.avatarsPath = avatarsPath;
- this.stickerPacksPath = stickerPacksPath;
- }
-
- public File getDataPath() {
- return dataPath;
- }
-
- public File getAttachmentsPath() {
- return attachmentsPath;
- }
-
- public File getAvatarsPath() {
- return avatarsPath;
- }
-
- public File getStickerPacksPath() {
- return stickerPacksPath;
- }
}
logger.info("Received link information from {}, linking in progress ...", number);
- if (SignalAccount.userExists(pathConfig.getDataPath(), number) && !canRelinkExistingAccount(number)) {
- throw new UserAlreadyExists(number, SignalAccount.getFileName(pathConfig.getDataPath(), number));
+ if (SignalAccount.userExists(pathConfig.dataPath(), number) && !canRelinkExistingAccount(number)) {
+ throw new UserAlreadyExists(number, SignalAccount.getFileName(pathConfig.dataPath(), number));
}
var encryptedDeviceName = deviceName == null
SignalAccount account = null;
try {
- account = SignalAccount.createOrUpdateLinkedAccount(pathConfig.getDataPath(),
+ account = SignalAccount.createOrUpdateLinkedAccount(pathConfig.dataPath(),
number,
ret.getUuid(),
password,
private boolean canRelinkExistingAccount(final String number) throws IOException {
final SignalAccount signalAccount;
try {
- signalAccount = SignalAccount.load(pathConfig.getDataPath(), number, false, TrustNewIdentity.ON_FIRST_USE);
+ signalAccount = SignalAccount.load(pathConfig.dataPath(), number, false, TrustNewIdentity.ON_FIRST_USE);
} catch (IOException e) {
logger.debug("Account in use or failed to load.", e);
return false;
var pathConfig = PathConfig.createDefault(settingsPath);
final var serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(serviceEnvironment, userAgent);
- if (!SignalAccount.userExists(pathConfig.getDataPath(), number)) {
+ if (!SignalAccount.userExists(pathConfig.dataPath(), number)) {
var identityKey = KeyUtils.generateIdentityKeyPair();
var registrationId = KeyHelper.generateRegistrationId(false);
var profileKey = KeyUtils.createProfileKey();
- var account = SignalAccount.create(pathConfig.getDataPath(),
+ var account = SignalAccount.create(pathConfig.dataPath(),
number,
identityKey,
registrationId,
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent);
}
- var account = SignalAccount.load(pathConfig.getDataPath(), number, true, TrustNewIdentity.ON_FIRST_USE);
+ var account = SignalAccount.load(pathConfig.dataPath(), number, true, TrustNewIdentity.ON_FIRST_USE);
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent);
}
package org.asamk.signal.manager.api;
-public class Device {
-
- private final long id;
- private final String name;
- private final long created;
- private final long lastSeen;
- private final boolean thisDevice;
-
- public Device(long id, String name, long created, long lastSeen, final boolean thisDevice) {
- this.id = id;
- this.name = name;
- this.created = created;
- this.lastSeen = lastSeen;
- this.thisDevice = thisDevice;
- }
-
- public long getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- public long getCreated() {
- return created;
- }
-
- public long getLastSeen() {
- return lastSeen;
- }
-
- public boolean isThisDevice() {
- return thisDevice;
- }
-}
+public record Device(long id, String name, long created, long lastSeen, boolean isThisDevice) {}
import java.util.Set;
-public class Group {
-
- private final GroupId groupId;
- private final String title;
- private final String description;
- private final GroupInviteLinkUrl groupInviteLinkUrl;
- private final Set<RecipientAddress> members;
- private final Set<RecipientAddress> pendingMembers;
- private final Set<RecipientAddress> requestingMembers;
- private final Set<RecipientAddress> adminMembers;
- private final boolean isBlocked;
- private final int messageExpirationTimer;
-
- private final GroupPermission permissionAddMember;
- private final GroupPermission permissionEditDetails;
- private final GroupPermission permissionSendMessage;
- private final boolean isMember;
- private final boolean isAdmin;
-
- public Group(
- final GroupId groupId,
- final String title,
- final String description,
- final GroupInviteLinkUrl groupInviteLinkUrl,
- final Set<RecipientAddress> members,
- final Set<RecipientAddress> pendingMembers,
- final Set<RecipientAddress> requestingMembers,
- final Set<RecipientAddress> adminMembers,
- final boolean isBlocked,
- final int messageExpirationTimer,
- final GroupPermission permissionAddMember,
- final GroupPermission permissionEditDetails,
- final GroupPermission permissionSendMessage,
- final boolean isMember,
- final boolean isAdmin
- ) {
- this.groupId = groupId;
- this.title = title;
- this.description = description;
- this.groupInviteLinkUrl = groupInviteLinkUrl;
- this.members = members;
- this.pendingMembers = pendingMembers;
- this.requestingMembers = requestingMembers;
- this.adminMembers = adminMembers;
- this.isBlocked = isBlocked;
- this.messageExpirationTimer = messageExpirationTimer;
- this.permissionAddMember = permissionAddMember;
- this.permissionEditDetails = permissionEditDetails;
- this.permissionSendMessage = permissionSendMessage;
- this.isMember = isMember;
- this.isAdmin = isAdmin;
- }
-
- public GroupId getGroupId() {
- return groupId;
- }
-
- public String getTitle() {
- return title;
- }
-
- public String getDescription() {
- return description;
- }
-
- public GroupInviteLinkUrl getGroupInviteLinkUrl() {
- return groupInviteLinkUrl;
- }
-
- public Set<RecipientAddress> getMembers() {
- return members;
- }
-
- public Set<RecipientAddress> getPendingMembers() {
- return pendingMembers;
- }
-
- public Set<RecipientAddress> getRequestingMembers() {
- return requestingMembers;
- }
-
- public Set<RecipientAddress> getAdminMembers() {
- return adminMembers;
- }
-
- public boolean isBlocked() {
- return isBlocked;
- }
-
- public int getMessageExpirationTimer() {
- return messageExpirationTimer;
- }
-
- public GroupPermission getPermissionAddMember() {
- return permissionAddMember;
- }
-
- public GroupPermission getPermissionEditDetails() {
- return permissionEditDetails;
- }
-
- public GroupPermission getPermissionSendMessage() {
- return permissionSendMessage;
- }
-
- public boolean isMember() {
- return isMember;
- }
-
- public boolean isAdmin() {
- return isAdmin;
- }
-}
+public record Group(
+ GroupId groupId,
+ String title,
+ String description,
+ GroupInviteLinkUrl groupInviteLinkUrl,
+ Set<RecipientAddress> members,
+ Set<RecipientAddress> pendingMembers,
+ Set<RecipientAddress> requestingMembers,
+ Set<RecipientAddress> adminMembers,
+ boolean isBlocked,
+ int messageExpirationTimer,
+ GroupPermission permissionAddMember,
+ GroupPermission permissionEditDetails,
+ GroupPermission permissionSendMessage,
+ boolean isMember,
+ boolean isAdmin
+) {}
import java.util.Date;
-public class Identity {
-
- private final RecipientAddress recipient;
- private final IdentityKey identityKey;
- private final String safetyNumber;
- private final byte[] scannableSafetyNumber;
- private final TrustLevel trustLevel;
- private final Date dateAdded;
-
- public Identity(
- final RecipientAddress recipient,
- final IdentityKey identityKey,
- final String safetyNumber,
- final byte[] scannableSafetyNumber,
- final TrustLevel trustLevel,
- final Date dateAdded
- ) {
- this.recipient = recipient;
- this.identityKey = identityKey;
- this.safetyNumber = safetyNumber;
- this.scannableSafetyNumber = scannableSafetyNumber;
- this.trustLevel = trustLevel;
- this.dateAdded = dateAdded;
- }
-
- public RecipientAddress getRecipient() {
- return recipient;
- }
-
- public IdentityKey getIdentityKey() {
- return this.identityKey;
- }
-
- public TrustLevel getTrustLevel() {
- return this.trustLevel;
- }
-
- boolean isTrusted() {
- return trustLevel == TrustLevel.TRUSTED_UNVERIFIED || trustLevel == TrustLevel.TRUSTED_VERIFIED;
- }
-
- public Date getDateAdded() {
- return this.dateAdded;
- }
+public record Identity(
+ RecipientAddress recipient,
+ IdentityKey identityKey,
+ String safetyNumber,
+ byte[] scannableSafetyNumber,
+ TrustLevel trustLevel,
+ Date dateAdded
+) {
public byte[] getFingerprint() {
return identityKey.getPublicKey().serialize();
}
-
- public String getSafetyNumber() {
- return safetyNumber;
- }
-
- public byte[] getScannableSafetyNumber() {
- return scannableSafetyNumber;
- }
}
import java.util.List;
-public class Message {
-
- private final String messageText;
- private final List<String> attachments;
-
- public Message(final String messageText, final List<String> attachments) {
- this.messageText = messageText;
- this.attachments = attachments;
- }
-
- public String getMessageText() {
- return messageText;
- }
-
- public List<String> getAttachments() {
- return attachments;
- }
-}
+public record Message(String messageText, List<String> attachments) {}
import java.util.List;
-public class SendGroupMessageResults {
-
- private final long timestamp;
- private final List<SendMessageResult> results;
-
- public SendGroupMessageResults(
- final long timestamp, final List<SendMessageResult> results
- ) {
- this.timestamp = timestamp;
- this.results = results;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
- public List<SendMessageResult> getResults() {
- return results;
- }
-}
+public record SendGroupMessageResults(long timestamp, List<SendMessageResult> results) {}
import java.util.List;
import java.util.Map;
-public class SendMessageResults {
-
- private final long timestamp;
- private final Map<RecipientIdentifier, List<SendMessageResult>> results;
-
- public SendMessageResults(
- final long timestamp, final Map<RecipientIdentifier, List<SendMessageResult>> results
- ) {
- this.timestamp = timestamp;
- this.results = results;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
- public Map<RecipientIdentifier, List<SendMessageResult>> getResults() {
- return results;
- }
-}
+public record SendMessageResults(long timestamp, Map<RecipientIdentifier, List<SendMessageResult>> results) {}
return new Storage(readReceipts, unidentifiedDeliveryIndicators, typingIndicators, linkPreviews);
}
- public static final class Storage {
-
- public Boolean readReceipts;
- public Boolean unidentifiedDeliveryIndicators;
- public Boolean typingIndicators;
- public Boolean linkPreviews;
-
- // For deserialization
- private Storage() {
- }
-
- public Storage(
- final Boolean readReceipts,
- final Boolean unidentifiedDeliveryIndicators,
- final Boolean typingIndicators,
- final Boolean linkPreviews
- ) {
- this.readReceipts = readReceipts;
- this.unidentifiedDeliveryIndicators = unidentifiedDeliveryIndicators;
- this.typingIndicators = typingIndicators;
- this.linkPreviews = linkPreviews;
- }
- }
+ public record Storage(
+ Boolean readReceipts, Boolean unidentifiedDeliveryIndicators, Boolean typingIndicators, Boolean linkPreviews
+ ) {}
public interface Saver {
g1.blocked,
g1.archived,
g1.members.stream()
- .map(m -> new Storage.GroupV1.Member(m.getId(), null, null))
+ .map(m -> new Storage.GroupV1.Member(m.id(), null, null))
.collect(Collectors.toList()));
}
}).collect(Collectors.toList()));
}
- public static class Storage {
+ public record Storage(@JsonDeserialize(using = GroupsDeserializer.class) List<Object> groups) {
- @JsonDeserialize(using = GroupsDeserializer.class)
- public List<Storage.Group> groups;
+ private record GroupV1(
+ String groupId,
+ String expectedV2Id,
+ String name,
+ String color,
+ int messageExpirationTime,
+ boolean blocked,
+ boolean archived,
+ @JsonDeserialize(using = MembersDeserializer.class) @JsonSerialize(using = MembersSerializer.class) List<Member> members
+ ) {
- // For deserialization
- public Storage() {
- }
-
- public Storage(final List<Storage.Group> groups) {
- this.groups = groups;
- }
-
- private abstract static class Group {
-
- }
-
- private static class GroupV1 extends Group {
-
- public String groupId;
- public String expectedV2Id;
- public String name;
- public String color;
- public int messageExpirationTime;
- public boolean blocked;
- public boolean archived;
-
- @JsonDeserialize(using = MembersDeserializer.class)
- @JsonSerialize(using = MembersSerializer.class)
- public List<Member> members;
-
- // For deserialization
- public GroupV1() {
- }
-
- public GroupV1(
- final String groupId,
- final String expectedV2Id,
- final String name,
- final String color,
- final int messageExpirationTime,
- final boolean blocked,
- final boolean archived,
- final List<Member> members
- ) {
- this.groupId = groupId;
- this.expectedV2Id = expectedV2Id;
- this.name = name;
- this.color = color;
- this.messageExpirationTime = messageExpirationTime;
- this.blocked = blocked;
- this.archived = archived;
- this.members = members;
- }
-
- private static final class Member {
-
- public Long recipientId;
-
- public String uuid;
-
- public String number;
+ private record Member(Long recipientId, String uuid, String number) {}
- Member(Long recipientId, final String uuid, final String number) {
- this.recipientId = recipientId;
- this.uuid = uuid;
- this.number = number;
- }
- }
-
- private static final class JsonRecipientAddress {
-
- public String uuid;
-
- public String number;
-
- // For deserialization
- public JsonRecipientAddress() {
- }
-
- JsonRecipientAddress(final String uuid, final String number) {
- this.uuid = uuid;
- this.number = number;
- }
- }
+ private record JsonRecipientAddress(String uuid, String number) {}
private static class MembersSerializer extends JsonSerializer<List<Member>> {
public void serialize(
final List<Member> value, final JsonGenerator jgen, final SerializerProvider provider
) throws IOException {
- jgen.writeStartArray(value.size());
+ jgen.writeStartArray(null, value.size());
for (var address : value) {
if (address.recipientId != null) {
jgen.writeNumber(address.recipientId);
}
}
- private static class GroupV2 extends Group {
-
- public String groupId;
- public String masterKey;
- public boolean blocked;
- public boolean permissionDenied;
-
- // For deserialization
- private GroupV2() {
- }
-
- public GroupV2(
- final String groupId, final String masterKey, final boolean blocked, final boolean permissionDenied
- ) {
- this.groupId = groupId;
- this.masterKey = masterKey;
- this.blocked = blocked;
- this.permissionDenied = permissionDenied;
- }
- }
-
+ private record GroupV2(String groupId, String masterKey, boolean blocked, boolean permissionDenied) {}
}
- private static class GroupsDeserializer extends JsonDeserializer<List<Storage.Group>> {
+ private static class GroupsDeserializer extends JsonDeserializer<List<Object>> {
@Override
- public List<Storage.Group> deserialize(
+ public List<Object> deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext
) throws IOException {
- var groups = new ArrayList<Storage.Group>();
+ var groups = new ArrayList<>();
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
for (var n : node) {
- Storage.Group g;
+ Object g;
if (n.hasNonNull("masterKey")) {
// a v2 group
g = jsonParser.getCodec().treeToValue(n, Storage.GroupV2.class);
} catch (IOException e) {
throw new AssertionError("Failed to create identities path", e);
}
- return new File(identitiesPath, String.valueOf(recipientId.getId()));
+ return new File(identitiesPath, String.valueOf(recipientId.id()));
}
private IdentityInfo loadIdentityLocked(final RecipientId recipientId) {
try (var inputStream = new FileInputStream(file)) {
var storage = objectMapper.readValue(inputStream, IdentityStorage.class);
- var id = new IdentityKey(Base64.getDecoder().decode(storage.getIdentityKey()));
- var trustLevel = TrustLevel.fromInt(storage.getTrustLevel());
- var added = new Date(storage.getAddedTimestamp());
+ var id = new IdentityKey(Base64.getDecoder().decode(storage.identityKey()));
+ var trustLevel = TrustLevel.fromInt(storage.trustLevel());
+ var added = new Date(storage.addedTimestamp());
final var identityInfo = new IdentityInfo(recipientId, id, trustLevel, added);
cachedIdentities.put(recipientId, identityInfo);
}
}
- private static final class IdentityStorage {
-
- private String identityKey;
- private int trustLevel;
- private long addedTimestamp;
-
- // For deserialization
- private IdentityStorage() {
- }
-
- private IdentityStorage(final String identityKey, final int trustLevel, final long addedTimestamp) {
- this.identityKey = identityKey;
- this.trustLevel = trustLevel;
- this.addedTimestamp = addedTimestamp;
- }
-
- public String getIdentityKey() {
- return identityKey;
- }
-
- public int getTrustLevel() {
- return trustLevel;
- }
-
- public long getAddedTimestamp() {
- return addedTimestamp;
- }
- }
+ private record IdentityStorage(String identityKey, int trustLevel, long addedTimestamp) {}
}
return messageCachePath;
}
- var sender = String.valueOf(recipientId.getId());
+ var sender = String.valueOf(recipientId.id());
return new File(messageCachePath, sender.replace("/", "_"));
}
package org.asamk.signal.manager.storage.recipients;
-public class RecipientId {
-
- private final long id;
-
- RecipientId(final long id) {
- this.id = id;
- }
+public record RecipientId(long id) {
public static RecipientId of(long id) {
return new RecipientId(id);
}
-
- public long getId() {
- return id;
- }
-
- @Override
- public String toString() {
- return "RecipientId{" + "id=" + id + '}';
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final RecipientId that = (RecipientId) o;
-
- return id == that.id;
- }
-
- @Override
- public int hashCode() {
- return (int) (id ^ (id >>> 32));
- }
}
.stream()
.map(Enum::name)
.collect(Collectors.toSet()));
- return new Storage.Recipient(pair.getKey().getId(),
+ return new Storage.Recipient(pair.getKey().id(),
recipient.getAddress().getNumber().orElse(null),
recipient.getAddress().getUuid().map(UUID::toString).orElse(null),
recipient.getProfileKey() == null
}
}
- private static class Storage {
-
- public List<Recipient> recipients;
-
- public long lastId;
-
- // For deserialization
- private Storage() {
- }
-
- public Storage(final List<Recipient> recipients, final long lastId) {
- this.recipients = recipients;
- this.lastId = lastId;
- }
-
- private static class Recipient {
-
- public long id;
- public String number;
- public String uuid;
- public String profileKey;
- public String profileKeyCredential;
- public Contact contact;
- public Profile profile;
-
- // For deserialization
- private Recipient() {
- }
-
- public Recipient(
- final long id,
- final String number,
- final String uuid,
- final String profileKey,
- final String profileKeyCredential,
- final Contact contact,
- final Profile profile
- ) {
- this.id = id;
- this.number = number;
- this.uuid = uuid;
- this.profileKey = profileKey;
- this.profileKeyCredential = profileKeyCredential;
- this.contact = contact;
- this.profile = profile;
- }
-
- private static class Contact {
-
- public String name;
- public String color;
- public int messageExpirationTime;
- public boolean blocked;
- public boolean archived;
-
- // For deserialization
- public Contact() {
- }
-
- public Contact(
- final String name,
- final String color,
- final int messageExpirationTime,
- final boolean blocked,
- final boolean archived
- ) {
- this.name = name;
- this.color = color;
- this.messageExpirationTime = messageExpirationTime;
- this.blocked = blocked;
- this.archived = archived;
- }
- }
-
- private static class Profile {
-
- public long lastUpdateTimestamp;
- public String givenName;
- public String familyName;
- public String about;
- public String aboutEmoji;
- public String avatarUrlPath;
- public String unidentifiedAccessMode;
- public Set<String> capabilities;
-
- // For deserialization
- private Profile() {
- }
-
- public Profile(
- final long lastUpdateTimestamp,
- final String givenName,
- final String familyName,
- final String about,
- final String aboutEmoji,
- final String avatarUrlPath,
- final String unidentifiedAccessMode,
- final Set<String> capabilities
- ) {
- this.lastUpdateTimestamp = lastUpdateTimestamp;
- this.givenName = givenName;
- this.familyName = familyName;
- this.about = about;
- this.aboutEmoji = aboutEmoji;
- this.avatarUrlPath = avatarUrlPath;
- this.unidentifiedAccessMode = unidentifiedAccessMode;
- this.capabilities = capabilities;
- }
- }
+ private record Storage(List<Recipient> recipients, long lastId) {
+
+ private record Recipient(
+ long id,
+ String number,
+ String uuid,
+ String profileKey,
+ String profileKeyCredential,
+ Storage.Recipient.Contact contact,
+ Storage.Recipient.Profile profile
+ ) {
+
+ private record Contact(
+ String name, String color, int messageExpirationTime, boolean blocked, boolean archived
+ ) {}
+
+ private record Profile(
+ long lastUpdateTimestamp,
+ String givenName,
+ String familyName,
+ String about,
+ String aboutEmoji,
+ String avatarUrlPath,
+ String unidentifiedAccessMode,
+ Set<String> capabilities
+ ) {}
}
}
continue;
}
- final var newKey = new Key(recipientId, key.getDeviceId(), key.distributionId);
+ final var newKey = new Key(recipientId, key.deviceId(), key.distributionId);
final var senderKeyRecord = loadSenderKeyLocked(newKey);
if (senderKeyRecord != null) {
continue;
}
private List<Key> getKeysLocked(RecipientId recipientId) {
- final var files = senderKeysPath.listFiles((_file, s) -> s.startsWith(recipientId.getId() + "_"));
+ final var files = senderKeysPath.listFiles((_file, s) -> s.startsWith(recipientId.id() + "_"));
if (files == null) {
return List.of();
}
throw new AssertionError("Failed to create sender keys path", e);
}
return new File(senderKeysPath,
- key.getRecipientId().getId() + "_" + key.getDeviceId() + "_" + key.distributionId.toString());
+ key.recipientId().id() + "_" + key.deviceId() + "_" + key.distributionId.toString());
}
private SenderKeyRecord loadSenderKeyLocked(final Key key) {
}
}
- private static final class Key {
+ private record Key(RecipientId recipientId, int deviceId, UUID distributionId) {
- private final RecipientId recipientId;
- private final int deviceId;
- private final UUID distributionId;
-
- public Key(
- final RecipientId recipientId, final int deviceId, final UUID distributionId
- ) {
- this.recipientId = recipientId;
- this.deviceId = deviceId;
- this.distributionId = distributionId;
- }
-
- public RecipientId getRecipientId() {
- return recipientId;
- }
-
- public int getDeviceId() {
- return deviceId;
- }
-
- public UUID getDistributionId() {
- return distributionId;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final Key key = (Key) o;
-
- if (deviceId != key.deviceId) return false;
- if (!recipientId.equals(key.recipientId)) return false;
- return distributionId.equals(key.distributionId);
- }
-
- @Override
- public int hashCode() {
- int result = recipientId.hashCode();
- result = 31 * result + deviceId;
- result = 31 * result + distributionId.hashCode();
- return result;
- }
}
}
synchronized (sharedSenderKeys) {
return sharedSenderKeys.get(distributionId)
.stream()
- .map(k -> new SignalProtocolAddress(addressResolver.resolveRecipientAddress(k.getRecipientId())
- .getIdentifier(), k.getDeviceId()))
+ .map(k -> new SignalProtocolAddress(addressResolver.resolveRecipientAddress(k.recipientId())
+ .getIdentifier(), k.deviceId()))
.collect(Collectors.toSet());
}
}
sharedSenderKeys.put(distributionId, new HashSet<>(entries) {
{
- entries.removeIf(e -> e.getRecipientId().equals(recipientId));
+ removeIf(e -> e.recipientId().equals(recipientId));
}
});
}
entries.stream()
.map(e -> e.recipientId.equals(toBeMergedRecipientId) ? new SenderKeySharedEntry(
recipientId,
- e.getDeviceId()) : e)
+ e.deviceId()) : e)
.collect(Collectors.toSet()));
}
saveLocked();
var storage = new Storage(sharedSenderKeys.entrySet().stream().flatMap(pair -> {
final var sharedWith = pair.getValue();
return sharedWith.stream()
- .map(entry -> new Storage.SharedSenderKey(entry.getRecipientId().getId(),
- entry.getDeviceId(),
+ .map(entry -> new Storage.SharedSenderKey(entry.recipientId().id(),
+ entry.deviceId(),
pair.getKey().asUuid().toString()));
}).collect(Collectors.toList()));
}
}
- private static class Storage {
+ private record Storage(List<SharedSenderKey> sharedSenderKeys) {
- public List<SharedSenderKey> sharedSenderKeys;
-
- // For deserialization
- private Storage() {
- }
-
- public Storage(final List<SharedSenderKey> sharedSenderKeys) {
- this.sharedSenderKeys = sharedSenderKeys;
- }
-
- private static class SharedSenderKey {
-
- public long recipientId;
- public int deviceId;
- public String distributionId;
-
- // For deserialization
- private SharedSenderKey() {
- }
-
- public SharedSenderKey(final long recipientId, final int deviceId, final String distributionId) {
- this.recipientId = recipientId;
- this.deviceId = deviceId;
- this.distributionId = distributionId;
- }
- }
+ private record SharedSenderKey(long recipientId, int deviceId, String distributionId) {}
}
- private static final class SenderKeySharedEntry {
-
- private final RecipientId recipientId;
- private final int deviceId;
-
- public SenderKeySharedEntry(
- final RecipientId recipientId, final int deviceId
- ) {
- this.recipientId = recipientId;
- this.deviceId = deviceId;
- }
-
- public RecipientId getRecipientId() {
- return recipientId;
- }
-
- public int getDeviceId() {
- return deviceId;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final SenderKeySharedEntry that = (SenderKeySharedEntry) o;
-
- if (deviceId != that.deviceId) return false;
- return recipientId.equals(that.recipientId);
- }
-
- @Override
- public int hashCode() {
- int result = recipientId.hashCode();
- result = 31 * result + deviceId;
- return result;
- }
- }
+ private record SenderKeySharedEntry(RecipientId recipientId, int deviceId) {}
}
synchronized (cachedSessions) {
return getKeysLocked(recipientId).stream()
// get all sessions for recipient except main device session
- .filter(key -> key.getDeviceId() != 1 && key.getRecipientId().equals(recipientId))
- .map(Key::getDeviceId)
+ .filter(key -> key.deviceId() != 1 && key.recipientId().equals(recipientId))
+ .map(Key::deviceId)
.collect(Collectors.toList());
}
}
.stream()
.flatMap(recipientId -> getKeysLocked(recipientId).stream())
.filter(key -> isActive(this.loadSessionLocked(key)))
- .map(key -> new SignalProtocolAddress(recipientIdToNameMap.get(key.recipientId), key.getDeviceId()))
+ .map(key -> new SignalProtocolAddress(recipientIdToNameMap.get(key.recipientId), key.deviceId()))
.collect(Collectors.toSet());
}
}
if (session == null) {
continue;
}
- final var newKey = new Key(recipientId, key.getDeviceId());
+ final var newKey = new Key(recipientId, key.deviceId());
storeSessionLocked(newKey, session);
}
}
}
private List<Key> getKeysLocked(RecipientId recipientId) {
- final var files = sessionsPath.listFiles((_file, s) -> s.startsWith(recipientId.getId() + "_"));
+ final var files = sessionsPath.listFiles((_file, s) -> s.startsWith(recipientId.id() + "_"));
if (files == null) {
return List.of();
}
} catch (IOException e) {
throw new AssertionError("Failed to create sessions path", e);
}
- return new File(sessionsPath, key.getRecipientId().getId() + "_" + key.getDeviceId());
+ return new File(sessionsPath, key.recipientId().id() + "_" + key.deviceId());
}
private SessionRecord loadSessionLocked(final Key key) {
&& record.getSessionVersion() == CiphertextMessage.CURRENT_VERSION;
}
- private static final class Key {
-
- private final RecipientId recipientId;
- private final int deviceId;
-
- public Key(final RecipientId recipientId, final int deviceId) {
- this.recipientId = recipientId;
- this.deviceId = deviceId;
- }
-
- public RecipientId getRecipientId() {
- return recipientId;
- }
-
- public int getDeviceId() {
- return deviceId;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final var key = (Key) o;
-
- if (deviceId != key.deviceId) return false;
- return recipientId.equals(key.recipientId);
- }
-
- @Override
- public int hashCode() {
- int result = recipientId.hashCode();
- result = 31 * result + deviceId;
- return result;
- }
- }
+ private record Key(RecipientId recipientId, int deviceId) {}
}
.collect(Collectors.toList()));
}
- public static class Storage {
+ public record Storage(List<Storage.Sticker> stickers) {
- public List<Storage.Sticker> stickers;
+ private record Sticker(String packId, String packKey, boolean installed) {
- // For deserialization
- private Storage() {
- }
-
- public Storage(final List<Sticker> stickers) {
- this.stickers = stickers;
- }
-
- private static class Sticker {
-
- public String packId;
- public String packKey;
- public boolean installed;
-
- // For deserialization
- private Sticker() {
- }
-
- public Sticker(final String packId, final String packKey, final boolean installed) {
- this.packId = packId;
- this.packKey = packKey;
- this.installed = installed;
- }
}
}
var pack = parseStickerPack(rootPath, zip);
- if (pack.stickers == null) {
+ if (pack.stickers() == null) {
throw new StickerPackInvalidException("Must set a 'stickers' field.");
}
- if (pack.stickers.isEmpty()) {
+ if (pack.stickers().isEmpty()) {
throw new StickerPackInvalidException("Must include stickers.");
}
- var stickers = new ArrayList<SignalServiceStickerManifestUpload.StickerInfo>(pack.stickers.size());
- for (var sticker : pack.stickers) {
- if (sticker.file == null) {
+ var stickers = new ArrayList<SignalServiceStickerManifestUpload.StickerInfo>(pack.stickers().size());
+ for (var sticker : pack.stickers()) {
+ if (sticker.file() == null) {
throw new StickerPackInvalidException("Must set a 'file' field on each sticker.");
}
Pair<InputStream, Long> data;
try {
- data = getInputStreamAndLength(rootPath, zip, sticker.file);
+ data = getInputStreamAndLength(rootPath, zip, sticker.file());
} catch (IOException ignored) {
- throw new StickerPackInvalidException("Could not find find " + sticker.file);
+ throw new StickerPackInvalidException("Could not find find " + sticker.file());
}
- var contentType = sticker.contentType != null && !sticker.contentType.isEmpty()
- ? sticker.contentType
- : getContentType(rootPath, zip, sticker.file);
+ var contentType = sticker.contentType() != null && !sticker.contentType().isEmpty()
+ ? sticker.contentType()
+ : getContentType(rootPath, zip, sticker.file());
var stickerInfo = new SignalServiceStickerManifestUpload.StickerInfo(data.first(),
data.second(),
- Optional.fromNullable(sticker.emoji).or(""),
+ Optional.fromNullable(sticker.emoji()).or(""),
contentType);
stickers.add(stickerInfo);
}
SignalServiceStickerManifestUpload.StickerInfo cover = null;
- if (pack.cover != null) {
- if (pack.cover.file == null) {
+ if (pack.cover() != null) {
+ if (pack.cover().file() == null) {
throw new StickerPackInvalidException("Must set a 'file' field on the cover.");
}
Pair<InputStream, Long> data;
try {
- data = getInputStreamAndLength(rootPath, zip, pack.cover.file);
+ data = getInputStreamAndLength(rootPath, zip, pack.cover().file());
} catch (IOException ignored) {
- throw new StickerPackInvalidException("Could not find find " + pack.cover.file);
+ throw new StickerPackInvalidException("Could not find find " + pack.cover().file());
}
- var contentType = pack.cover.contentType != null && !pack.cover.contentType.isEmpty()
- ? pack.cover.contentType
- : getContentType(rootPath, zip, pack.cover.file);
+ var contentType = pack.cover().contentType() != null && !pack.cover().contentType().isEmpty() ? pack.cover()
+ .contentType() : getContentType(rootPath, zip, pack.cover().file());
cover = new SignalServiceStickerManifestUpload.StickerInfo(data.first(),
data.second(),
- Optional.fromNullable(pack.cover.emoji).or(""),
+ Optional.fromNullable(pack.cover().emoji()).or(""),
contentType);
}
- return new SignalServiceStickerManifestUpload(pack.title, pack.author, cover, stickers);
+ return new SignalServiceStickerManifestUpload(pack.title(), pack.author(), cover, stickers);
}
private static JsonStickerPack parseStickerPack(String rootPath, ZipFile zip) throws IOException {
public void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception) {
final var object = new HashMap<String, Object>();
if (exception != null) {
- object.put("error", new JsonError(exception));
+ object.put("error", JsonError.from(exception));
}
if (envelope != null) {
- object.put("envelope", new JsonMessageEnvelope(envelope, content, exception, m));
+ object.put("envelope", JsonMessageEnvelope.from(envelope, content, exception, m));
}
jsonWriter.write(object);
var group = m.getGroup(groupId);
if (group != null) {
- writer.println("Name: {}", group.getTitle());
+ writer.println("Name: {}", group.title());
} else {
writer.println("Name: <Unknown group>");
}
}
}
- private static final class JsonUserStatus {
-
- public final String recipient;
-
- public final String number;
-
- public final String uuid;
-
- public final boolean isRegistered;
-
- public JsonUserStatus(String recipient, String number, String uuid, boolean isRegistered) {
- this.recipient = recipient;
- this.number = number;
- this.uuid = uuid;
- this.isRegistered = isRegistered;
- }
- }
+ private record JsonUserStatus(String recipient, String number, String uuid, boolean isRegistered) {}
}
writer.println("Joined group \"{}\"", newGroupId.toBase64());
}
}
- handleSendMessageResults(results.second().getResults());
+ handleSendMessageResults(results.second().results());
} catch (GroupPatchNotAcceptedException e) {
throw new UserErrorException("Failed to join group, maybe already a member");
} catch (IOException e) {
public interface JsonRpcLocalCommand extends JsonRpcCommand<Map<String, Object>>, LocalCommand {
default TypeReference<Map<String, Object>> getRequestType() {
- return new TypeReference<>() {
- };
+ return new TypeReference<>() {};
}
default void handleCommand(
}
}
- private static final class JsonContact {
-
- public final String number;
- public final String uuid;
- public final String name;
- public final boolean isBlocked;
- public final int messageExpirationTime;
-
- private JsonContact(
- final String number,
- final String uuid,
- final String name,
- final boolean isBlocked,
- final int messageExpirationTime
- ) {
- this.number = number;
- this.uuid = uuid;
- this.name = name;
- this.isBlocked = isBlocked;
- this.messageExpirationTime = messageExpirationTime;
- }
- }
+ private record JsonContact(String number, String uuid, String name, boolean isBlocked, int messageExpirationTime) {}
}
if (outputWriter instanceof PlainTextWriter writer) {
for (var d : devices) {
- writer.println("- Device {}{}:", d.getId(), (d.isThisDevice() ? " (this device)" : ""));
+ writer.println("- Device {}{}:", d.id(), (d.isThisDevice() ? " (this device)" : ""));
writer.indent(w -> {
- w.println("Name: {}", d.getName());
- w.println("Created: {}", DateUtils.formatTimestamp(d.getCreated()));
- w.println("Last seen: {}", DateUtils.formatTimestamp(d.getLastSeen()));
+ w.println("Name: {}", d.name());
+ w.println("Created: {}", DateUtils.formatTimestamp(d.created()));
+ w.println("Last seen: {}", DateUtils.formatTimestamp(d.lastSeen()));
});
}
} else {
final var writer = (JsonWriter) outputWriter;
final var jsonDevices = devices.stream()
- .map(d -> new JsonDevice(d.getId(), d.getName(), d.getCreated(), d.getLastSeen()))
+ .map(d -> new JsonDevice(d.id(), d.name(), d.created(), d.lastSeen()))
.collect(Collectors.toList());
writer.write(jsonDevices);
}
}
- private static final class JsonDevice {
-
- public final long id;
- public final String name;
- public final long createdTimestamp;
- public final long lastSeenTimestamp;
-
- private JsonDevice(
- final long id, final String name, final long createdTimestamp, final long lastSeenTimestamp
- ) {
- this.id = id;
- this.name = name;
- this.createdTimestamp = createdTimestamp;
- this.lastSeenTimestamp = lastSeenTimestamp;
- }
- }
+ private record JsonDevice(long id, String name, long createdTimestamp, long lastSeenTimestamp) {}
}
PlainTextWriter writer, Group group, boolean detailed
) {
if (detailed) {
- final var groupInviteLink = group.getGroupInviteLinkUrl();
+ final var groupInviteLink = group.groupInviteLinkUrl();
writer.println(
"Id: {} Name: {} Description: {} Active: {} Blocked: {} Members: {} Pending members: {} Requesting members: {} Admins: {} Message expiration: {} Link: {}",
- group.getGroupId().toBase64(),
- group.getTitle(),
- group.getDescription(),
+ group.groupId().toBase64(),
+ group.title(),
+ group.description(),
group.isMember(),
group.isBlocked(),
- resolveMembers(group.getMembers()),
- resolveMembers(group.getPendingMembers()),
- resolveMembers(group.getRequestingMembers()),
- resolveMembers(group.getAdminMembers()),
- group.getMessageExpirationTimer() == 0 ? "disabled" : group.getMessageExpirationTimer() + "s",
+ resolveMembers(group.members()),
+ resolveMembers(group.pendingMembers()),
+ resolveMembers(group.requestingMembers()),
+ resolveMembers(group.adminMembers()),
+ group.messageExpirationTimer() == 0 ? "disabled" : group.messageExpirationTimer() + "s",
groupInviteLink == null ? '-' : groupInviteLink.getUrl());
} else {
writer.println("Id: {} Name: {} Active: {} Blocked: {}",
- group.getGroupId().toBase64(),
- group.getTitle(),
+ group.groupId().toBase64(),
+ group.title(),
group.isMember(),
group.isBlocked());
}
if (outputWriter instanceof JsonWriter jsonWriter) {
var jsonGroups = groups.stream().map(group -> {
- final var groupInviteLink = group.getGroupInviteLinkUrl();
+ final var groupInviteLink = group.groupInviteLinkUrl();
- return new JsonGroup(group.getGroupId().toBase64(),
- group.getTitle(),
- group.getDescription(),
+ return new JsonGroup(group.groupId().toBase64(),
+ group.title(),
+ group.description(),
group.isMember(),
group.isBlocked(),
- group.getMessageExpirationTimer(),
- resolveJsonMembers(group.getMembers()),
- resolveJsonMembers(group.getPendingMembers()),
- resolveJsonMembers(group.getRequestingMembers()),
- resolveJsonMembers(group.getAdminMembers()),
- group.getPermissionAddMember().name(),
- group.getPermissionEditDetails().name(),
- group.getPermissionSendMessage().name(),
+ group.messageExpirationTimer(),
+ resolveJsonMembers(group.members()),
+ resolveJsonMembers(group.pendingMembers()),
+ resolveJsonMembers(group.requestingMembers()),
+ resolveJsonMembers(group.adminMembers()),
+ group.permissionAddMember().name(),
+ group.permissionEditDetails().name(),
+ group.permissionSendMessage().name(),
groupInviteLink == null ? null : groupInviteLink.getUrl());
}).collect(Collectors.toList());
}
}
- private static final class JsonGroup {
-
- public final String id;
- public final String name;
- public final String description;
- public final boolean isMember;
- public final boolean isBlocked;
- public final int messageExpirationTime;
-
- public final Set<JsonGroupMember> members;
- public final Set<JsonGroupMember> pendingMembers;
- public final Set<JsonGroupMember> requestingMembers;
- public final Set<JsonGroupMember> admins;
- public final String permissionAddMember;
- public final String permissionEditDetails;
- public final String permissionSendMessage;
- public final String groupInviteLink;
-
- public JsonGroup(
- String id,
- String name,
- String description,
- boolean isMember,
- boolean isBlocked,
- final int messageExpirationTime,
- Set<JsonGroupMember> members,
- Set<JsonGroupMember> pendingMembers,
- Set<JsonGroupMember> requestingMembers,
- Set<JsonGroupMember> admins,
- final String permissionAddMember,
- final String permissionEditDetails,
- final String permissionSendMessage,
- String groupInviteLink
- ) {
- this.id = id;
- this.name = name;
- this.description = description;
- this.isMember = isMember;
- this.isBlocked = isBlocked;
- this.messageExpirationTime = messageExpirationTime;
-
- this.members = members;
- this.pendingMembers = pendingMembers;
- this.requestingMembers = requestingMembers;
- this.admins = admins;
- this.permissionAddMember = permissionAddMember;
- this.permissionEditDetails = permissionEditDetails;
- this.permissionSendMessage = permissionSendMessage;
- this.groupInviteLink = groupInviteLink;
- }
- }
-
- private static final class JsonGroupMember {
-
- public final String number;
- public final String uuid;
-
- private JsonGroupMember(final String number, final String uuid) {
- this.number = number;
- this.uuid = uuid;
- }
- }
+ private record JsonGroup(
+ String id,
+ String name,
+ String description,
+ boolean isMember,
+ boolean isBlocked,
+ int messageExpirationTime,
+ Set<JsonGroupMember> members,
+ Set<JsonGroupMember> pendingMembers,
+ Set<JsonGroupMember> requestingMembers,
+ Set<JsonGroupMember> admins,
+ String permissionAddMember,
+ String permissionEditDetails,
+ String permissionSendMessage,
+ String groupInviteLink
+ ) {}
+
+ private record JsonGroupMember(String number, String uuid) {}
}
}
private static void printIdentityFingerprint(PlainTextWriter writer, Manager m, Identity theirId) {
- final SignalServiceAddress address = theirId.getRecipient().toSignalServiceAddress();
- var digits = Util.formatSafetyNumber(theirId.getSafetyNumber());
+ final SignalServiceAddress address = theirId.recipient().toSignalServiceAddress();
+ var digits = Util.formatSafetyNumber(theirId.safetyNumber());
writer.println("{}: {} Added: {} Fingerprint: {} Safety Number: {}",
address.getNumber().orNull(),
- theirId.getTrustLevel(),
- theirId.getDateAdded(),
+ theirId.trustLevel(),
+ theirId.dateAdded(),
Hex.toString(theirId.getFingerprint()),
digits);
}
} else {
final var writer = (JsonWriter) outputWriter;
final var jsonIdentities = identities.stream().map(id -> {
- final var address = id.getRecipient().toSignalServiceAddress();
- var safetyNumber = Util.formatSafetyNumber(id.getSafetyNumber());
- var scannableSafetyNumber = id.getScannableSafetyNumber();
+ final var address = id.recipient().toSignalServiceAddress();
+ var safetyNumber = Util.formatSafetyNumber(id.safetyNumber());
+ var scannableSafetyNumber = id.scannableSafetyNumber();
return new JsonIdentity(address.getNumber().orNull(),
address.getUuid().toString(),
Hex.toString(id.getFingerprint()),
scannableSafetyNumber == null
? null
: Base64.getEncoder().encodeToString(scannableSafetyNumber),
- id.getTrustLevel().name(),
- id.getDateAdded().getTime());
+ id.trustLevel().name(),
+ id.dateAdded().getTime());
}).collect(Collectors.toList());
writer.write(jsonIdentities);
}
}
- private static final class JsonIdentity {
-
- public final String number;
- public final String uuid;
- public final String fingerprint;
- public final String safetyNumber;
- public final String scannableSafetyNumber;
- public final String trustLevel;
- public final long addedTimestamp;
-
- private JsonIdentity(
- final String number,
- final String uuid,
- final String fingerprint,
- final String safetyNumber,
- final String scannableSafetyNumber,
- final String trustLevel,
- final long addedTimestamp
- ) {
- this.number = number;
- this.uuid = uuid;
- this.fingerprint = fingerprint;
- this.safetyNumber = safetyNumber;
- this.scannableSafetyNumber = scannableSafetyNumber;
- this.trustLevel = trustLevel;
- this.addedTimestamp = addedTimestamp;
- }
- }
+ private record JsonIdentity(
+ String number,
+ String uuid,
+ String fingerprint,
+ String safetyNumber,
+ String scannableSafetyNumber,
+ String trustLevel,
+ long addedTimestamp
+ ) {}
}
try {
try {
final var results = m.quitGroup(groupId, groupAdmins);
- final var timestamp = results.getTimestamp();
+ final var timestamp = results.timestamp();
outputResult(outputWriter, timestamp);
- handleSendMessageResults(results.getResults());
+ handleSendMessageResults(results.results());
} catch (NotAGroupMemberException e) {
logger.info("User is not a group member");
}
if (outputWriter instanceof JsonWriter jsonWriter) {
dbusconnection.addSigHandler(Signal.MessageReceived.class, signal, messageReceived -> {
- var envelope = new JsonMessageEnvelope(messageReceived);
+ var envelope = JsonMessageEnvelope.from(messageReceived);
final var object = Map.of("envelope", envelope);
jsonWriter.write(object);
});
dbusconnection.addSigHandler(Signal.ReceiptReceived.class, signal, receiptReceived -> {
- var envelope = new JsonMessageEnvelope(receiptReceived);
+ var envelope = JsonMessageEnvelope.from(receiptReceived);
final var object = Map.of("envelope", envelope);
jsonWriter.write(object);
});
dbusconnection.addSigHandler(Signal.SyncMessageReceived.class, signal, syncReceived -> {
- var envelope = new JsonMessageEnvelope(syncReceived);
+ var envelope = JsonMessageEnvelope.from(syncReceived);
final var object = Map.of("envelope", envelope);
jsonWriter.write(object);
});
try {
final var results = m.sendRemoteDeleteMessage(targetTimestamp, recipientIdentifiers);
- outputResult(outputWriter, results.getTimestamp());
- ErrorUtils.handleSendMessageResults(results.getResults());
+ outputResult(outputWriter, results.timestamp());
+ ErrorUtils.handleSendMessageResults(results.results());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
throw new UserErrorException(e.getMessage());
} catch (IOException e) {
try {
var results = m.sendMessage(new Message(messageText, attachments), recipientIdentifiers);
- outputResult(outputWriter, results.getTimestamp());
- ErrorUtils.handleSendMessageResults(results.getResults());
+ outputResult(outputWriter, results.timestamp());
+ ErrorUtils.handleSendMessageResults(results.results());
} catch (AttachmentInvalidException | IOException e) {
throw new UnexpectedErrorException("Failed to send message: " + e.getMessage() + " (" + e.getClass()
.getSimpleName() + ")", e);
CommandUtil.getSingleRecipientIdentifier(targetAuthor, m.getSelfNumber()),
targetTimestamp,
recipientIdentifiers);
- outputResult(outputWriter, results.getTimestamp());
- ErrorUtils.handleSendMessageResults(results.getResults());
+ outputResult(outputWriter, results.timestamp());
+ ErrorUtils.handleSendMessageResults(results.results());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
throw new UserErrorException(e.getMessage());
} catch (IOException e) {
var results = m.createGroup(groupName,
groupMembers,
groupAvatar == null ? null : new File(groupAvatar));
- timestamp = results.second().getTimestamp();
- ErrorUtils.handleSendMessageResults(results.second().getResults());
+ timestamp = results.second().timestamp();
+ ErrorUtils.handleSendMessageResults(results.second().results());
groupId = results.first();
groupName = null;
groupMembers = null;
: groupSendMessagesPermission == GroupPermission.ONLY_ADMINS)
.build());
if (results != null) {
- timestamp = results.getTimestamp();
- ErrorUtils.handleSendMessageResults(results.getResults());
+ timestamp = results.timestamp();
+ ErrorUtils.handleSendMessageResults(results.results());
}
outputResult(outputWriter, timestamp, isNewGroup ? groupId : null);
} catch (AttachmentInvalidException e) {
final Message message, final Set<RecipientIdentifier> recipients
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
return handleMessage(recipients,
- numbers -> signal.sendMessage(message.getMessageText(), message.getAttachments(), numbers),
- () -> signal.sendNoteToSelfMessage(message.getMessageText(), message.getAttachments()),
- groupId -> signal.sendGroupMessage(message.getMessageText(), message.getAttachments(), groupId));
+ numbers -> signal.sendMessage(message.messageText(), message.attachments(), numbers),
+ () -> signal.sendNoteToSelfMessage(message.messageText(), message.attachments()),
+ groupId -> signal.sendGroupMessage(message.messageText(), message.attachments(), groupId));
}
@Override
.map(RecipientIdentifier.class::cast)
.collect(Collectors.toSet()));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (AttachmentInvalidException e) {
throw new Error.AttachmentInvalid(e.getMessage());
} catch (IOException e) {
getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
.map(RecipientIdentifier.class::cast)
.collect(Collectors.toSet()));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
try {
final var results = m.sendRemoteDeleteMessage(targetSentTimestamp,
Set.of(new RecipientIdentifier.Group(getGroupId(groupId))));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
.map(RecipientIdentifier.class::cast)
.collect(Collectors.toSet()));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
try {
final var results = m.sendMessage(new Message(message, attachments),
Set.of(RecipientIdentifier.NoteToSelf.INSTANCE));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (AttachmentInvalidException e) {
throw new Error.AttachmentInvalid(e.getMessage());
} catch (IOException e) {
public void sendEndSessionMessage(final List<String> recipients) {
try {
final var results = m.sendEndSessionMessage(getSingleRecipientIdentifiers(recipients, m.getSelfNumber()));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
+ checkSendMessageResults(results.timestamp(), results.results());
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
}
try {
var results = m.sendMessage(new Message(message, attachments),
Set.of(new RecipientIdentifier.Group(getGroupId(groupId))));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
getSingleRecipientIdentifier(targetAuthor, m.getSelfNumber()),
targetSentTimestamp,
Set.of(new RecipientIdentifier.Group(getGroupId(groupId))));
- checkSendMessageResults(results.getTimestamp(), results.getResults());
- return results.getTimestamp();
+ checkSendMessageResults(results.timestamp(), results.results());
+ return results.timestamp();
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
var groups = m.getGroups();
var ids = new ArrayList<byte[]>(groups.size());
for (var group : groups) {
- ids.add(group.getGroupId().serialize());
+ ids.add(group.groupId().serialize());
}
return ids;
}
@Override
public String getGroupName(final byte[] groupId) {
var group = m.getGroup(getGroupId(groupId));
- if (group == null || group.getTitle() == null) {
+ if (group == null || group.title() == null) {
return "";
} else {
- return group.getTitle();
+ return group.title();
}
}
if (group == null) {
return List.of();
} else {
- final var members = group.getMembers();
+ final var members = group.members();
return getRecipientStrings(members);
}
}
final var memberIdentifiers = getSingleRecipientIdentifiers(members, m.getSelfNumber());
if (groupId == null) {
final var results = m.createGroup(name, memberIdentifiers, avatar == null ? null : new File(avatar));
- checkSendMessageResults(results.second().getTimestamp(), results.second().getResults());
+ checkSendMessageResults(results.second().timestamp(), results.second().results());
return results.first().serialize();
} else {
final var results = m.updateGroup(getGroupId(groupId),
.withAvatarFile(avatar == null ? null : new File(avatar))
.build());
if (results != null) {
- checkSendMessageResults(results.getTimestamp(), results.getResults());
+ checkSendMessageResults(results.timestamp(), results.results());
}
return groupId;
}
// all numbers the system knows
@Override
public List<String> listNumbers() {
- return Stream.concat(m.getIdentities().stream().map(Identity::getRecipient),
- m.getContacts().stream().map(Pair::first))
+ return Stream.concat(m.getIdentities().stream().map(Identity::recipient),
+ m.getContacts().stream().map(Pair::first))
.map(a -> a.getNumber().orElse(null))
.filter(Objects::nonNull)
.distinct()
}
// Try profiles if no contact name was found
for (var identity : m.getIdentities()) {
- final var address = identity.getRecipient();
+ final var address = identity.recipient();
var number = address.getNumber().orElse(null);
if (number != null) {
Profile profile = null;
if (d.isThisDevice()) {
thisDevice = new DBusPath(deviceObjectPath);
}
- this.devices.add(new StructDevice(new DBusPath(deviceObjectPath), d.getId(), emptyIfNull(d.getName())));
+ this.devices.add(new StructDevice(new DBusPath(deviceObjectPath), d.id(), emptyIfNull(d.name())));
});
}
unExportGroups();
groups.forEach(g -> {
- final var object = new DbusSignalGroupImpl(g.getGroupId());
+ final var object = new DbusSignalGroupImpl(g.groupId());
try {
connection.exportObject(object);
} catch (DBusException e) {
e.printStackTrace();
}
this.groups.add(new StructGroup(new DBusPath(object.getObjectPath()),
- g.getGroupId().serialize(),
- emptyIfNull(g.getTitle())));
+ g.groupId().serialize(),
+ emptyIfNull(g.title())));
});
}
public DbusSignalDeviceImpl(final org.asamk.signal.manager.api.Device device) {
super.addPropertiesHandler(new DbusInterfacePropertiesHandler("org.asamk.Signal.Device",
- List.of(new DbusProperty<>("Id", device::getId),
- new DbusProperty<>("Name", () -> emptyIfNull(device.getName()), this::setDeviceName),
- new DbusProperty<>("Created", device::getCreated),
- new DbusProperty<>("LastSeen", device::getLastSeen))));
+ List.of(new DbusProperty<>("Id", device::id),
+ new DbusProperty<>("Name", () -> emptyIfNull(device.name()), this::setDeviceName),
+ new DbusProperty<>("Created", device::created),
+ new DbusProperty<>("LastSeen", device::lastSeen))));
this.device = device;
}
@Override
public String getObjectPath() {
- return getDeviceObjectPath(objectPath, device.getId());
+ return getDeviceObjectPath(objectPath, device.id());
}
@Override
public void removeDevice() throws Error.Failure {
try {
- m.removeLinkedDevices(device.getId());
+ m.removeLinkedDevices(device.id());
updateDevices();
} catch (IOException e) {
throw new Error.Failure(e.getMessage());
this.groupId = groupId;
super.addPropertiesHandler(new DbusInterfacePropertiesHandler("org.asamk.Signal.Group",
List.of(new DbusProperty<>("Id", groupId::serialize),
- new DbusProperty<>("Name", () -> emptyIfNull(getGroup().getTitle()), this::setGroupName),
+ new DbusProperty<>("Name", () -> emptyIfNull(getGroup().title()), this::setGroupName),
new DbusProperty<>("Description",
- () -> emptyIfNull(getGroup().getDescription()),
+ () -> emptyIfNull(getGroup().description()),
this::setGroupDescription),
new DbusProperty<>("Avatar", this::setGroupAvatar),
new DbusProperty<>("IsBlocked", () -> getGroup().isBlocked(), this::setIsBlocked),
new DbusProperty<>("IsMember", () -> getGroup().isMember()),
new DbusProperty<>("IsAdmin", () -> getGroup().isAdmin()),
new DbusProperty<>("MessageExpirationTimer",
- () -> getGroup().getMessageExpirationTimer(),
+ () -> getGroup().messageExpirationTimer(),
this::setMessageExpirationTime),
new DbusProperty<>("Members",
- () -> new Variant<>(getRecipientStrings(getGroup().getMembers()), "as")),
+ () -> new Variant<>(getRecipientStrings(getGroup().members()), "as")),
new DbusProperty<>("PendingMembers",
- () -> new Variant<>(getRecipientStrings(getGroup().getPendingMembers()), "as")),
+ () -> new Variant<>(getRecipientStrings(getGroup().pendingMembers()), "as")),
new DbusProperty<>("RequestingMembers",
- () -> new Variant<>(getRecipientStrings(getGroup().getRequestingMembers()), "as")),
+ () -> new Variant<>(getRecipientStrings(getGroup().requestingMembers()), "as")),
new DbusProperty<>("Admins",
- () -> new Variant<>(getRecipientStrings(getGroup().getAdminMembers()), "as")),
+ () -> new Variant<>(getRecipientStrings(getGroup().adminMembers()), "as")),
new DbusProperty<>("PermissionAddMember",
- () -> getGroup().getPermissionAddMember().name(),
+ () -> getGroup().permissionAddMember().name(),
this::setGroupPermissionAddMember),
new DbusProperty<>("PermissionEditDetails",
- () -> getGroup().getPermissionEditDetails().name(),
+ () -> getGroup().permissionEditDetails().name(),
this::setGroupPermissionEditDetails),
new DbusProperty<>("PermissionSendMessage",
- () -> getGroup().getPermissionSendMessage().name(),
+ () -> getGroup().permissionSendMessage().name(),
this::setGroupPermissionSendMessage),
new DbusProperty<>("GroupInviteLink", () -> {
- final var groupInviteLinkUrl = getGroup().getGroupInviteLinkUrl();
+ final var groupInviteLinkUrl = getGroup().groupInviteLinkUrl();
return groupInviteLinkUrl == null ? "" : groupInviteLinkUrl.getUrl();
}))));
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
-class JsonAttachment {
-
- @JsonProperty
- final String contentType;
-
- @JsonProperty
- final String filename;
-
- @JsonProperty
- final String id;
-
- @JsonProperty
- final Long size;
-
- JsonAttachment(SignalServiceAttachment attachment) {
- this.contentType = attachment.getContentType();
+record JsonAttachment(String contentType, String filename, String id, Long size) {
+ static JsonAttachment from(SignalServiceAttachment attachment) {
if (attachment.isPointer()) {
final var pointer = attachment.asPointer();
- this.id = pointer.getRemoteId().toString();
- this.filename = pointer.getFileName().orNull();
- this.size = pointer.getSize().transform(Integer::longValue).orNull();
+ final var id = pointer.getRemoteId().toString();
+ final var filename = pointer.getFileName().orNull();
+ final var size = pointer.getSize().transform(Integer::longValue).orNull();
+ return new JsonAttachment(attachment.getContentType(), filename, id, size);
} else {
final var stream = attachment.asStream();
- this.id = null;
- this.filename = stream.getFileName().orNull();
- this.size = stream.getLength();
+ final var filename = stream.getFileName().orNull();
+ final var size = stream.getLength();
+ return new JsonAttachment(attachment.getContentType(), filename, null, size);
}
}
- JsonAttachment(String filename) {
- this.filename = filename;
- this.contentType = null;
- this.id = null;
- this.size = null;
+ static JsonAttachment from(String filename) {
+ return new JsonAttachment(filename, null, null, null);
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
import java.util.List;
-class JsonCallMessage {
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final OfferMessage offerMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final AnswerMessage answerMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final BusyMessage busyMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final HangupMessage hangupMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<IceUpdateMessage> iceUpdateMessages;
-
- JsonCallMessage(SignalServiceCallMessage callMessage) {
- this.offerMessage = callMessage.getOfferMessage().orNull();
- this.answerMessage = callMessage.getAnswerMessage().orNull();
- this.busyMessage = callMessage.getBusyMessage().orNull();
- this.hangupMessage = callMessage.getHangupMessage().orNull();
- this.iceUpdateMessages = callMessage.getIceUpdateMessages().orNull();
+record JsonCallMessage(
+ @JsonInclude(JsonInclude.Include.NON_NULL) OfferMessage offerMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) AnswerMessage answerMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) BusyMessage busyMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) HangupMessage hangupMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<IceUpdateMessage> iceUpdateMessages
+) {
+
+ static JsonCallMessage from(SignalServiceCallMessage callMessage) {
+ return new JsonCallMessage(callMessage.getOfferMessage().orNull(),
+ callMessage.getAnswerMessage().orNull(),
+ callMessage.getBusyMessage().orNull(),
+ callMessage.getHangupMessage().orNull(),
+ callMessage.getIceUpdateMessages().orNull());
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.asamk.signal.util.Util;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
-public class JsonContactAddress {
-
- @JsonProperty
- private final SharedContact.PostalAddress.Type type;
-
- @JsonProperty
- private final String label;
-
- @JsonProperty
- private final String street;
-
- @JsonProperty
- private final String pobox;
-
- @JsonProperty
- private final String neighborhood;
-
- @JsonProperty
- private final String city;
-
- @JsonProperty
- private final String region;
-
- @JsonProperty
- private final String postcode;
-
- @JsonProperty
- private final String country;
-
- public JsonContactAddress(SharedContact.PostalAddress address) {
- type = address.getType();
- label = Util.getStringIfNotBlank(address.getLabel());
- street = Util.getStringIfNotBlank(address.getStreet());
- pobox = Util.getStringIfNotBlank(address.getPobox());
- neighborhood = Util.getStringIfNotBlank(address.getNeighborhood());
- city = Util.getStringIfNotBlank(address.getCity());
- region = Util.getStringIfNotBlank(address.getRegion());
- postcode = Util.getStringIfNotBlank(address.getPostcode());
- country = Util.getStringIfNotBlank(address.getCountry());
+public record JsonContactAddress(
+ SharedContact.PostalAddress.Type type,
+ String label,
+ String street,
+ String pobox,
+ String neighborhood,
+ String city,
+ String region,
+ String postcode,
+ String country
+) {
+
+ static JsonContactAddress from(SharedContact.PostalAddress address) {
+ return new JsonContactAddress(address.getType(),
+ Util.getStringIfNotBlank(address.getLabel()),
+ Util.getStringIfNotBlank(address.getStreet()),
+ Util.getStringIfNotBlank(address.getPobox()),
+ Util.getStringIfNotBlank(address.getNeighborhood()),
+ Util.getStringIfNotBlank(address.getCity()),
+ Util.getStringIfNotBlank(address.getRegion()),
+ Util.getStringIfNotBlank(address.getPostcode()),
+ Util.getStringIfNotBlank(address.getCountry()));
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
-public class JsonContactAvatar {
-
- @JsonProperty
- private final JsonAttachment attachment;
-
- @JsonProperty
- private final boolean isProfile;
+public record JsonContactAvatar(JsonAttachment attachment, boolean isProfile) {
- public JsonContactAvatar(SharedContact.Avatar avatar) {
- attachment = new JsonAttachment(avatar.getAttachment());
- isProfile = avatar.isProfile();
+ static JsonContactAvatar from(SharedContact.Avatar avatar) {
+ return new JsonContactAvatar(JsonAttachment.from(avatar.getAttachment()), avatar.isProfile());
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.asamk.signal.util.Util;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
-public class JsonContactEmail {
-
- @JsonProperty
- private final String value;
-
- @JsonProperty
- private final SharedContact.Email.Type type;
-
- @JsonProperty
- private final String label;
+public record JsonContactEmail(String value, SharedContact.Email.Type type, String label) {
- public JsonContactEmail(SharedContact.Email email) {
- value = email.getValue();
- type = email.getType();
- label = Util.getStringIfNotBlank(email.getLabel());
+ static JsonContactEmail from(SharedContact.Email email) {
+ return new JsonContactEmail(email.getValue(), email.getType(), Util.getStringIfNotBlank(email.getLabel()));
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.asamk.signal.util.Util;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
-public class JsonContactName {
-
- @JsonProperty
- private final String display;
-
- @JsonProperty
- private final String given;
-
- @JsonProperty
- private final String family;
-
- @JsonProperty
- private final String prefix;
-
- @JsonProperty
- private final String suffix;
-
- @JsonProperty
- private final String middle;
-
- public JsonContactName(SharedContact.Name name) {
- display = Util.getStringIfNotBlank(name.getDisplay());
- given = Util.getStringIfNotBlank(name.getGiven());
- family = Util.getStringIfNotBlank(name.getFamily());
- prefix = Util.getStringIfNotBlank(name.getPrefix());
- suffix = Util.getStringIfNotBlank(name.getSuffix());
- middle = Util.getStringIfNotBlank(name.getMiddle());
+public record JsonContactName(
+ String display, String given, String family, String prefix, String suffix, String middle
+) {
+
+ static JsonContactName from(SharedContact.Name name) {
+ return new JsonContactName(Util.getStringIfNotBlank(name.getDisplay()),
+ Util.getStringIfNotBlank(name.getGiven()),
+ Util.getStringIfNotBlank(name.getFamily()),
+ Util.getStringIfNotBlank(name.getPrefix()),
+ Util.getStringIfNotBlank(name.getSuffix()),
+ Util.getStringIfNotBlank(name.getMiddle()));
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.asamk.signal.util.Util;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
-public class JsonContactPhone {
-
- @JsonProperty
- private final String value;
-
- @JsonProperty
- private final SharedContact.Phone.Type type;
-
- @JsonProperty
- private final String label;
+public record JsonContactPhone(String value, SharedContact.Phone.Type type, String label) {
- public JsonContactPhone(SharedContact.Phone phone) {
- value = phone.getValue();
- type = phone.getType();
- label = Util.getStringIfNotBlank(phone.getLabel());
+ static JsonContactPhone from(SharedContact.Phone phone) {
+ return new JsonContactPhone(phone.getValue(), phone.getType(), Util.getStringIfNotBlank(phone.getLabel()));
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.asamk.Signal;
import org.asamk.signal.manager.Manager;
import java.util.List;
import java.util.stream.Collectors;
-class JsonDataMessage {
-
- @JsonProperty
- final long timestamp;
-
- @JsonProperty
- final String message;
-
- @JsonProperty
- final Integer expiresInSeconds;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final Boolean viewOnce;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonReaction reaction;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonQuote quote;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonMention> mentions;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonAttachment> attachments;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonSticker sticker;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonRemoteDelete remoteDelete;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonSharedContact> contacts;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonGroupInfo groupInfo;
-
- JsonDataMessage(SignalServiceDataMessage dataMessage, Manager m) {
- this.timestamp = dataMessage.getTimestamp();
+record JsonDataMessage(
+ long timestamp,
+ String message,
+ Integer expiresInSeconds,
+ @JsonInclude(JsonInclude.Include.NON_NULL) Boolean viewOnce,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonReaction reaction,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonQuote quote,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonMention> mentions,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonAttachment> attachments,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonSticker sticker,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonRemoteDelete remoteDelete,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonSharedContact> contacts,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonGroupInfo groupInfo
+) {
+
+ static JsonDataMessage from(SignalServiceDataMessage dataMessage, Manager m) {
+ final var timestamp = dataMessage.getTimestamp();
+ final JsonGroupInfo groupInfo;
if (dataMessage.getGroupContext().isPresent()) {
final var groupContext = dataMessage.getGroupContext().get();
if (groupContext.getGroupV1().isPresent()) {
- var groupInfo = groupContext.getGroupV1().get();
- this.groupInfo = new JsonGroupInfo(groupInfo);
+ var group = groupContext.getGroupV1().get();
+ groupInfo = JsonGroupInfo.from(group);
} else if (groupContext.getGroupV2().isPresent()) {
- var groupInfo = groupContext.getGroupV2().get();
- this.groupInfo = new JsonGroupInfo(groupInfo);
+ var group = groupContext.getGroupV2().get();
+ groupInfo = JsonGroupInfo.from(group);
} else {
- this.groupInfo = null;
+ groupInfo = null;
}
} else {
- this.groupInfo = null;
+ groupInfo = null;
}
- this.message = dataMessage.getBody().orNull();
- this.expiresInSeconds = dataMessage.getExpiresInSeconds();
- this.viewOnce = dataMessage.isViewOnce();
- this.reaction = dataMessage.getReaction().isPresent()
- ? new JsonReaction(dataMessage.getReaction().get(), m)
- : null;
- this.quote = dataMessage.getQuote().isPresent() ? new JsonQuote(dataMessage.getQuote().get(), m) : null;
+ final var message = dataMessage.getBody().orNull();
+ final var expiresInSeconds = dataMessage.getExpiresInSeconds();
+ final var viewOnce = dataMessage.isViewOnce();
+ final var reaction = dataMessage.getReaction().isPresent() ? JsonReaction.from(dataMessage.getReaction().get(),
+ m) : null;
+ final var quote = dataMessage.getQuote().isPresent() ? JsonQuote.from(dataMessage.getQuote().get(), m) : null;
+ final List<JsonMention> mentions;
if (dataMessage.getMentions().isPresent()) {
- this.mentions = dataMessage.getMentions()
+ mentions = dataMessage.getMentions()
.get()
.stream()
- .map(mention -> new JsonMention(mention, m))
+ .map(mention -> JsonMention.from(mention, m))
.collect(Collectors.toList());
} else {
- this.mentions = List.of();
+ mentions = List.of();
}
- remoteDelete = dataMessage.getRemoteDelete().isPresent() ? new JsonRemoteDelete(dataMessage.getRemoteDelete()
- .get()) : null;
+ final var remoteDelete = dataMessage.getRemoteDelete().isPresent()
+ ? JsonRemoteDelete.from(dataMessage.getRemoteDelete().get())
+ : null;
+ final List<JsonAttachment> attachments;
if (dataMessage.getAttachments().isPresent()) {
- this.attachments = dataMessage.getAttachments()
+ attachments = dataMessage.getAttachments()
.get()
.stream()
- .map(JsonAttachment::new)
+ .map(JsonAttachment::from)
.collect(Collectors.toList());
} else {
- this.attachments = List.of();
+ attachments = List.of();
}
- this.sticker = dataMessage.getSticker().isPresent() ? new JsonSticker(dataMessage.getSticker().get()) : null;
+ final var sticker = dataMessage.getSticker().isPresent()
+ ? JsonSticker.from(dataMessage.getSticker().get())
+ : null;
+ final List<JsonSharedContact> contacts;
if (dataMessage.getSharedContacts().isPresent()) {
- this.contacts = dataMessage.getSharedContacts()
+ contacts = dataMessage.getSharedContacts()
.get()
.stream()
- .map(JsonSharedContact::new)
+ .map(JsonSharedContact::from)
.collect(Collectors.toList());
} else {
- this.contacts = List.of();
+ contacts = List.of();
}
+ return new JsonDataMessage(timestamp,
+ message,
+ expiresInSeconds,
+ viewOnce,
+ reaction,
+ quote,
+ mentions,
+ attachments,
+ sticker,
+ remoteDelete,
+ contacts,
+ groupInfo);
}
- public JsonDataMessage(Signal.MessageReceived messageReceived) {
- timestamp = messageReceived.getTimestamp();
- message = messageReceived.getMessage();
- groupInfo = messageReceived.getGroupId().length > 0 ? new JsonGroupInfo(messageReceived.getGroupId()) : null;
- expiresInSeconds = null;
- viewOnce = null;
- remoteDelete = null;
- reaction = null; // TODO Replace these 5 with the proper commands
- quote = null;
- mentions = null;
- sticker = null;
- contacts = null;
- attachments = messageReceived.getAttachments().stream().map(JsonAttachment::new).collect(Collectors.toList());
+ static JsonDataMessage from(Signal.MessageReceived messageReceived) {
+ return new JsonDataMessage(messageReceived.getTimestamp(),
+ messageReceived.getMessage(),
+ // TODO Replace these with the proper commands
+ null,
+ null,
+ null,
+ null,
+ null,
+ messageReceived.getAttachments().stream().map(JsonAttachment::from).collect(Collectors.toList()),
+ null,
+ null,
+ null,
+ messageReceived.getGroupId().length > 0 ? JsonGroupInfo.from(messageReceived.getGroupId()) : null);
}
- public JsonDataMessage(Signal.SyncMessageReceived messageReceived) {
- timestamp = messageReceived.getTimestamp();
- message = messageReceived.getMessage();
- groupInfo = messageReceived.getGroupId().length > 0 ? new JsonGroupInfo(messageReceived.getGroupId()) : null;
- expiresInSeconds = null;
- viewOnce = null;
- remoteDelete = null;
- reaction = null; // TODO Replace these 5 with the proper commands
- quote = null;
- mentions = null;
- sticker = null;
- contacts = null;
- attachments = messageReceived.getAttachments().stream().map(JsonAttachment::new).collect(Collectors.toList());
+ static JsonDataMessage from(Signal.SyncMessageReceived messageReceived) {
+ return new JsonDataMessage(messageReceived.getTimestamp(),
+ messageReceived.getMessage(),
+ // TODO Replace these with the proper commands
+ null,
+ null,
+ null,
+ null,
+ null,
+ messageReceived.getAttachments().stream().map(JsonAttachment::from).collect(Collectors.toList()),
+ null,
+ null,
+ null,
+ messageReceived.getGroupId().length > 0 ? JsonGroupInfo.from(messageReceived.getGroupId()) : null);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
+public record JsonError(String message, String type) {
-public class JsonError {
-
- @JsonProperty
- final String message;
-
- @JsonProperty
- final String type;
-
- public JsonError(Throwable exception) {
- this.message = exception.getMessage();
- this.type = exception.getClass().getSimpleName();
+ public static JsonError from(Throwable exception) {
+ return new JsonError(exception.getMessage(), exception.getClass().getSimpleName());
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.asamk.signal.manager.groups.GroupUtils;
import org.asamk.signal.util.Util;
import java.util.List;
import java.util.stream.Collectors;
-class JsonGroupInfo {
-
- @JsonProperty
- final String groupId;
-
- @JsonProperty
- final String type;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final String name;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<String> members;
-
- JsonGroupInfo(SignalServiceGroup groupInfo) {
- this.groupId = Base64.getEncoder().encodeToString(groupInfo.getGroupId());
- this.type = groupInfo.getType().toString();
- this.name = groupInfo.getName().orNull();
- if (groupInfo.getMembers().isPresent()) {
- this.members = groupInfo.getMembers()
- .get()
- .stream()
- .map(Util::getLegacyIdentifier)
- .collect(Collectors.toList());
- } else {
- this.members = null;
- }
+record JsonGroupInfo(
+ String groupId,
+ String type,
+ @JsonInclude(JsonInclude.Include.NON_NULL) String name,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<String> members
+) {
+
+ static JsonGroupInfo from(SignalServiceGroup groupInfo) {
+ return new JsonGroupInfo(Base64.getEncoder().encodeToString(groupInfo.getGroupId()),
+ groupInfo.getType().toString(),
+ groupInfo.getName().orNull(),
+ groupInfo.getMembers().isPresent() ? groupInfo.getMembers()
+ .get()
+ .stream()
+ .map(Util::getLegacyIdentifier)
+ .collect(Collectors.toList()) : null);
}
- JsonGroupInfo(SignalServiceGroupV2 groupInfo) {
- this.groupId = GroupUtils.getGroupIdV2(groupInfo.getMasterKey()).toBase64();
- this.type = groupInfo.hasSignedGroupChange() ? "UPDATE" : "DELIVER";
- this.members = null;
- this.name = null;
+ static JsonGroupInfo from(SignalServiceGroupV2 groupInfo) {
+ return new JsonGroupInfo(GroupUtils.getGroupIdV2(groupInfo.getMasterKey()).toBase64(),
+ groupInfo.hasSignedGroupChange() ? "UPDATE" : "DELIVER",
+ null,
+ null);
}
- JsonGroupInfo(byte[] groupId) {
- this.groupId = Base64.getEncoder().encodeToString(groupId);
- this.type = "DELIVER";
- this.members = null;
- this.name = null;
+ static JsonGroupInfo from(byte[] groupId) {
+ return new JsonGroupInfo(Base64.getEncoder().encodeToString(groupId), "DELIVER", null, null);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.asamk.signal.manager.Manager;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import static org.asamk.signal.util.Util.getLegacyIdentifier;
-public class JsonMention {
-
- @JsonProperty
- @Deprecated
- final String name;
-
- @JsonProperty
- final String number;
-
- @JsonProperty
- final String uuid;
-
- @JsonProperty
- final int start;
-
- @JsonProperty
- final int length;
+public record JsonMention(@Deprecated String name, String number, String uuid, int start, int length) {
- JsonMention(SignalServiceDataMessage.Mention mention, Manager m) {
+ static JsonMention from(SignalServiceDataMessage.Mention mention, Manager m) {
final var address = m.resolveSignalServiceAddress(new SignalServiceAddress(mention.getUuid()));
- this.name = getLegacyIdentifier(address);
- this.number = address.getNumber().orNull();
- this.uuid = address.getUuid().toString();
- this.start = mention.getStart();
- this.length = mention.getLength();
+ return new JsonMention(getLegacyIdentifier(address),
+ address.getNumber().orNull(),
+ address.getUuid().toString(),
+ mention.getStart(),
+ mention.getLength());
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.asamk.Signal;
import org.asamk.signal.manager.Manager;
import static org.asamk.signal.util.Util.getLegacyIdentifier;
-public class JsonMessageEnvelope {
-
- @JsonProperty
- @Deprecated
- final String source;
-
- @JsonProperty
- final String sourceNumber;
-
- @JsonProperty
- final String sourceUuid;
-
- @JsonProperty
- final String sourceName;
-
- @JsonProperty
- final Integer sourceDevice;
-
- @JsonProperty
- final long timestamp;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonDataMessage dataMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonSyncMessage syncMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonCallMessage callMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonReceiptMessage receiptMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonTypingMessage typingMessage;
-
- public JsonMessageEnvelope(
+public record JsonMessageEnvelope(
+ @Deprecated String source,
+ String sourceNumber,
+ String sourceUuid,
+ String sourceName,
+ Integer sourceDevice,
+ long timestamp,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonDataMessage dataMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessage syncMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonCallMessage callMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonReceiptMessage receiptMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonTypingMessage typingMessage
+) {
+
+ public static JsonMessageEnvelope from(
SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception, Manager m
) {
+ final String source;
+ final String sourceNumber;
+ final String sourceUuid;
+ final Integer sourceDevice;
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
- var source = m.resolveSignalServiceAddress(envelope.getSourceAddress());
- this.source = getLegacyIdentifier(source);
- this.sourceNumber = source.getNumber().orNull();
- this.sourceUuid = source.getUuid().toString();
- this.sourceDevice = envelope.getSourceDevice();
+ final var sourceAddress = m.resolveSignalServiceAddress(envelope.getSourceAddress());
+ source = getLegacyIdentifier(sourceAddress);
+ sourceNumber = sourceAddress.getNumber().orNull();
+ sourceUuid = sourceAddress.getUuid().toString();
+ sourceDevice = envelope.getSourceDevice();
} else if (envelope.isUnidentifiedSender() && content != null) {
- final var source = m.resolveSignalServiceAddress(content.getSender());
- this.source = getLegacyIdentifier(source);
- this.sourceNumber = source.getNumber().orNull();
- this.sourceUuid = source.getUuid().toString();
- this.sourceDevice = content.getSenderDevice();
+ final var sender = m.resolveSignalServiceAddress(content.getSender());
+ source = getLegacyIdentifier(sender);
+ sourceNumber = sender.getNumber().orNull();
+ sourceUuid = sender.getUuid().toString();
+ sourceDevice = content.getSenderDevice();
} else if (exception instanceof UntrustedIdentityException e) {
- final var source = m.resolveSignalServiceAddress(e.getSender());
- this.source = getLegacyIdentifier(source);
- this.sourceNumber = source.getNumber().orNull();
- this.sourceUuid = source.getUuid().toString();
- this.sourceDevice = e.getSenderDevice();
+ final var sender = m.resolveSignalServiceAddress(e.getSender());
+ source = getLegacyIdentifier(sender);
+ sourceNumber = sender.getNumber().orNull();
+ sourceUuid = sender.getUuid().toString();
+ sourceDevice = e.getSenderDevice();
} else {
- this.source = null;
- this.sourceNumber = null;
- this.sourceUuid = null;
- this.sourceDevice = null;
+ source = null;
+ sourceNumber = null;
+ sourceUuid = null;
+ sourceDevice = null;
}
String name;
try {
- name = m.getContactOrProfileName(RecipientIdentifier.Single.fromString(this.source, m.getSelfNumber()));
+ name = m.getContactOrProfileName(RecipientIdentifier.Single.fromString(source, m.getSelfNumber()));
} catch (InvalidNumberException | NullPointerException e) {
name = null;
}
- this.sourceName = name;
- this.timestamp = envelope.getTimestamp();
+ final var sourceName = name;
+ final var timestamp = envelope.getTimestamp();
+ final JsonReceiptMessage receiptMessage;
if (envelope.isReceipt()) {
- this.receiptMessage = JsonReceiptMessage.deliveryReceipt(timestamp, List.of(timestamp));
+ receiptMessage = JsonReceiptMessage.deliveryReceipt(timestamp, List.of(timestamp));
} else if (content != null && content.getReceiptMessage().isPresent()) {
- this.receiptMessage = new JsonReceiptMessage(content.getReceiptMessage().get());
+ receiptMessage = JsonReceiptMessage.from(content.getReceiptMessage().get());
} else {
- this.receiptMessage = null;
+ receiptMessage = null;
}
- this.typingMessage = content != null && content.getTypingMessage().isPresent()
- ? new JsonTypingMessage(content.getTypingMessage().get())
- : null;
+ final var typingMessage = content != null && content.getTypingMessage().isPresent() ? JsonTypingMessage.from(
+ content.getTypingMessage().get()) : null;
- this.dataMessage = content != null && content.getDataMessage().isPresent()
- ? new JsonDataMessage(content.getDataMessage().get(), m)
+ final var dataMessage = content != null && content.getDataMessage().isPresent()
+ ? JsonDataMessage.from(content.getDataMessage().get(), m)
: null;
- this.syncMessage = content != null && content.getSyncMessage().isPresent()
- ? new JsonSyncMessage(content.getSyncMessage().get(), m)
+ final var syncMessage = content != null && content.getSyncMessage().isPresent()
+ ? JsonSyncMessage.from(content.getSyncMessage().get(), m)
: null;
- this.callMessage = content != null && content.getCallMessage().isPresent()
- ? new JsonCallMessage(content.getCallMessage().get())
+ final var callMessage = content != null && content.getCallMessage().isPresent()
+ ? JsonCallMessage.from(content.getCallMessage().get())
: null;
+
+ return new JsonMessageEnvelope(source,
+ sourceNumber,
+ sourceUuid,
+ sourceName,
+ sourceDevice,
+ timestamp,
+ dataMessage,
+ syncMessage,
+ callMessage,
+ receiptMessage,
+ typingMessage);
}
- public JsonMessageEnvelope(Signal.MessageReceived messageReceived) {
- source = messageReceived.getSender();
- sourceNumber = null;
- sourceUuid = null;
- sourceName = null;
- sourceDevice = null;
- timestamp = messageReceived.getTimestamp();
- receiptMessage = null;
- dataMessage = new JsonDataMessage(messageReceived);
- syncMessage = null;
- callMessage = null;
- typingMessage = null;
+ public static JsonMessageEnvelope from(Signal.MessageReceived messageReceived) {
+ return new JsonMessageEnvelope(messageReceived.getSource(),
+ null,
+ null,
+ null,
+ null,
+ messageReceived.getTimestamp(),
+ JsonDataMessage.from(messageReceived),
+ null,
+ null,
+ null,
+ null);
}
- public JsonMessageEnvelope(Signal.ReceiptReceived receiptReceived) {
- source = receiptReceived.getSender();
- sourceNumber = null;
- sourceUuid = null;
- sourceName = null;
- sourceDevice = null;
- timestamp = receiptReceived.getTimestamp();
- receiptMessage = JsonReceiptMessage.deliveryReceipt(timestamp, List.of(timestamp));
- dataMessage = null;
- syncMessage = null;
- callMessage = null;
- typingMessage = null;
+ public static JsonMessageEnvelope from(Signal.ReceiptReceived receiptReceived) {
+ return new JsonMessageEnvelope(receiptReceived.getSender(),
+ null,
+ null,
+ null,
+ null,
+ receiptReceived.getTimestamp(),
+ null,
+ null,
+ null,
+ JsonReceiptMessage.deliveryReceipt(receiptReceived.getTimestamp(),
+ List.of(receiptReceived.getTimestamp())),
+ null);
}
- public JsonMessageEnvelope(Signal.SyncMessageReceived messageReceived) {
- source = messageReceived.getSource();
- sourceNumber = null;
- sourceUuid = null;
- sourceName = null;
- sourceDevice = null;
- timestamp = messageReceived.getTimestamp();
- receiptMessage = null;
- dataMessage = null;
- syncMessage = new JsonSyncMessage(messageReceived);
- callMessage = null;
- typingMessage = null;
+ public static JsonMessageEnvelope from(Signal.SyncMessageReceived messageReceived) {
+ return new JsonMessageEnvelope(messageReceived.getSource(),
+ null,
+ null,
+ null,
+ null,
+ messageReceived.getTimestamp(),
+ null,
+ JsonSyncMessage.from(messageReceived),
+ null,
+ null,
+ null);
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.asamk.signal.manager.Manager;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import static org.asamk.signal.util.Util.getLegacyIdentifier;
-public class JsonQuote {
-
- @JsonProperty
- final long id;
-
- @JsonProperty
- @Deprecated
- final String author;
-
- @JsonProperty
- final String authorNumber;
-
- @JsonProperty
- final String authorUuid;
-
- @JsonProperty
- final String text;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonMention> mentions;
-
- @JsonProperty
- final List<JsonQuotedAttachment> attachments;
-
- JsonQuote(SignalServiceDataMessage.Quote quote, Manager m) {
- this.id = quote.getId();
+public record JsonQuote(
+ long id,
+ @Deprecated String author,
+ String authorNumber,
+ String authorUuid,
+ String text,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonMention> mentions,
+ List<JsonQuotedAttachment> attachments
+) {
+
+ static JsonQuote from(SignalServiceDataMessage.Quote quote, Manager m) {
+ final var id = quote.getId();
final var address = m.resolveSignalServiceAddress(quote.getAuthor());
- this.author = getLegacyIdentifier(address);
- this.authorNumber = address.getNumber().orNull();
- this.authorUuid = address.getUuid().toString();
- this.text = quote.getText();
+ final var author = getLegacyIdentifier(address);
+ final var authorNumber = address.getNumber().orNull();
+ final var authorUuid = address.getUuid().toString();
+ final var text = quote.getText();
+ final List<JsonMention> mentions;
if (quote.getMentions() != null && quote.getMentions().size() > 0) {
- this.mentions = quote.getMentions()
+ mentions = quote.getMentions()
.stream()
- .map(quotedMention -> new JsonMention(quotedMention, m))
+ .map(quotedMention -> JsonMention.from(quotedMention, m))
.collect(Collectors.toList());
} else {
- this.mentions = null;
+ mentions = null;
}
+ final List<JsonQuotedAttachment> attachments;
if (quote.getAttachments().size() > 0) {
- this.attachments = quote.getAttachments()
- .stream()
- .map(JsonQuotedAttachment::new)
- .collect(Collectors.toList());
+ attachments = quote.getAttachments().stream().map(JsonQuotedAttachment::from).collect(Collectors.toList());
} else {
- this.attachments = new ArrayList<>();
+ attachments = new ArrayList<>();
}
+
+ return new JsonQuote(id, author, authorNumber, authorUuid, text, mentions, attachments);
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
-public class JsonQuotedAttachment {
+public record JsonQuotedAttachment(
+ String contentType, String filename, @JsonInclude(JsonInclude.Include.NON_NULL) JsonAttachment thumbnail
+) {
- @JsonProperty
- final String contentType;
-
- @JsonProperty
- final String filename;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonAttachment thumbnail;
-
- JsonQuotedAttachment(SignalServiceDataMessage.Quote.QuotedAttachment quotedAttachment) {
- contentType = quotedAttachment.getContentType();
- filename = quotedAttachment.getFileName();
+ static JsonQuotedAttachment from(SignalServiceDataMessage.Quote.QuotedAttachment quotedAttachment) {
+ final var contentType = quotedAttachment.getContentType();
+ final var filename = quotedAttachment.getFileName();
+ final JsonAttachment thumbnail;
if (quotedAttachment.getThumbnail() != null) {
- thumbnail = new JsonAttachment(quotedAttachment.getThumbnail());
+ thumbnail = JsonAttachment.from(quotedAttachment.getThumbnail());
} else {
thumbnail = null;
}
+ return new JsonQuotedAttachment(contentType, filename, thumbnail);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.asamk.signal.manager.Manager;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Reaction;
import static org.asamk.signal.util.Util.getLegacyIdentifier;
-public class JsonReaction {
-
- @JsonProperty
- final String emoji;
-
- @JsonProperty
- @Deprecated
- final String targetAuthor;
-
- @JsonProperty
- final String targetAuthorNumber;
-
- @JsonProperty
- final String targetAuthorUuid;
-
- @JsonProperty
- final long targetSentTimestamp;
-
- @JsonProperty
- final boolean isRemove;
-
- JsonReaction(Reaction reaction, Manager m) {
- this.emoji = reaction.getEmoji();
+public record JsonReaction(
+ String emoji,
+ @Deprecated String targetAuthor,
+ String targetAuthorNumber,
+ String targetAuthorUuid,
+ long targetSentTimestamp,
+ boolean isRemove
+) {
+
+ static JsonReaction from(Reaction reaction, Manager m) {
+ final var emoji = reaction.getEmoji();
final var address = m.resolveSignalServiceAddress(reaction.getTargetAuthor());
- this.targetAuthor = getLegacyIdentifier(address);
- this.targetAuthorNumber = address.getNumber().orNull();
- this.targetAuthorUuid = address.getUuid().toString();
- this.targetSentTimestamp = reaction.getTargetSentTimestamp();
- this.isRemove = reaction.isRemove();
+ final var targetAuthor = getLegacyIdentifier(address);
+ final var targetAuthorNumber = address.getNumber().orNull();
+ final var targetAuthorUuid = address.getUuid().toString();
+ final var targetSentTimestamp = reaction.getTargetSentTimestamp();
+ final var isRemove = reaction.isRemove();
+ return new JsonReaction(emoji,
+ targetAuthor,
+ targetAuthorNumber,
+ targetAuthorUuid,
+ targetSentTimestamp,
+ isRemove);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
import java.util.List;
-class JsonReceiptMessage {
-
- @JsonProperty
- final long when;
-
- @JsonProperty
- final boolean isDelivery;
-
- @JsonProperty
- final boolean isRead;
-
- @JsonProperty
- final List<Long> timestamps;
-
- JsonReceiptMessage(SignalServiceReceiptMessage receiptMessage) {
- this.when = receiptMessage.getWhen();
- this.isDelivery = receiptMessage.isDeliveryReceipt();
- this.isRead = receiptMessage.isReadReceipt();
- this.timestamps = receiptMessage.getTimestamps();
- }
+record JsonReceiptMessage(long when, boolean isDelivery, boolean isRead, List<Long> timestamps) {
- private JsonReceiptMessage(
- final long when, final boolean isDelivery, final boolean isRead, final List<Long> timestamps
- ) {
- this.when = when;
- this.isDelivery = isDelivery;
- this.isRead = isRead;
- this.timestamps = timestamps;
+ static JsonReceiptMessage from(SignalServiceReceiptMessage receiptMessage) {
+ final var when = receiptMessage.getWhen();
+ final var isDelivery = receiptMessage.isDeliveryReceipt();
+ final var isRead = receiptMessage.isReadReceipt();
+ final var timestamps = receiptMessage.getTimestamps();
+ return new JsonReceiptMessage(when, isDelivery, isRead, timestamps);
}
static JsonReceiptMessage deliveryReceipt(final long when, final List<Long> timestamps) {
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
-class JsonRemoteDelete {
-
- @JsonProperty
- final long timestamp;
+record JsonRemoteDelete(long timestamp) {
- JsonRemoteDelete(SignalServiceDataMessage.RemoteDelete remoteDelete) {
- this.timestamp = remoteDelete.getTargetSentTimestamp();
+ static JsonRemoteDelete from(SignalServiceDataMessage.RemoteDelete remoteDelete) {
+ return new JsonRemoteDelete(remoteDelete.getTargetSentTimestamp());
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import java.util.List;
import java.util.stream.Collectors;
-public class JsonSharedContact {
-
- @JsonProperty
- final JsonContactName name;
-
- @JsonProperty
- final JsonContactAvatar avatar;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonContactPhone> phone;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonContactEmail> email;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonContactAddress> address;
-
- @JsonProperty
- final String organization;
-
- public JsonSharedContact(SharedContact contact) {
- name = new JsonContactName(contact.getName());
- if (contact.getAvatar().isPresent()) {
- avatar = new JsonContactAvatar(contact.getAvatar().get());
- } else {
- avatar = null;
- }
-
- if (contact.getPhone().isPresent()) {
- phone = contact.getPhone().get().stream().map(JsonContactPhone::new).collect(Collectors.toList());
- } else {
- phone = null;
- }
-
- if (contact.getEmail().isPresent()) {
- email = contact.getEmail().get().stream().map(JsonContactEmail::new).collect(Collectors.toList());
- } else {
- email = null;
- }
-
- if (contact.getAddress().isPresent()) {
- address = contact.getAddress().get().stream().map(JsonContactAddress::new).collect(Collectors.toList());
- } else {
- address = null;
- }
-
- organization = contact.getOrganization().orNull();
+public record JsonSharedContact(
+ JsonContactName name,
+ JsonContactAvatar avatar,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonContactPhone> phone,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonContactEmail> email,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonContactAddress> address,
+ String organization
+) {
+
+ static JsonSharedContact from(SharedContact contact) {
+ final var name = JsonContactName.from(contact.getName());
+ final var avatar = contact.getAvatar().isPresent() ? JsonContactAvatar.from(contact.getAvatar().get()) : null;
+
+ final var phone = contact.getPhone().isPresent() ? contact.getPhone()
+ .get()
+ .stream()
+ .map(JsonContactPhone::from)
+ .collect(Collectors.toList()) : null;
+
+ final var email = contact.getEmail().isPresent() ? contact.getEmail()
+ .get()
+ .stream()
+ .map(JsonContactEmail::from)
+ .collect(Collectors.toList()) : null;
+
+ final var address = contact.getAddress().isPresent() ? contact.getAddress()
+ .get()
+ .stream()
+ .map(JsonContactAddress::from)
+ .collect(Collectors.toList()) : null;
+
+ final var organization = contact.getOrganization().orNull();
+
+ return new JsonSharedContact(name, avatar, phone, email, address, organization);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import java.util.Base64;
-public class JsonSticker {
-
- @JsonProperty
- final String packId;
-
- @JsonProperty
- final String packKey;
-
- @JsonProperty
- final int stickerId;
+public record JsonSticker(String packId, String packKey, int stickerId) {
- public JsonSticker(SignalServiceDataMessage.Sticker sticker) {
- this.packId = Base64.getEncoder().encodeToString(sticker.getPackId());
- this.packKey = Base64.getEncoder().encodeToString(sticker.getPackKey());
- this.stickerId = sticker.getStickerId();
+ static JsonSticker from(SignalServiceDataMessage.Sticker sticker) {
+ final var packId = Base64.getEncoder().encodeToString(sticker.getPackId());
+ final var packKey = Base64.getEncoder().encodeToString(sticker.getPackKey());
+ final var stickerId = sticker.getStickerId();
+ return new JsonSticker(packId, packKey, stickerId);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
import org.asamk.Signal;
import org.asamk.signal.manager.Manager;
import static org.asamk.signal.util.Util.getLegacyIdentifier;
-class JsonSyncDataMessage extends JsonDataMessage {
-
- @JsonProperty
- @Deprecated
- final String destination;
-
- @JsonProperty
- final String destinationNumber;
-
- @JsonProperty
- final String destinationUuid;
-
- JsonSyncDataMessage(SentTranscriptMessage transcriptMessage, Manager m) {
- super(transcriptMessage.getMessage(), m);
+record JsonSyncDataMessage(
+ @Deprecated String destination,
+ String destinationNumber,
+ String destinationUuid,
+ @JsonUnwrapped JsonDataMessage dataMessage
+) {
+ static JsonSyncDataMessage from(SentTranscriptMessage transcriptMessage, Manager m) {
if (transcriptMessage.getDestination().isPresent()) {
final var address = transcriptMessage.getDestination().get();
- this.destination = getLegacyIdentifier(address);
- this.destinationNumber = address.getNumber().orNull();
- this.destinationUuid = address.getUuid().toString();
+ return new JsonSyncDataMessage(getLegacyIdentifier(address),
+ address.getNumber().orNull(),
+ address.getUuid().toString(),
+ JsonDataMessage.from(transcriptMessage.getMessage(), m));
+
} else {
- this.destination = null;
- this.destinationNumber = null;
- this.destinationUuid = null;
+ return new JsonSyncDataMessage(null, null, null, JsonDataMessage.from(transcriptMessage.getMessage(), m));
}
}
- JsonSyncDataMessage(Signal.SyncMessageReceived messageReceived) {
- super(messageReceived);
- this.destination = messageReceived.getDestination();
- this.destinationNumber = null;
- this.destinationUuid = null;
+ static JsonSyncDataMessage from(Signal.SyncMessageReceived messageReceived) {
+ return new JsonSyncDataMessage(messageReceived.getDestination(),
+ null,
+ null,
+ JsonDataMessage.from(messageReceived));
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.asamk.Signal;
import org.asamk.signal.manager.Manager;
REQUEST_SYNC
}
-class JsonSyncMessage {
+record JsonSyncMessage(
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncDataMessage sentMessage,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<String> blockedNumbers,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<String> blockedGroupIds,
+ @JsonInclude(JsonInclude.Include.NON_NULL) List<JsonSyncReadMessage> readMessages,
+ @JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessageType type
+) {
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonSyncDataMessage sentMessage;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<String> blockedNumbers;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<String> blockedGroupIds;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final List<JsonSyncReadMessage> readMessages;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final JsonSyncMessageType type;
+ JsonSyncMessage(
+ final JsonSyncDataMessage sentMessage,
+ final List<String> blockedNumbers,
+ final List<String> blockedGroupIds,
+ final List<JsonSyncReadMessage> readMessages,
+ final JsonSyncMessageType type
+ ) {
+ this.sentMessage = sentMessage;
+ this.blockedNumbers = blockedNumbers;
+ this.blockedGroupIds = blockedGroupIds;
+ this.readMessages = readMessages;
+ this.type = type;
+ }
- JsonSyncMessage(SignalServiceSyncMessage syncMessage, Manager m) {
- this.sentMessage = syncMessage.getSent().isPresent()
- ? new JsonSyncDataMessage(syncMessage.getSent().get(), m)
- : null;
+ static JsonSyncMessage from(SignalServiceSyncMessage syncMessage, Manager m) {
+ final var sentMessage = syncMessage.getSent().isPresent() ? JsonSyncDataMessage.from(syncMessage.getSent()
+ .get(), m) : null;
+ final List<String> blockedNumbers;
+ final List<String> blockedGroupIds;
if (syncMessage.getBlockedList().isPresent()) {
final var base64 = Base64.getEncoder();
- this.blockedNumbers = syncMessage.getBlockedList()
+ blockedNumbers = syncMessage.getBlockedList()
.get()
.getAddresses()
.stream()
.map(Util::getLegacyIdentifier)
.collect(Collectors.toList());
- this.blockedGroupIds = syncMessage.getBlockedList()
+ blockedGroupIds = syncMessage.getBlockedList()
.get()
.getGroupIds()
.stream()
.map(base64::encodeToString)
.collect(Collectors.toList());
} else {
- this.blockedNumbers = null;
- this.blockedGroupIds = null;
- }
- if (syncMessage.getRead().isPresent()) {
- this.readMessages = syncMessage.getRead()
- .get()
- .stream()
- .map(JsonSyncReadMessage::new)
- .collect(Collectors.toList());
- } else {
- this.readMessages = null;
+ blockedNumbers = null;
+ blockedGroupIds = null;
}
+ final var readMessages = syncMessage.getRead().isPresent() ? syncMessage.getRead()
+ .get()
+ .stream()
+ .map(JsonSyncReadMessage::from)
+ .collect(Collectors.toList()) : null;
+
+ final JsonSyncMessageType type;
if (syncMessage.getContacts().isPresent()) {
- this.type = JsonSyncMessageType.CONTACTS_SYNC;
+ type = JsonSyncMessageType.CONTACTS_SYNC;
} else if (syncMessage.getGroups().isPresent()) {
- this.type = JsonSyncMessageType.GROUPS_SYNC;
+ type = JsonSyncMessageType.GROUPS_SYNC;
} else if (syncMessage.getRequest().isPresent()) {
- this.type = JsonSyncMessageType.REQUEST_SYNC;
+ type = JsonSyncMessageType.REQUEST_SYNC;
} else {
- this.type = null;
+ type = null;
}
+ return new JsonSyncMessage(sentMessage, blockedNumbers, blockedGroupIds, readMessages, type);
}
- JsonSyncMessage(Signal.SyncMessageReceived messageReceived) {
- this.sentMessage = new JsonSyncDataMessage(messageReceived);
- this.blockedNumbers = null;
- this.blockedGroupIds = null;
- this.readMessages = null;
- this.type = null;
+ static JsonSyncMessage from(Signal.SyncMessageReceived messageReceived) {
+ return new JsonSyncMessage(JsonSyncDataMessage.from(messageReceived), null, null, null, null);
}
}
package org.asamk.signal.json;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
import static org.asamk.signal.util.Util.getLegacyIdentifier;
-class JsonSyncReadMessage {
-
- @JsonProperty
- @Deprecated
- final String sender;
-
- @JsonProperty
- final String senderNumber;
-
- @JsonProperty
- final String senderUuid;
-
- @JsonProperty
- final long timestamp;
-
- public JsonSyncReadMessage(final ReadMessage readMessage) {
- final var sender = readMessage.getSender();
- this.sender = getLegacyIdentifier(sender);
- this.senderNumber = sender.getNumber().orNull();
- this.senderUuid = sender.getUuid().toString();
- this.timestamp = readMessage.getTimestamp();
+record JsonSyncReadMessage(
+ @Deprecated String sender, String senderNumber, String senderUuid, long timestamp
+) {
+
+ static JsonSyncReadMessage from(final ReadMessage readMessage) {
+ final var senderAddress = readMessage.getSender();
+ final var sender = getLegacyIdentifier(senderAddress);
+ final var senderNumber = senderAddress.getNumber().orNull();
+ final var senderUuid = senderAddress.getUuid().toString();
+ final var timestamp = readMessage.getTimestamp();
+ return new JsonSyncReadMessage(sender, senderNumber, senderUuid, timestamp);
}
}
package org.asamk.signal.json;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
import java.util.Base64;
-class JsonTypingMessage {
+record JsonTypingMessage(
+ String action, long timestamp, @JsonInclude(JsonInclude.Include.NON_NULL) String groupId
+) {
- @JsonProperty
- final String action;
-
- @JsonProperty
- final long timestamp;
-
- @JsonProperty
- @JsonInclude(JsonInclude.Include.NON_NULL)
- final String groupId;
+ JsonTypingMessage(final String action, final long timestamp, final String groupId) {
+ this.action = action;
+ this.timestamp = timestamp;
+ this.groupId = groupId;
+ }
- JsonTypingMessage(SignalServiceTypingMessage typingMessage) {
- this.action = typingMessage.getAction().name();
- this.timestamp = typingMessage.getTimestamp();
+ static JsonTypingMessage from(SignalServiceTypingMessage typingMessage) {
+ final var action = typingMessage.getAction().name();
+ final var timestamp = typingMessage.getTimestamp();
final var encoder = Base64.getEncoder();
- this.groupId = typingMessage.getGroupId().transform(encoder::encodeToString).orNull();
+ final var groupId = typingMessage.getGroupId().transform(encoder::encodeToString).orNull();
+ return new JsonTypingMessage(action, timestamp, groupId);
}
}