mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-28 18:10:38 +00:00
Use record classes
This commit is contained in:
parent
ce70a623c2
commit
ce7aa580b6
66 changed files with 754 additions and 1877 deletions
7
.idea/codeStyles/Project.xml
generated
7
.idea/codeStyles/Project.xml
generated
|
@ -26,14 +26,14 @@
|
|||
<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" />
|
||||
|
@ -52,6 +52,7 @@
|
|||
<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">
|
||||
|
|
|
@ -15,6 +15,7 @@ repositories {
|
|||
|
||||
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")
|
||||
|
|
|
@ -15,10 +15,7 @@ import java.util.Map;
|
|||
|
||||
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();
|
||||
|
@ -57,11 +54,6 @@ public class DeviceLinkInfo {
|
|||
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 {
|
||||
|
|
|
@ -1,55 +1,8 @@
|
|||
package org.asamk.signal.manager;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JsonStickerPack {
|
||||
public record JsonStickerPack(String title, String author, JsonSticker cover, List<JsonSticker> stickers) {
|
||||
|
||||
@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 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) {}
|
||||
}
|
||||
|
|
|
@ -57,11 +57,11 @@ public interface Manager extends Closeable {
|
|||
) 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();
|
||||
|
@ -74,7 +74,7 @@ public interface Manager extends Closeable {
|
|||
|
||||
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) {
|
||||
|
|
|
@ -169,9 +169,9 @@ public class ManagerImpl implements Manager {
|
|||
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());
|
||||
|
@ -426,7 +426,7 @@ public class ManagerImpl implements Manager {
|
|||
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 {
|
||||
|
@ -642,8 +642,8 @@ public class ManagerImpl implements Manager {
|
|||
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));
|
||||
}
|
||||
|
|
|
@ -2,12 +2,9 @@ package org.asamk.signal.manager;
|
|||
|
||||
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"),
|
||||
|
@ -15,29 +12,4 @@ public class PathConfig {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,8 +95,8 @@ public class ProvisioningManager {
|
|||
|
||||
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
|
||||
|
@ -115,7 +115,7 @@ public class ProvisioningManager {
|
|||
|
||||
SignalAccount account = null;
|
||||
try {
|
||||
account = SignalAccount.createOrUpdateLinkedAccount(pathConfig.getDataPath(),
|
||||
account = SignalAccount.createOrUpdateLinkedAccount(pathConfig.dataPath(),
|
||||
number,
|
||||
ret.getUuid(),
|
||||
password,
|
||||
|
@ -165,7 +165,7 @@ public class ProvisioningManager {
|
|||
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;
|
||||
|
|
|
@ -96,12 +96,12 @@ public class RegistrationManager implements Closeable {
|
|||
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,
|
||||
|
@ -111,7 +111,7 @@ public class RegistrationManager implements Closeable {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1,38 +1,3 @@
|
|||
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) {}
|
||||
|
|
|
@ -7,116 +7,20 @@ import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
|||
|
||||
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
|
||||
) {}
|
||||
|
|
|
@ -6,60 +6,16 @@ import org.whispersystems.libsignal.IdentityKey;
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,4 @@ package org.asamk.signal.manager.api;
|
|||
|
||||
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) {}
|
||||
|
|
|
@ -4,23 +4,4 @@ import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
|||
|
||||
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) {}
|
||||
|
|
|
@ -5,23 +5,4 @@ import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
|||
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) {}
|
||||
|
|
|
@ -62,29 +62,9 @@ public class ConfigurationStore {
|
|||
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 {
|
||||
|
||||
|
|
|
@ -262,7 +262,7 @@ public class GroupStore {
|
|||
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()));
|
||||
}
|
||||
|
||||
|
@ -274,91 +274,22 @@ public class GroupStore {
|
|||
}).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() {
|
||||
}
|
||||
private record Member(Long recipientId, String uuid, String number) {}
|
||||
|
||||
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;
|
||||
|
||||
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>> {
|
||||
|
||||
|
@ -366,7 +297,7 @@ public class GroupStore {
|
|||
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);
|
||||
|
@ -404,39 +335,19 @@ public class GroupStore {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -185,7 +185,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
|
|||
} 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) {
|
||||
|
@ -203,9 +203,9 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
|
|||
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);
|
||||
|
@ -251,32 +251,5 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
|
|||
}
|
||||
}
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public class MessageCache {
|
|||
return messageCachePath;
|
||||
}
|
||||
|
||||
var sender = String.valueOf(recipientId.getId());
|
||||
var sender = String.valueOf(recipientId.id());
|
||||
return new File(messageCachePath, sender.replace("/", "_"));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,38 +1,8 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -453,7 +453,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
|
|||
.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
|
||||
|
@ -479,115 +479,32 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
|
|||
}
|
||||
}
|
||||
|
||||
private static class Storage {
|
||||
private record Storage(List<Recipient> recipients, long lastId) {
|
||||
|
||||
public List<Recipient> recipients;
|
||||
private record Recipient(
|
||||
long id,
|
||||
String number,
|
||||
String uuid,
|
||||
String profileKey,
|
||||
String profileKeyCredential,
|
||||
Storage.Recipient.Contact contact,
|
||||
Storage.Recipient.Profile profile
|
||||
) {
|
||||
|
||||
public long lastId;
|
||||
private record Contact(
|
||||
String name, String color, int messageExpirationTime, boolean blocked, boolean archived
|
||||
) {}
|
||||
|
||||
// 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 Profile(
|
||||
long lastUpdateTimestamp,
|
||||
String givenName,
|
||||
String familyName,
|
||||
String about,
|
||||
String aboutEmoji,
|
||||
String avatarUrlPath,
|
||||
String unidentifiedAccessMode,
|
||||
Set<String> capabilities
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ public class SenderKeyRecordStore implements org.whispersystems.libsignal.groups
|
|||
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;
|
||||
|
@ -126,7 +126,7 @@ public class SenderKeyRecordStore implements org.whispersystems.libsignal.groups
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ public class SenderKeyRecordStore implements org.whispersystems.libsignal.groups
|
|||
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) {
|
||||
|
@ -212,50 +212,7 @@ public class SenderKeyRecordStore implements org.whispersystems.libsignal.groups
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,8 +87,8 @@ public class SenderKeySharedStore {
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ public class SenderKeySharedStore {
|
|||
|
||||
sharedSenderKeys.put(distributionId, new HashSet<>(entries) {
|
||||
{
|
||||
entries.removeIf(e -> e.getRecipientId().equals(recipientId));
|
||||
removeIf(e -> e.recipientId().equals(recipientId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ public class SenderKeySharedStore {
|
|||
entries.stream()
|
||||
.map(e -> e.recipientId.equals(toBeMergedRecipientId) ? new SenderKeySharedEntry(
|
||||
recipientId,
|
||||
e.getDeviceId()) : e)
|
||||
e.deviceId()) : e)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
saveLocked();
|
||||
|
@ -181,8 +181,8 @@ public class SenderKeySharedStore {
|
|||
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()));
|
||||
|
||||
|
@ -199,72 +199,10 @@ public class SenderKeySharedStore {
|
|||
}
|
||||
}
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
|
|
@ -88,8 +88,8 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
.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());
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
if (session == null) {
|
||||
continue;
|
||||
}
|
||||
final var newKey = new Key(recipientId, key.getDeviceId());
|
||||
final var newKey = new Key(recipientId, key.deviceId());
|
||||
storeSessionLocked(newKey, session);
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
} 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) {
|
||||
|
@ -324,40 +324,5 @@ public class SessionStore implements SignalServiceSessionStore {
|
|||
&& 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) {}
|
||||
}
|
||||
|
|
|
@ -65,33 +65,10 @@ public class StickerStore {
|
|||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,60 +35,59 @@ public class StickerUtils {
|
|||
|
||||
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 {
|
||||
|
|
|
@ -26,11 +26,11 @@ public class JsonReceiveMessageHandler implements Manager.ReceiveMessageHandler
|
|||
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);
|
||||
|
|
|
@ -643,7 +643,7 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
|||
|
||||
var group = m.getGroup(groupId);
|
||||
if (group != null) {
|
||||
writer.println("Name: {}", group.getTitle());
|
||||
writer.println("Name: {}", group.title());
|
||||
} else {
|
||||
writer.println("Name: <Unknown group>");
|
||||
}
|
||||
|
|
|
@ -66,21 +66,5 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand {
|
|||
}
|
||||
}
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class JoinGroupCommand implements JsonRpcLocalCommand {
|
|||
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) {
|
||||
|
|
|
@ -16,8 +16,7 @@ import java.util.Map;
|
|||
public interface JsonRpcLocalCommand extends JsonRpcCommand<Map<String, Object>>, LocalCommand {
|
||||
|
||||
default TypeReference<Map<String, Object>> getRequestType() {
|
||||
return new TypeReference<>() {
|
||||
};
|
||||
return new TypeReference<>() {};
|
||||
}
|
||||
|
||||
default void handleCommand(
|
||||
|
|
|
@ -54,26 +54,5 @@ public class ListContactsCommand implements JsonRpcLocalCommand {
|
|||
}
|
||||
}
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
|
|
@ -45,36 +45,21 @@ public class ListDevicesCommand implements JsonRpcLocalCommand {
|
|||
|
||||
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) {}
|
||||
}
|
||||
|
|
|
@ -50,25 +50,25 @@ public class ListGroupsCommand implements JsonRpcLocalCommand {
|
|||
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());
|
||||
}
|
||||
|
@ -83,21 +83,21 @@ public class ListGroupsCommand implements JsonRpcLocalCommand {
|
|||
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());
|
||||
|
||||
|
@ -111,66 +111,22 @@ public class ListGroupsCommand implements JsonRpcLocalCommand {
|
|||
}
|
||||
}
|
||||
|
||||
private static final class JsonGroup {
|
||||
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
|
||||
) {}
|
||||
|
||||
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 JsonGroupMember(String number, String uuid) {}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,12 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand {
|
|||
} 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()),
|
||||
|
@ -76,40 +76,21 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand {
|
|||
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
|
||||
) {}
|
||||
}
|
||||
|
|
|
@ -55,9 +55,9 @@ public class QuitGroupCommand implements JsonRpcLocalCommand {
|
|||
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");
|
||||
}
|
||||
|
|
|
@ -61,19 +61,19 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
|
|||
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);
|
||||
});
|
||||
|
|
|
@ -56,8 +56,8 @@ public class RemoteDeleteCommand implements JsonRpcLocalCommand {
|
|||
|
||||
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) {
|
||||
|
|
|
@ -102,8 +102,8 @@ public class SendCommand implements JsonRpcLocalCommand {
|
|||
|
||||
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);
|
||||
|
|
|
@ -72,8 +72,8 @@ public class SendReactionCommand implements JsonRpcLocalCommand {
|
|||
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) {
|
||||
|
|
|
@ -127,8 +127,8 @@ public class UpdateGroupCommand implements JsonRpcLocalCommand {
|
|||
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;
|
||||
|
@ -154,8 +154,8 @@ public class UpdateGroupCommand implements JsonRpcLocalCommand {
|
|||
: 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) {
|
||||
|
|
|
@ -321,9 +321,9 @@ public class DbusManagerImpl implements Manager {
|
|||
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
|
||||
|
|
|
@ -153,8 +153,8 @@ public class DbusSignalImpl implements Signal {
|
|||
.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) {
|
||||
|
@ -182,8 +182,8 @@ public class DbusSignalImpl implements Signal {
|
|||
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) {
|
||||
|
@ -198,8 +198,8 @@ public class DbusSignalImpl implements Signal {
|
|||
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) {
|
||||
|
@ -236,8 +236,8 @@ public class DbusSignalImpl implements Signal {
|
|||
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) {
|
||||
|
@ -303,8 +303,8 @@ public class DbusSignalImpl implements Signal {
|
|||
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) {
|
||||
|
@ -318,7 +318,7 @@ public class DbusSignalImpl implements Signal {
|
|||
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());
|
||||
}
|
||||
|
@ -329,8 +329,8 @@ public class DbusSignalImpl implements Signal {
|
|||
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) {
|
||||
|
@ -354,8 +354,8 @@ public class DbusSignalImpl implements Signal {
|
|||
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) {
|
||||
|
@ -420,7 +420,7 @@ public class DbusSignalImpl implements Signal {
|
|||
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;
|
||||
}
|
||||
|
@ -444,10 +444,10 @@ public class DbusSignalImpl implements Signal {
|
|||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,7 +457,7 @@ public class DbusSignalImpl implements Signal {
|
|||
if (group == null) {
|
||||
return List.of();
|
||||
} else {
|
||||
final var members = group.getMembers();
|
||||
final var members = group.members();
|
||||
return getRecipientStrings(members);
|
||||
}
|
||||
}
|
||||
|
@ -478,7 +478,7 @@ public class DbusSignalImpl implements Signal {
|
|||
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),
|
||||
|
@ -488,7 +488,7 @@ public class DbusSignalImpl implements Signal {
|
|||
.withAvatarFile(avatar == null ? null : new File(avatar))
|
||||
.build());
|
||||
if (results != null) {
|
||||
checkSendMessageResults(results.getTimestamp(), results.getResults());
|
||||
checkSendMessageResults(results.timestamp(), results.results());
|
||||
}
|
||||
return groupId;
|
||||
}
|
||||
|
@ -600,8 +600,8 @@ public class DbusSignalImpl implements Signal {
|
|||
// 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()
|
||||
|
@ -620,7 +620,7 @@ public class DbusSignalImpl implements Signal {
|
|||
}
|
||||
// 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;
|
||||
|
@ -835,7 +835,7 @@ public class DbusSignalImpl implements Signal {
|
|||
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())));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -862,15 +862,15 @@ public class DbusSignalImpl implements Signal {
|
|||
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())));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -885,22 +885,22 @@ public class DbusSignalImpl implements Signal {
|
|||
|
||||
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());
|
||||
|
@ -929,36 +929,36 @@ public class DbusSignalImpl implements Signal {
|
|||
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();
|
||||
}))));
|
||||
}
|
||||
|
|
|
@ -1,43 +1,25 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -12,33 +11,19 @@ import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMess
|
|||
|
||||
import java.util.List;
|
||||
|
||||
class JsonCallMessage {
|
||||
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
|
||||
) {
|
||||
|
||||
@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();
|
||||
static JsonCallMessage from(SignalServiceCallMessage callMessage) {
|
||||
return new JsonCallMessage(callMessage.getOfferMessage().orNull(),
|
||||
callMessage.getAnswerMessage().orNull(),
|
||||
callMessage.getBusyMessage().orNull(),
|
||||
callMessage.getHangupMessage().orNull(),
|
||||
callMessage.getIceUpdateMessages().orNull());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,48 +1,29 @@
|
|||
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 {
|
||||
public record JsonContactAddress(
|
||||
SharedContact.PostalAddress.Type type,
|
||||
String label,
|
||||
String street,
|
||||
String pobox,
|
||||
String neighborhood,
|
||||
String city,
|
||||
String region,
|
||||
String postcode,
|
||||
String country
|
||||
) {
|
||||
|
||||
@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());
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
package org.asamk.signal.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
|
||||
public class JsonContactAvatar {
|
||||
public record JsonContactAvatar(JsonAttachment attachment, boolean isProfile) {
|
||||
|
||||
@JsonProperty
|
||||
private final JsonAttachment attachment;
|
||||
|
||||
@JsonProperty
|
||||
private final 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,11 @@
|
|||
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 {
|
||||
public record JsonContactEmail(String value, SharedContact.Email.Type type, String label) {
|
||||
|
||||
@JsonProperty
|
||||
private final String value;
|
||||
|
||||
@JsonProperty
|
||||
private final SharedContact.Email.Type type;
|
||||
|
||||
@JsonProperty
|
||||
private final 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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,18 @@
|
|||
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 {
|
||||
public record JsonContactName(
|
||||
String display, String given, String family, String prefix, String suffix, String middle
|
||||
) {
|
||||
|
||||
@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());
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,11 @@
|
|||
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 {
|
||||
public record JsonContactPhone(String value, SharedContact.Phone.Type type, String label) {
|
||||
|
||||
@JsonProperty
|
||||
private final String value;
|
||||
|
||||
@JsonProperty
|
||||
private final SharedContact.Phone.Type type;
|
||||
|
||||
@JsonProperty
|
||||
private final 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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -10,136 +9,124 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class JsonDataMessage {
|
||||
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
|
||||
) {
|
||||
|
||||
@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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -12,48 +11,32 @@ import java.util.Base64;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class JsonGroupInfo {
|
||||
record JsonGroupInfo(
|
||||
String groupId,
|
||||
String type,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) String name,
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) List<String> members
|
||||
) {
|
||||
|
||||
@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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,19 @@
|
|||
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 {
|
||||
public record JsonMention(@Deprecated String name, String number, String uuid, int start, int length) {
|
||||
|
||||
@JsonProperty
|
||||
@Deprecated
|
||||
final String name;
|
||||
|
||||
@JsonProperty
|
||||
final String number;
|
||||
|
||||
@JsonProperty
|
||||
final String uuid;
|
||||
|
||||
@JsonProperty
|
||||
final int start;
|
||||
|
||||
@JsonProperty
|
||||
final 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -15,143 +14,133 @@ import java.util.List;
|
|||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
public class 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
|
||||
) {
|
||||
|
||||
@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 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())
|
||||
final var typingMessage = content != null && content.getTypingMessage().isPresent() ? JsonTypingMessage.from(
|
||||
content.getTypingMessage().get()) : null;
|
||||
|
||||
final var dataMessage = content != null && content.getDataMessage().isPresent()
|
||||
? JsonDataMessage.from(content.getDataMessage().get(), m)
|
||||
: null;
|
||||
final var syncMessage = content != null && content.getSyncMessage().isPresent()
|
||||
? JsonSyncMessage.from(content.getSyncMessage().get(), m)
|
||||
: null;
|
||||
final var callMessage = content != null && content.getCallMessage().isPresent()
|
||||
? JsonCallMessage.from(content.getCallMessage().get())
|
||||
: null;
|
||||
|
||||
this.dataMessage = content != null && content.getDataMessage().isPresent()
|
||||
? new JsonDataMessage(content.getDataMessage().get(), m)
|
||||
: null;
|
||||
this.syncMessage = content != null && content.getSyncMessage().isPresent()
|
||||
? new JsonSyncMessage(content.getSyncMessage().get(), m)
|
||||
: null;
|
||||
this.callMessage = content != null && content.getCallMessage().isPresent()
|
||||
? new JsonCallMessage(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -12,55 +11,41 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.asamk.signal.util.Util.getLegacyIdentifier;
|
||||
|
||||
public class JsonQuote {
|
||||
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
|
||||
) {
|
||||
|
||||
@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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,22 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,32 @@
|
|||
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 {
|
||||
public record JsonReaction(
|
||||
String emoji,
|
||||
@Deprecated String targetAuthor,
|
||||
String targetAuthorNumber,
|
||||
String targetAuthorUuid,
|
||||
long targetSentTimestamp,
|
||||
boolean isRemove
|
||||
) {
|
||||
|
||||
@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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,17 @@
|
|||
package org.asamk.signal.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class JsonReceiptMessage {
|
||||
record JsonReceiptMessage(long when, boolean isDelivery, boolean isRead, List<Long> timestamps) {
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
package org.asamk.signal.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
|
||||
class JsonRemoteDelete {
|
||||
record JsonRemoteDelete(long timestamp) {
|
||||
|
||||
@JsonProperty
|
||||
final long timestamp;
|
||||
|
||||
JsonRemoteDelete(SignalServiceDataMessage.RemoteDelete remoteDelete) {
|
||||
this.timestamp = remoteDelete.getTargetSentTimestamp();
|
||||
static JsonRemoteDelete from(SignalServiceDataMessage.RemoteDelete remoteDelete) {
|
||||
return new JsonRemoteDelete(remoteDelete.getTargetSentTimestamp());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,62 +1,45 @@
|
|||
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 {
|
||||
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
|
||||
) {
|
||||
|
||||
@JsonProperty
|
||||
final JsonContactName name;
|
||||
static JsonSharedContact from(SharedContact contact) {
|
||||
final var name = JsonContactName.from(contact.getName());
|
||||
final var avatar = contact.getAvatar().isPresent() ? JsonContactAvatar.from(contact.getAvatar().get()) : null;
|
||||
|
||||
@JsonProperty
|
||||
final JsonContactAvatar avatar;
|
||||
final var phone = contact.getPhone().isPresent() ? contact.getPhone()
|
||||
.get()
|
||||
.stream()
|
||||
.map(JsonContactPhone::from)
|
||||
.collect(Collectors.toList()) : null;
|
||||
|
||||
@JsonProperty
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
final List<JsonContactPhone> phone;
|
||||
final var email = contact.getEmail().isPresent() ? contact.getEmail()
|
||||
.get()
|
||||
.stream()
|
||||
.map(JsonContactEmail::from)
|
||||
.collect(Collectors.toList()) : null;
|
||||
|
||||
@JsonProperty
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
final List<JsonContactEmail> email;
|
||||
final var address = contact.getAddress().isPresent() ? contact.getAddress()
|
||||
.get()
|
||||
.stream()
|
||||
.map(JsonContactAddress::from)
|
||||
.collect(Collectors.toList()) : null;
|
||||
|
||||
@JsonProperty
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
final List<JsonContactAddress> address;
|
||||
final var organization = contact.getOrganization().orNull();
|
||||
|
||||
@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();
|
||||
return new JsonSharedContact(name, avatar, phone, email, address, organization);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,15 @@
|
|||
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 {
|
||||
public record JsonSticker(String packId, String packKey, int stickerId) {
|
||||
|
||||
@JsonProperty
|
||||
final String packId;
|
||||
|
||||
@JsonProperty
|
||||
final String packKey;
|
||||
|
||||
@JsonProperty
|
||||
final 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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;
|
||||
|
@ -8,37 +8,30 @@ import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptM
|
|||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
@ -18,76 +17,72 @@ enum JsonSyncMessageType {
|
|||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@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(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,19 @@
|
|||
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 {
|
||||
record JsonSyncReadMessage(
|
||||
@Deprecated String sender, String senderNumber, String senderUuid, long timestamp
|
||||
) {
|
||||
|
||||
@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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
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;
|
||||
JsonTypingMessage(final String action, final long timestamp, final String groupId) {
|
||||
this.action = action;
|
||||
this.timestamp = timestamp;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
final long timestamp;
|
||||
|
||||
@JsonProperty
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
final String 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue