mirror of
https://github.com/AsamK/signal-cli.git
synced 2026-08-29 06:06:22 +00:00
Update libsignal-service
This commit is contained in:
parent
81e513d6b7
commit
d2f5696df1
@ -4,7 +4,7 @@ coroutines = "1.10.2"
|
||||
junit = "6.1.2"
|
||||
micronaut-json-schema = "2.1.0"
|
||||
micronaut-core = "5.1.10"
|
||||
signal-service = "2.15.3_unofficial_151"
|
||||
signal-service = "2.15.3_unofficial_152"
|
||||
|
||||
[libraries]
|
||||
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.85"
|
||||
|
||||
@ -15,6 +15,7 @@ public record Contact(
|
||||
long muteUntil,
|
||||
boolean hideStory,
|
||||
boolean isBlocked,
|
||||
long blockedAt,
|
||||
boolean isArchived,
|
||||
boolean isProfileSharingEnabled,
|
||||
boolean isHidden,
|
||||
@ -34,6 +35,7 @@ public record Contact(
|
||||
builder.muteUntil,
|
||||
builder.hideStory,
|
||||
builder.isBlocked,
|
||||
builder.blockedAt,
|
||||
builder.isArchived,
|
||||
builder.isProfileSharingEnabled,
|
||||
builder.isHidden,
|
||||
@ -58,6 +60,7 @@ public record Contact(
|
||||
builder.muteUntil = copy.muteUntil();
|
||||
builder.hideStory = copy.hideStory();
|
||||
builder.isBlocked = copy.isBlocked();
|
||||
builder.blockedAt = copy.blockedAt();
|
||||
builder.isArchived = copy.isArchived();
|
||||
builder.isProfileSharingEnabled = copy.isProfileSharingEnabled();
|
||||
builder.isHidden = copy.isHidden();
|
||||
@ -109,6 +112,7 @@ public record Contact(
|
||||
private long muteUntil;
|
||||
private boolean hideStory;
|
||||
private boolean isBlocked;
|
||||
private long blockedAt;
|
||||
private boolean isArchived;
|
||||
private boolean isProfileSharingEnabled;
|
||||
private boolean isHidden;
|
||||
@ -177,10 +181,20 @@ public record Contact(
|
||||
}
|
||||
|
||||
public Builder withIsBlocked(final boolean val) {
|
||||
if (val && !isBlocked) {
|
||||
blockedAt = System.currentTimeMillis();
|
||||
} else if (!val) {
|
||||
blockedAt = 0;
|
||||
}
|
||||
isBlocked = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withBlockedAt(final long val) {
|
||||
blockedAt = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withIsArchived(final boolean val) {
|
||||
isArchived = val;
|
||||
return this;
|
||||
|
||||
@ -739,7 +739,10 @@ public record MessageEnvelope(
|
||||
null,
|
||||
d.getE164(),
|
||||
null))
|
||||
.toList(), blockedListMessage.groupIds.stream().map(GroupId::unknownVersion).toList());
|
||||
.toList(),
|
||||
blockedListMessage.groups.stream()
|
||||
.map(group -> GroupId.unknownVersion(group.getGroupId()))
|
||||
.toList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,7 +32,13 @@ public class ServiceConfig {
|
||||
final var attachmentBackfill = !isPrimaryDevice;
|
||||
final var spqr = true;
|
||||
final var usernameSyncChangeMessage = !isPrimaryDevice;
|
||||
return new AccountAttributes.Capabilities(true, true, attachmentBackfill, spqr, usernameSyncChangeMessage);
|
||||
final var optionalPhoneNumber = !isPrimaryDevice;
|
||||
return new AccountAttributes.Capabilities(true,
|
||||
true,
|
||||
attachmentBackfill,
|
||||
spqr,
|
||||
usernameSyncChangeMessage,
|
||||
optionalPhoneNumber);
|
||||
}
|
||||
|
||||
public static ServiceEnvironmentConfig getServiceEnvironmentConfig(
|
||||
|
||||
@ -50,6 +50,7 @@ import org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevic
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -399,13 +400,17 @@ public class AccountHelper {
|
||||
}
|
||||
|
||||
private void reserveUsername(final List<Username> candidates) throws IOException {
|
||||
final var candidateHashes = new ArrayList<String>();
|
||||
final var candidateHashes = new ArrayList<byte[]>();
|
||||
for (final var candidate : candidates) {
|
||||
candidateHashes.add(Base64.encodeUrlSafeWithoutPadding(candidate.getHash()));
|
||||
candidateHashes.add(candidate.getHash());
|
||||
}
|
||||
|
||||
final var response = handleResponseException(dependencies.getAccountApi().reserveUsername(candidateHashes));
|
||||
final var hashIndex = candidateHashes.indexOf(response.getUsernameHash());
|
||||
final var usernameHash = handleResponseException(dependencies.getAccountApi().reserveUsername(candidateHashes));
|
||||
final var hashIndex = candidateHashes.stream()
|
||||
.filter(candidateHash -> Arrays.equals(candidateHash, usernameHash))
|
||||
.findFirst()
|
||||
.map(candidateHashes::indexOf)
|
||||
.orElse(-1);
|
||||
if (hashIndex == -1) {
|
||||
logger.warn("[reserveUsername] The response hash could not be found in our set of candidateHashes.");
|
||||
throw new IOException("Unexpected username response");
|
||||
@ -498,8 +503,7 @@ public class AccountHelper {
|
||||
final var usernameLink = account.getUsernameLink();
|
||||
|
||||
if (usernameLink == null) {
|
||||
handleResponseException(dependencies.getAccountApi()
|
||||
.reserveUsername(List.of(Base64.encodeUrlSafeWithoutPadding(username.getHash()))));
|
||||
handleResponseException(dependencies.getAccountApi().reserveUsername(List.of(username.getHash())));
|
||||
logger.debug("[reserveUsername] Successfully reserved existing username.");
|
||||
final var linkComponents = confirmUsernameAndCreateNewLink(username);
|
||||
account.setUsernameLink(linkComponents);
|
||||
@ -534,19 +538,19 @@ public class AccountHelper {
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
final var encryptedDeviceName = getEncryptedDeviceName(deviceName);
|
||||
account.setEncryptedDeviceName(encryptedDeviceName);
|
||||
account.setEncryptedDeviceName(Base64.encodeWithoutPadding(encryptedDeviceName));
|
||||
}
|
||||
|
||||
public void setDeviceName(int deviceId, String deviceName) throws IOException {
|
||||
final var encryptedDeviceName = getEncryptedDeviceName(deviceName);
|
||||
handleResponseException(dependencies.getLinkDeviceApi().setDeviceName(encryptedDeviceName, deviceId));
|
||||
handleResponseExceptionSuspend(cont -> dependencies.getLinkDeviceApi()
|
||||
.setDeviceName(encryptedDeviceName, deviceId, cont));
|
||||
context.getSyncHelper().sendDeviceNameChange(deviceId);
|
||||
}
|
||||
|
||||
private String getEncryptedDeviceName(final String deviceName) {
|
||||
private byte[] getEncryptedDeviceName(final String deviceName) {
|
||||
final var identityKey = account.getAciIdentityKeyPair();
|
||||
return Base64.encodeWithoutPadding(DeviceNameCipher.encryptDeviceName(deviceName.getBytes(StandardCharsets.UTF_8),
|
||||
identityKey));
|
||||
return DeviceNameCipher.encryptDeviceName(deviceName.getBytes(StandardCharsets.UTF_8), identityKey);
|
||||
}
|
||||
|
||||
public void refreshDeviceName() throws IOException {
|
||||
@ -585,7 +589,8 @@ public class AccountHelper {
|
||||
account.getOrCreatePinMasterKey(),
|
||||
account.getOrCreateMediaRootBackupKey(),
|
||||
verificationCode.getVerificationCode(),
|
||||
null));
|
||||
null,
|
||||
account.getAuthCredentialSalt()));
|
||||
account.setMultiDevice(true);
|
||||
context.getJobExecutor().enqueueJob(new SyncStorageJob());
|
||||
}
|
||||
@ -601,16 +606,14 @@ public class AccountHelper {
|
||||
var masterKey = account.getOrCreatePinMasterKey();
|
||||
|
||||
context.getPinHelper().migrateRegistrationLockPin(account.getRegistrationLockPin(), masterKey);
|
||||
handleResponseException(dependencies.getAccountApi()
|
||||
.enableRegistrationLock(masterKey.deriveRegistrationLock()));
|
||||
handleResponseException(dependencies.getAccountApi().enableRegistrationLock(masterKey));
|
||||
}
|
||||
|
||||
public void setRegistrationPin(String pin) throws IOException {
|
||||
var masterKey = account.getOrCreatePinMasterKey();
|
||||
|
||||
context.getPinHelper().setRegistrationLockPin(pin, masterKey);
|
||||
handleResponseException(dependencies.getAccountApi()
|
||||
.enableRegistrationLock(masterKey.deriveRegistrationLock()));
|
||||
handleResponseException(dependencies.getAccountApi().enableRegistrationLock(masterKey));
|
||||
|
||||
account.setRegistrationLockPin(pin);
|
||||
updateAccountAttributes();
|
||||
|
||||
@ -85,12 +85,18 @@ public class ContactHelper {
|
||||
}
|
||||
|
||||
public void setContactBlocked(RecipientId recipientId, boolean blocked) {
|
||||
setContactBlocked(recipientId, blocked, blocked ? System.currentTimeMillis() : 0);
|
||||
}
|
||||
|
||||
public void setContactBlocked(RecipientId recipientId, boolean blocked, long blockedAt) {
|
||||
var contact = account.getContactStore().getContact(recipientId);
|
||||
final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
|
||||
if (blocked) {
|
||||
builder.withIsProfileSharingEnabled(false);
|
||||
}
|
||||
account.getContactStore().storeContact(recipientId, builder.withIsBlocked(blocked).build());
|
||||
account.getContactStore()
|
||||
.storeContact(recipientId,
|
||||
builder.withIsBlocked(blocked).withBlockedAt(blocked ? blockedAt : 0).build());
|
||||
}
|
||||
|
||||
public void setContactProfileSharing(RecipientId recipientId, boolean profileSharing) {
|
||||
|
||||
@ -459,12 +459,21 @@ public class GroupHelper {
|
||||
}
|
||||
|
||||
public void setGroupBlocked(final GroupId groupId, final boolean blocked) throws GroupNotFoundException {
|
||||
setGroupBlocked(groupId, blocked, blocked ? System.currentTimeMillis() : 0);
|
||||
}
|
||||
|
||||
public void setGroupBlocked(
|
||||
final GroupId groupId,
|
||||
final boolean blocked,
|
||||
final long blockedAt
|
||||
) throws GroupNotFoundException {
|
||||
var group = getGroup(groupId);
|
||||
if (group == null) {
|
||||
throw new GroupNotFoundException(groupId);
|
||||
}
|
||||
|
||||
group.setBlocked(blocked);
|
||||
group.setBlockedAt(blocked ? blockedAt : 0);
|
||||
account.getGroupStore().updateGroup(group);
|
||||
context.getJobExecutor().enqueueJob(new SyncStorageJob());
|
||||
}
|
||||
|
||||
@ -626,13 +626,12 @@ public final class IncomingMessageHandler {
|
||||
for (var individual : blockedListMessage.individuals) {
|
||||
final var address = new RecipientAddress(individual.getAci(), individual.getE164());
|
||||
final var recipientId = account.getRecipientResolver().resolveRecipient(address);
|
||||
context.getContactHelper().setContactBlocked(recipientId, true);
|
||||
context.getContactHelper().setContactBlocked(recipientId, true, individual.getBlockedAt());
|
||||
}
|
||||
for (var groupId : blockedListMessage.groupIds.stream()
|
||||
.map(GroupId::unknownVersion)
|
||||
.collect(Collectors.toSet())) {
|
||||
for (var group : blockedListMessage.groups) {
|
||||
final var groupId = GroupId.unknownVersion(group.getGroupId());
|
||||
try {
|
||||
context.getGroupHelper().setGroupBlocked(groupId, true);
|
||||
context.getGroupHelper().setGroupBlocked(groupId, true, group.getBlockedAt());
|
||||
} catch (GroupNotFoundException e) {
|
||||
logger.warn("BlockedListMessage contained groupID that was not found in GroupStore: {}",
|
||||
groupId.toBase64());
|
||||
|
||||
@ -12,6 +12,7 @@ import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.signalservice.api.messages.EnvelopeResponse;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.websocket.SignalWebSocket;
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
|
||||
@ -147,15 +148,19 @@ public class ReceiveHelper {
|
||||
logger.debug("Retrieved {} envelopes!", batch.size());
|
||||
isWaitingForMessage = false;
|
||||
for (final var it : batch) {
|
||||
SignalServiceEnvelope envelope1 = new SignalServiceEnvelope(it.getEnvelope(),
|
||||
it.getServerDeliveredTimestamp());
|
||||
final var sourceServiceId = envelope1.getSourceServiceId();
|
||||
final var recipientId = sourceServiceId == null
|
||||
? null
|
||||
: account.getRecipientResolver().resolveRecipient(sourceServiceId);
|
||||
logger.trace("Storing new message from {}", recipientId);
|
||||
// store message on disk, before acknowledging receipt to the server
|
||||
cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId);
|
||||
if (it instanceof EnvelopeResponse.Unparseable) {
|
||||
logger.warn("Received unparseable envelope from server, ignoring.");
|
||||
} else if (it instanceof EnvelopeResponse.Parsed parsed) {
|
||||
SignalServiceEnvelope envelope1 = new SignalServiceEnvelope(parsed.getEnvelope(),
|
||||
parsed.getServerDeliveredTimestamp());
|
||||
final var sourceServiceId = envelope1.getSourceServiceId();
|
||||
final var recipientId = sourceServiceId == null
|
||||
? null
|
||||
: account.getRecipientResolver().resolveRecipient(sourceServiceId);
|
||||
logger.trace("Storing new message from {}", recipientId);
|
||||
// store message on disk, before acknowledging receipt to the server
|
||||
cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId);
|
||||
}
|
||||
try {
|
||||
signalWebSocket.sendAck(it);
|
||||
} catch (IOException e) {
|
||||
@ -167,6 +172,9 @@ public class ReceiveHelper {
|
||||
backOffCounter = 0;
|
||||
|
||||
if (queueNotEmpty) {
|
||||
if (cachedMessage[0] == null) {
|
||||
continue;
|
||||
}
|
||||
if (remainingMessages > 0) {
|
||||
remainingMessages -= 1;
|
||||
}
|
||||
|
||||
@ -237,18 +237,19 @@ public class SyncHelper {
|
||||
final var address = account.getRecipientAddressResolver().resolveRecipientAddress(record.first());
|
||||
if (address.aci().isPresent() || address.number().isPresent()) {
|
||||
addresses.add(new BlockedListMessage.Individual(address.aci().orElse(null),
|
||||
address.number().orElse(null)));
|
||||
address.number().orElse(null),
|
||||
record.second().blockedAt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
var groupIds = new ArrayList<byte[]>();
|
||||
var groups = new ArrayList<BlockedListMessage.Group>();
|
||||
for (var record : account.getGroupStore().getGroups()) {
|
||||
if (record.isBlocked()) {
|
||||
groupIds.add(record.getGroupId().serialize());
|
||||
groups.add(new BlockedListMessage.Group(record.getGroupId().serialize(), record.getBlockedAt()));
|
||||
}
|
||||
}
|
||||
return context.getSendHelper()
|
||||
.sendSyncMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groupIds)));
|
||||
.sendSyncMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groups)));
|
||||
}
|
||||
|
||||
public SendMessageResult sendVerifiedMessage(
|
||||
|
||||
@ -214,6 +214,7 @@ public class ProvisioningManagerImpl implements ProvisioningManager, Closeable {
|
||||
pniIdentity,
|
||||
profileKey,
|
||||
accountEntropyPool,
|
||||
msg.authCredentialSalt == null ? null : msg.authCredentialSalt.toByteArray(),
|
||||
mediaRootBackupKey);
|
||||
|
||||
if (msg.readReceipts != null) {
|
||||
|
||||
@ -33,7 +33,7 @@ import java.util.UUID;
|
||||
public class AccountDatabase extends Database {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AccountDatabase.class);
|
||||
private static final long DATABASE_VERSION = 30;
|
||||
private static final long DATABASE_VERSION = 31;
|
||||
|
||||
private AccountDatabase(final HikariDataSource dataSource) {
|
||||
super(logger, DATABASE_VERSION, dataSource);
|
||||
@ -643,6 +643,16 @@ public class AccountDatabase extends Database {
|
||||
""");
|
||||
}
|
||||
}
|
||||
if (oldVersion < 31) {
|
||||
logger.debug("Updating database: Add blocked-at timestamps");
|
||||
try (final var statement = connection.createStatement()) {
|
||||
statement.executeUpdate("""
|
||||
ALTER TABLE recipient ADD blocked_at INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE group_v1 ADD blocked_at INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE group_v2 ADD blocked_at INTEGER NOT NULL DEFAULT 0;
|
||||
""");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createUuidMappingTable(
|
||||
|
||||
@ -116,7 +116,7 @@ public class SignalAccount implements Closeable {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SignalAccount.class);
|
||||
|
||||
private static final int MINIMUM_STORAGE_VERSION = 1;
|
||||
private static final int CURRENT_STORAGE_VERSION = 10;
|
||||
private static final int CURRENT_STORAGE_VERSION = 11;
|
||||
|
||||
private final Object LOCK = new Object();
|
||||
|
||||
@ -141,6 +141,7 @@ public class SignalAccount implements Closeable {
|
||||
private MasterKey pinMasterKey;
|
||||
private StorageKey storageKey;
|
||||
private AccountEntropyPool accountEntropyPool;
|
||||
private byte[] authCredentialSalt;
|
||||
private MediaRootBackupKey mediaRootBackupKey;
|
||||
private ProfileKey profileKey;
|
||||
|
||||
@ -301,6 +302,7 @@ public class SignalAccount implements Closeable {
|
||||
final IdentityKeyPair pniIdentity,
|
||||
final ProfileKey profileKey,
|
||||
final AccountEntropyPool accountEntropyPool,
|
||||
final byte[] authCredentialSalt,
|
||||
final MediaRootBackupKey mediaRootBackupKey
|
||||
) {
|
||||
this.deviceId = 0;
|
||||
@ -325,6 +327,7 @@ public class SignalAccount implements Closeable {
|
||||
this.pinMasterKey = null;
|
||||
this.accountEntropyPool = null;
|
||||
}
|
||||
this.authCredentialSalt = authCredentialSalt;
|
||||
this.mediaRootBackupKey = mediaRootBackupKey;
|
||||
getKeyValueStore().storeEntry(storageManifestVersion, -1L);
|
||||
this.setStorageManifest(null);
|
||||
@ -361,6 +364,7 @@ public class SignalAccount implements Closeable {
|
||||
) {
|
||||
this.pinMasterKey = masterKey;
|
||||
this.accountEntropyPool = null;
|
||||
this.authCredentialSalt = null;
|
||||
getKeyValueStore().storeEntry(storageManifestVersion, -1L);
|
||||
this.setStorageManifest(null);
|
||||
this.storageKey = null;
|
||||
@ -526,6 +530,9 @@ public class SignalAccount implements Closeable {
|
||||
if (storage.accountEntropyPool != null) {
|
||||
accountEntropyPool = new AccountEntropyPool(storage.accountEntropyPool);
|
||||
}
|
||||
if (storage.authCredentialSalt != null) {
|
||||
authCredentialSalt = base64.decode(storage.authCredentialSalt);
|
||||
}
|
||||
if (storage.mediaRootBackupKey != null) {
|
||||
mediaRootBackupKey = new MediaRootBackupKey(base64.decode(storage.mediaRootBackupKey));
|
||||
}
|
||||
@ -906,6 +913,7 @@ public class SignalAccount implements Closeable {
|
||||
0,
|
||||
false,
|
||||
contact.blocked,
|
||||
0,
|
||||
contact.archived,
|
||||
false,
|
||||
false,
|
||||
@ -1014,6 +1022,7 @@ public class SignalAccount implements Closeable {
|
||||
pinMasterKey == null ? null : base64.encodeToString(pinMasterKey.serialize()),
|
||||
storageKey == null ? null : base64.encodeToString(storageKey.serialize()),
|
||||
accountEntropyPool == null ? null : accountEntropyPool.getValue(),
|
||||
authCredentialSalt == null ? null : base64.encodeToString(authCredentialSalt),
|
||||
mediaRootBackupKey == null ? null : base64.encodeToString(mediaRootBackupKey.getValue()),
|
||||
profileKey == null ? null : base64.encodeToString(profileKey.serialize()),
|
||||
usernameLink == null ? null : base64.encodeToString(usernameLink.getEntropy()),
|
||||
@ -1228,6 +1237,11 @@ public class SignalAccount implements Closeable {
|
||||
return pniAccountData.getSignalServiceAccountDataStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignalServiceAccountDataStore pniOrNull() {
|
||||
return getPni() != null ? pniAccountData.getSignalServiceAccountDataStore() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiDevice() {
|
||||
return SignalAccount.this.isMultiDevice();
|
||||
@ -1648,6 +1662,10 @@ public class SignalAccount implements Closeable {
|
||||
save();
|
||||
}
|
||||
|
||||
public byte[] getAuthCredentialSalt() {
|
||||
return authCredentialSalt;
|
||||
}
|
||||
|
||||
public String getRecoveryPassword() {
|
||||
final var masterKey = getPinBackedMasterKey();
|
||||
if (masterKey == null) {
|
||||
@ -1987,6 +2005,7 @@ public class SignalAccount implements Closeable {
|
||||
String pinMasterKey,
|
||||
String storageKey,
|
||||
String accountEntropyPool,
|
||||
String authCredentialSalt,
|
||||
String mediaRootBackupKey,
|
||||
String profileKey,
|
||||
String usernameLinkEntropy,
|
||||
|
||||
@ -58,6 +58,10 @@ public sealed abstract class GroupInfo permits GroupInfoV1, GroupInfoV2 {
|
||||
|
||||
public abstract void setBlocked(boolean blocked);
|
||||
|
||||
public abstract long getBlockedAt();
|
||||
|
||||
public abstract void setBlockedAt(long blockedAt);
|
||||
|
||||
public abstract boolean isProfileSharingEnabled();
|
||||
|
||||
public abstract void setProfileSharingEnabled(boolean profileSharingEnabled);
|
||||
|
||||
@ -24,6 +24,7 @@ public final class GroupInfoV1 extends GroupInfo {
|
||||
public String color;
|
||||
public int messageExpirationTime;
|
||||
public boolean blocked;
|
||||
private long blockedAt;
|
||||
public boolean archived;
|
||||
private byte[] storageRecord;
|
||||
|
||||
@ -39,6 +40,7 @@ public final class GroupInfoV1 extends GroupInfo {
|
||||
final String color,
|
||||
final int messageExpirationTime,
|
||||
final boolean blocked,
|
||||
final long blockedAt,
|
||||
final boolean archived,
|
||||
final byte[] storageRecord
|
||||
) {
|
||||
@ -49,6 +51,7 @@ public final class GroupInfoV1 extends GroupInfo {
|
||||
this.color = color;
|
||||
this.messageExpirationTime = messageExpirationTime;
|
||||
this.blocked = blocked;
|
||||
this.blockedAt = blockedAt;
|
||||
this.archived = archived;
|
||||
this.storageRecord = storageRecord;
|
||||
}
|
||||
@ -91,9 +94,24 @@ public final class GroupInfoV1 extends GroupInfo {
|
||||
|
||||
@Override
|
||||
public void setBlocked(final boolean blocked) {
|
||||
if (blocked && !this.blocked) {
|
||||
blockedAt = System.currentTimeMillis();
|
||||
} else if (!blocked) {
|
||||
blockedAt = 0;
|
||||
}
|
||||
this.blocked = blocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlockedAt() {
|
||||
return blockedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockedAt(final long blockedAt) {
|
||||
this.blockedAt = blockedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProfileSharingEnabled() {
|
||||
return true;
|
||||
|
||||
@ -23,6 +23,7 @@ public final class GroupInfoV2 extends GroupInfo {
|
||||
private final GroupMasterKey masterKey;
|
||||
private final DistributionId distributionId;
|
||||
private boolean blocked;
|
||||
private long blockedAt;
|
||||
private boolean profileSharingEnabled;
|
||||
private DecryptedGroup group;
|
||||
private byte[] storageRecord;
|
||||
@ -47,6 +48,7 @@ public final class GroupInfoV2 extends GroupInfo {
|
||||
final DecryptedGroup group,
|
||||
final DistributionId distributionId,
|
||||
final boolean blocked,
|
||||
final long blockedAt,
|
||||
final boolean profileSharingEnabled,
|
||||
final boolean permissionDenied,
|
||||
final byte[] storageRecord,
|
||||
@ -57,6 +59,7 @@ public final class GroupInfoV2 extends GroupInfo {
|
||||
this.group = group;
|
||||
this.distributionId = distributionId;
|
||||
this.blocked = blocked;
|
||||
this.blockedAt = blockedAt;
|
||||
this.profileSharingEnabled = profileSharingEnabled;
|
||||
this.permissionDenied = permissionDenied;
|
||||
this.storageRecord = storageRecord;
|
||||
@ -186,9 +189,24 @@ public final class GroupInfoV2 extends GroupInfo {
|
||||
|
||||
@Override
|
||||
public void setBlocked(final boolean blocked) {
|
||||
if (blocked && !this.blocked) {
|
||||
blockedAt = System.currentTimeMillis();
|
||||
} else if (!blocked) {
|
||||
blockedAt = 0;
|
||||
}
|
||||
this.blocked = blocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlockedAt() {
|
||||
return blockedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockedAt(final long blockedAt) {
|
||||
this.blockedAt = blockedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProfileSharingEnabled() {
|
||||
return profileSharingEnabled;
|
||||
|
||||
@ -63,6 +63,7 @@ public class GroupStore {
|
||||
distribution_id BLOB UNIQUE NOT NULL,
|
||||
endorsement_expiration_time INTEGER NOT NULL DEFAULT 0,
|
||||
blocked INTEGER NOT NULL DEFAULT FALSE,
|
||||
blocked_at INTEGER NOT NULL DEFAULT 0,
|
||||
profile_sharing INTEGER NOT NULL DEFAULT FALSE,
|
||||
permission_denied INTEGER NOT NULL DEFAULT FALSE
|
||||
) STRICT;
|
||||
@ -83,6 +84,7 @@ public class GroupStore {
|
||||
color TEXT,
|
||||
expiration_time INTEGER NOT NULL DEFAULT 0,
|
||||
blocked INTEGER NOT NULL DEFAULT FALSE,
|
||||
blocked_at INTEGER NOT NULL DEFAULT 0,
|
||||
archived INTEGER NOT NULL DEFAULT FALSE
|
||||
) STRICT;
|
||||
CREATE TABLE group_v1_member (
|
||||
@ -401,6 +403,7 @@ public class GroupStore {
|
||||
deleteGroup(connection, groupInfoV1.getGroupId());
|
||||
final var groupInfoV2 = new GroupInfoV2(groupId, groupMasterKey, recipientResolver);
|
||||
groupInfoV2.setBlocked(groupInfoV1.isBlocked());
|
||||
groupInfoV2.setBlockedAt(groupInfoV1.getBlockedAt());
|
||||
updateGroup(connection, groupInfoV2);
|
||||
logger.debug("Locally migrated group {} to group v2, id: {}",
|
||||
groupInfoV1.getGroupId().toBase64(),
|
||||
@ -614,9 +617,9 @@ public class GroupStore {
|
||||
}
|
||||
}
|
||||
final var sql = """
|
||||
INSERT INTO %s (_id, group_id, group_id_v2, name, color, expiration_time, blocked, archived, storage_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (_id) DO UPDATE SET group_id=excluded.group_id, group_id_v2=excluded.group_id_v2, name=excluded.name, color=excluded.color, expiration_time=excluded.expiration_time, blocked=excluded.blocked, archived=excluded.archived, storage_id=excluded.storage_id
|
||||
INSERT INTO %s (_id, group_id, group_id_v2, name, color, expiration_time, blocked, blocked_at, archived, storage_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (_id) DO UPDATE SET group_id=excluded.group_id, group_id_v2=excluded.group_id_v2, name=excluded.name, color=excluded.color, expiration_time=excluded.expiration_time, blocked=excluded.blocked, blocked_at=excluded.blocked_at, archived=excluded.archived, storage_id=excluded.storage_id
|
||||
RETURNING _id
|
||||
""".formatted(TABLE_GROUP_V1);
|
||||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
@ -631,8 +634,9 @@ public class GroupStore {
|
||||
statement.setString(5, groupV1.color);
|
||||
statement.setLong(6, groupV1.getMessageExpirationTimer());
|
||||
statement.setBoolean(7, groupV1.isBlocked());
|
||||
statement.setBoolean(8, groupV1.archived);
|
||||
statement.setBytes(9, KeyUtils.createRawStorageId());
|
||||
statement.setLong(8, groupV1.getBlockedAt());
|
||||
statement.setBoolean(9, groupV1.archived);
|
||||
statement.setBytes(10, KeyUtils.createRawStorageId());
|
||||
final var generatedKey = Utils.executeQueryForOptional(statement, Utils::getIdMapper);
|
||||
|
||||
if (internalId == null) {
|
||||
@ -658,9 +662,9 @@ public class GroupStore {
|
||||
} else if (group instanceof GroupInfoV2 groupV2) {
|
||||
final var sql = (
|
||||
"""
|
||||
INSERT INTO %s (_id, group_id, master_key, group_data, distribution_id, blocked, permission_denied, storage_id, profile_sharing)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (_id) DO UPDATE SET group_id=excluded.group_id, master_key=excluded.master_key, group_data=excluded.group_data, distribution_id=excluded.distribution_id, blocked=excluded.blocked, permission_denied=excluded.permission_denied, storage_id=excluded.storage_id, profile_sharing=excluded.profile_sharing
|
||||
INSERT INTO %s (_id, group_id, master_key, group_data, distribution_id, blocked, blocked_at, permission_denied, storage_id, profile_sharing)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (_id) DO UPDATE SET group_id=excluded.group_id, master_key=excluded.master_key, group_data=excluded.group_data, distribution_id=excluded.distribution_id, blocked=excluded.blocked, blocked_at=excluded.blocked_at, permission_denied=excluded.permission_denied, storage_id=excluded.storage_id, profile_sharing=excluded.profile_sharing
|
||||
"""
|
||||
).formatted(TABLE_GROUP_V2);
|
||||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
@ -678,9 +682,10 @@ public class GroupStore {
|
||||
}
|
||||
statement.setBytes(5, UuidUtil.toByteArray(groupV2.getDistributionId().asUuid()));
|
||||
statement.setBoolean(6, groupV2.isBlocked());
|
||||
statement.setBoolean(7, groupV2.isPermissionDenied());
|
||||
statement.setBytes(8, KeyUtils.createRawStorageId());
|
||||
statement.setBoolean(9, groupV2.isProfileSharingEnabled());
|
||||
statement.setLong(7, groupV2.getBlockedAt());
|
||||
statement.setBoolean(8, groupV2.isPermissionDenied());
|
||||
statement.setBytes(9, KeyUtils.createRawStorageId());
|
||||
statement.setBoolean(10, groupV2.isProfileSharingEnabled());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
} else {
|
||||
@ -691,7 +696,7 @@ public class GroupStore {
|
||||
private List<GroupInfoV2> getGroupsV2() {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.master_key, g.group_data, g.distribution_id, g.blocked, g.profile_sharing, g.permission_denied, g.storage_record
|
||||
SELECT g.group_id, g.master_key, g.group_data, g.distribution_id, g.blocked, g.blocked_at, g.profile_sharing, g.permission_denied, g.storage_record
|
||||
FROM %s g
|
||||
"""
|
||||
).formatted(TABLE_GROUP_V2);
|
||||
@ -709,7 +714,7 @@ public class GroupStore {
|
||||
public GroupInfoV2 getGroup(Connection connection, GroupIdV2 groupIdV2) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.master_key, g.group_data, g.distribution_id, g.blocked, g.profile_sharing, g.permission_denied, g.storage_record
|
||||
SELECT g.group_id, g.master_key, g.group_data, g.distribution_id, g.blocked, g.blocked_at, g.profile_sharing, g.permission_denied, g.storage_record
|
||||
FROM %s g
|
||||
WHERE g.group_id = ?
|
||||
"""
|
||||
@ -743,7 +748,7 @@ public class GroupStore {
|
||||
public GroupInfoV2 getGroupV2(Connection connection, StorageId storageId) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.master_key, g.group_data, g.distribution_id, g.blocked, g.profile_sharing, g.permission_denied, g.storage_record
|
||||
SELECT g.group_id, g.master_key, g.group_data, g.distribution_id, g.blocked, g.blocked_at, g.profile_sharing, g.permission_denied, g.storage_record
|
||||
FROM %s g
|
||||
WHERE g.storage_id = ?
|
||||
"""
|
||||
@ -766,6 +771,7 @@ public class GroupStore {
|
||||
final var groupData = resultSet.getBytes("group_data");
|
||||
final var distributionId = resultSet.getBytes("distribution_id");
|
||||
final var blocked = resultSet.getBoolean("blocked");
|
||||
final var blockedAt = resultSet.getLong("blocked_at");
|
||||
final var profileSharingEnabled = resultSet.getBoolean("profile_sharing");
|
||||
final var permissionDenied = resultSet.getBoolean("permission_denied");
|
||||
final var storageRecord = resultSet.getBytes("storage_record");
|
||||
@ -774,6 +780,7 @@ public class GroupStore {
|
||||
groupData == null ? null : DecryptedGroup.ADAPTER.decode(groupData),
|
||||
DistributionId.from(UuidUtil.parseOrThrow(distributionId)),
|
||||
blocked,
|
||||
blockedAt,
|
||||
profileSharingEnabled,
|
||||
permissionDenied,
|
||||
storageRecord,
|
||||
@ -800,7 +807,7 @@ public class GroupStore {
|
||||
private List<GroupInfoV1> getGroupsV1() {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.archived, g.storage_record
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.blocked_at, g.archived, g.storage_record
|
||||
FROM %s g
|
||||
"""
|
||||
).formatted(TABLE_GROUP_V1_MEMBER, TABLE_GROUP_V1);
|
||||
@ -818,7 +825,7 @@ public class GroupStore {
|
||||
public GroupInfoV1 getGroup(Connection connection, GroupIdV1 groupIdV1) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.archived, g.storage_record
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.blocked_at, g.archived, g.storage_record
|
||||
FROM %s g
|
||||
WHERE g.group_id = ?
|
||||
"""
|
||||
@ -852,7 +859,7 @@ public class GroupStore {
|
||||
public GroupInfoV1 getGroupV1(Connection connection, StorageId storageId) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.archived, g.storage_record
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.blocked_at, g.archived, g.storage_record
|
||||
FROM %s g
|
||||
WHERE g.storage_id = ?
|
||||
"""
|
||||
@ -882,6 +889,7 @@ public class GroupStore {
|
||||
.collect(Collectors.toSet());
|
||||
final var expirationTime = resultSet.getInt("expiration_time");
|
||||
final var blocked = resultSet.getBoolean("blocked");
|
||||
final var blockedAt = resultSet.getLong("blocked_at");
|
||||
final var archived = resultSet.getBoolean("archived");
|
||||
final var storageRecord = resultSet.getBytes("storage_record");
|
||||
return new GroupInfoV1(GroupId.v1(groupId),
|
||||
@ -891,6 +899,7 @@ public class GroupStore {
|
||||
color,
|
||||
expirationTime,
|
||||
blocked,
|
||||
blockedAt,
|
||||
archived,
|
||||
storageRecord);
|
||||
}
|
||||
@ -902,7 +911,7 @@ public class GroupStore {
|
||||
private GroupInfoV1 getGroupV1ByV2Id(Connection connection, GroupIdV2 groupIdV2) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.archived, g.storage_record
|
||||
SELECT g.group_id, g.group_id_v2, g.name, g.color, (select group_concat(gm.recipient_id) from %s gm where gm.group_id = g._id) as members, g.expiration_time, g.blocked, g.blocked_at, g.archived, g.storage_record
|
||||
FROM %s g
|
||||
WHERE g.group_id_v2 = ?
|
||||
"""
|
||||
|
||||
@ -59,6 +59,7 @@ public class LegacyGroupStore {
|
||||
g1.color,
|
||||
g1.messageExpirationTime,
|
||||
g1.blocked,
|
||||
0,
|
||||
g1.archived,
|
||||
null);
|
||||
}
|
||||
@ -77,6 +78,7 @@ public class LegacyGroupStore {
|
||||
loadDecryptedGroupLocked(groupId, groupCachePath),
|
||||
g2.distributionId == null ? DistributionId.create() : DistributionId.from(g2.distributionId),
|
||||
g2.blocked,
|
||||
0,
|
||||
true,
|
||||
g2.permissionDenied,
|
||||
null,
|
||||
|
||||
@ -50,6 +50,7 @@ public class LegacyRecipientStore2 {
|
||||
0,
|
||||
false,
|
||||
r.contact.blocked,
|
||||
0,
|
||||
r.contact.archived,
|
||||
r.contact.profileSharingEnabled,
|
||||
false,
|
||||
|
||||
@ -96,6 +96,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
expiration_time_version INTEGER DEFAULT 1 NOT NULL,
|
||||
mute_until INTEGER NOT NULL DEFAULT 0,
|
||||
blocked INTEGER NOT NULL DEFAULT FALSE,
|
||||
blocked_at INTEGER NOT NULL DEFAULT 0,
|
||||
archived INTEGER NOT NULL DEFAULT FALSE,
|
||||
profile_sharing INTEGER NOT NULL DEFAULT FALSE,
|
||||
hide_story INTEGER NOT NULL DEFAULT FALSE,
|
||||
@ -351,7 +352,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
public List<Pair<RecipientId, Contact>> getContacts() {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT r._id, r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden, r.unregistered_timestamp
|
||||
SELECT r._id, r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.blocked_at, r.archived, r.hidden, r.unregistered_timestamp
|
||||
FROM %s r
|
||||
WHERE (r.number IS NOT NULL OR r.pni IS NOT NULL OR r.aci IS NOT NULL) AND %s AND r.hidden = FALSE
|
||||
"""
|
||||
@ -376,7 +377,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
r.number, r.aci, r.pni, r.username,
|
||||
r.profile_key, r.profile_key_credential,
|
||||
r.pni_signature_verified,
|
||||
r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden, r.unregistered_timestamp,
|
||||
r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.blocked_at, r.archived, r.hidden, r.unregistered_timestamp,
|
||||
r.profile_last_update_timestamp, r.profile_given_name, r.profile_family_name, r.profile_about, r.profile_about_emoji, r.profile_avatar_url_path, r.profile_mobile_coin_address, r.profile_unidentified_access_mode, r.profile_capabilities, r.profile_phone_number_sharing,
|
||||
r.discoverable,
|
||||
r.storage_record
|
||||
@ -397,7 +398,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
r.number, r.aci, r.pni, r.username,
|
||||
r.profile_key, r.profile_key_credential,
|
||||
r.pni_signature_verified,
|
||||
r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden, r.unregistered_timestamp,
|
||||
r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.blocked_at, r.archived, r.hidden, r.unregistered_timestamp,
|
||||
r.profile_last_update_timestamp, r.profile_given_name, r.profile_family_name, r.profile_about, r.profile_about_emoji, r.profile_avatar_url_path, r.profile_mobile_coin_address, r.profile_unidentified_access_mode, r.profile_capabilities, r.profile_phone_number_sharing,
|
||||
r.discoverable,
|
||||
r.storage_record
|
||||
@ -447,7 +448,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
r.number, r.aci, r.pni, r.username,
|
||||
r.profile_key, r.profile_key_credential,
|
||||
r.pni_signature_verified,
|
||||
r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden, r.unregistered_timestamp,
|
||||
r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.blocked_at, r.archived, r.hidden, r.unregistered_timestamp,
|
||||
r.profile_last_update_timestamp, r.profile_given_name, r.profile_family_name, r.profile_about, r.profile_about_emoji, r.profile_avatar_url_path, r.profile_mobile_coin_address, r.profile_unidentified_access_mode, r.profile_capabilities, r.profile_phone_number_sharing,
|
||||
r.discoverable,
|
||||
r.storage_record
|
||||
@ -892,7 +893,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
final var sql = (
|
||||
"""
|
||||
UPDATE %s
|
||||
SET given_name = ?, family_name = ?, nick_name = ?, expiration_time = ?, expiration_time_version = ?, mute_until = ?, hide_story = ?, profile_sharing = ?, color = ?, blocked = ?, archived = ?, unregistered_timestamp = ?, nick_name_given_name = ?, nick_name_family_name = ?, note = ?, hidden = ?
|
||||
SET given_name = ?, family_name = ?, nick_name = ?, expiration_time = ?, expiration_time_version = ?, mute_until = ?, hide_story = ?, profile_sharing = ?, color = ?, blocked = ?, blocked_at = ?, archived = ?, unregistered_timestamp = ?, nick_name_given_name = ?, nick_name_family_name = ?, note = ?, hidden = ?
|
||||
WHERE _id = ?
|
||||
"""
|
||||
).formatted(TABLE_RECIPIENT);
|
||||
@ -907,17 +908,18 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
statement.setBoolean(8, contact != null && contact.isProfileSharingEnabled());
|
||||
statement.setString(9, contact == null ? null : contact.color());
|
||||
statement.setBoolean(10, contact != null && contact.isBlocked());
|
||||
statement.setBoolean(11, contact != null && contact.isArchived());
|
||||
statement.setLong(11, contact == null ? 0 : contact.blockedAt());
|
||||
statement.setBoolean(12, contact != null && contact.isArchived());
|
||||
if (contact == null || contact.unregisteredTimestamp() == null) {
|
||||
statement.setNull(12, Types.INTEGER);
|
||||
statement.setNull(13, Types.INTEGER);
|
||||
} else {
|
||||
statement.setLong(12, contact.unregisteredTimestamp());
|
||||
statement.setLong(13, contact.unregisteredTimestamp());
|
||||
}
|
||||
statement.setString(13, contact == null ? null : contact.nickNameGivenName());
|
||||
statement.setString(14, contact == null ? null : contact.nickNameFamilyName());
|
||||
statement.setString(15, contact == null ? null : contact.note());
|
||||
statement.setBoolean(16, contact != null && contact.isHidden());
|
||||
statement.setLong(17, recipientId.id());
|
||||
statement.setString(14, contact == null ? null : contact.nickNameGivenName());
|
||||
statement.setString(15, contact == null ? null : contact.nickNameFamilyName());
|
||||
statement.setString(16, contact == null ? null : contact.note());
|
||||
statement.setBoolean(17, contact != null && contact.isHidden());
|
||||
statement.setLong(18, recipientId.id());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
if (contact != null && contact.unregisteredTimestamp() != null) {
|
||||
@ -1594,7 +1596,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
private Contact getContact(final Connection connection, final RecipientId recipientId) throws SQLException {
|
||||
final var sql = (
|
||||
"""
|
||||
SELECT r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden, r.unregistered_timestamp
|
||||
SELECT r.given_name, r.family_name, r.nick_name, r.nick_name_given_name, r.nick_name_family_name, r.note, r.expiration_time, r.expiration_time_version, r.mute_until, r.hide_story, r.profile_sharing, r.color, r.blocked, r.blocked_at, r.archived, r.hidden, r.unregistered_timestamp
|
||||
FROM %s r
|
||||
WHERE r._id = ? AND (%s)
|
||||
"""
|
||||
@ -1699,6 +1701,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
|
||||
resultSet.getLong("mute_until"),
|
||||
resultSet.getBoolean("hide_story"),
|
||||
resultSet.getBoolean("blocked"),
|
||||
resultSet.getLong("blocked_at"),
|
||||
resultSet.getBoolean("archived"),
|
||||
resultSet.getBoolean("profile_sharing"),
|
||||
resultSet.getBoolean("hidden"),
|
||||
|
||||
@ -410,7 +410,7 @@ public class SessionStore implements SignalServiceSessionStore {
|
||||
}
|
||||
|
||||
private static boolean isActive(SessionRecord record) {
|
||||
return record != null && record.hasSenderChain(0.0);
|
||||
return record != null && record.hasSenderChain();
|
||||
}
|
||||
|
||||
record Key(String address, int deviceId) {}
|
||||
|
||||
@ -205,6 +205,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
||||
.identityState(identityState)
|
||||
.identityKey(identityKey)
|
||||
.blocked(remote.blocked)
|
||||
.blockedAtTimestamp(remote.blockedAtTimestamp)
|
||||
.whitelisted(remote.whitelisted)
|
||||
.archived(remote.archived)
|
||||
.markedUnread(remote.markedUnread)
|
||||
@ -283,7 +284,9 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
||||
final var contactNickGivenName = contact == null ? null : contact.nickNameGivenName();
|
||||
final var contactNickFamilyName = contact == null ? null : contact.nickNameFamilyName();
|
||||
final var contactNote = contact == null ? null : contact.note();
|
||||
final var blockedAt = contact == null ? 0 : contact.blockedAt();
|
||||
if (blocked != contactProto.blocked
|
||||
|| blockedAt != contactProto.blockedAtTimestamp
|
||||
|| profileShared != contactProto.whitelisted
|
||||
|| archived != contactProto.archived
|
||||
|| hidden != contactProto.hidden
|
||||
@ -301,6 +304,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
||||
logger.debug("Storing new or updated contact {}", recipientId);
|
||||
final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
|
||||
final var newContact = contactBuilder.withIsBlocked(contactProto.blocked)
|
||||
.withBlockedAt(contactProto.blocked ? contactProto.blockedAtTimestamp : 0)
|
||||
.withIsProfileSharingEnabled(contactProto.whitelisted)
|
||||
.withIsArchived(contactProto.archived)
|
||||
.withIsHidden(contactProto.hidden)
|
||||
|
||||
@ -114,6 +114,7 @@ public final class GroupV1RecordProcessor extends DefaultStorageRecordProcessor<
|
||||
final var group = account.getGroupStore().getOrCreateGroupV1(connection, groupIdV1);
|
||||
if (group != null) {
|
||||
group.setBlocked(groupV1Proto.blocked);
|
||||
group.setBlockedAt(0);
|
||||
account.getGroupStore().updateGroup(connection, group);
|
||||
account.getGroupStore()
|
||||
.storeStorageRecord(connection, group.getGroupId(), groupV1Record.getId(), groupV1Proto.encode());
|
||||
|
||||
@ -56,6 +56,7 @@ public final class GroupV2RecordProcessor extends DefaultStorageRecordProcessor<
|
||||
final var mergedBuilder = remote.newBuilder()
|
||||
.masterKey(remote.masterKey)
|
||||
.blocked(remote.blocked)
|
||||
.blockedAtTimestamp(remote.blockedAtTimestamp)
|
||||
.whitelisted(remote.whitelisted)
|
||||
.archived(remote.archived)
|
||||
.markedUnread(remote.markedUnread)
|
||||
@ -93,6 +94,7 @@ public final class GroupV2RecordProcessor extends DefaultStorageRecordProcessor<
|
||||
|
||||
final var group = account.getGroupStore().getGroupOrPartialMigrate(connection, groupMasterKey);
|
||||
group.setBlocked(groupV2Proto.blocked);
|
||||
group.setBlockedAt(groupV2Proto.blocked ? groupV2Proto.blockedAtTimestamp : 0);
|
||||
group.setProfileSharingEnabled(groupV2Proto.whitelisted);
|
||||
account.getGroupStore().updateGroup(connection, group);
|
||||
account.getGroupStore()
|
||||
|
||||
@ -123,6 +123,7 @@ public final class StorageSyncModels {
|
||||
.nickname(getNicknameRemoteRecord(recipient.getContact()))
|
||||
.note(emptyIfNull(recipient.getContact().note()))
|
||||
.blocked(recipient.getContact().isBlocked())
|
||||
.blockedAtTimestamp(recipient.getContact().blockedAt())
|
||||
.whitelisted(recipient.getContact().isProfileSharingEnabled())
|
||||
.mutedUntilTimestamp(recipient.getContact().muteUntil())
|
||||
.hideStory(recipient.getContact().hideStory())
|
||||
@ -161,6 +162,7 @@ public final class StorageSyncModels {
|
||||
final var builder = SignalGroupV2Record.Companion.newBuilder(group.getStorageRecord());
|
||||
builder.masterKey(ByteString.of(group.getMasterKey().serialize()));
|
||||
builder.blocked(group.isBlocked());
|
||||
builder.blockedAtTimestamp(group.getBlockedAt());
|
||||
builder.whitelisted(group.isProfileSharingEnabled());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ package org.asamk.signal.manager.storage.groups;
|
||||
|
||||
import org.asamk.signal.manager.api.Group;
|
||||
import org.asamk.signal.manager.api.GroupId;
|
||||
import org.asamk.signal.manager.api.GroupIdV2;
|
||||
import org.asamk.signal.manager.groups.GroupUtils;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientId;
|
||||
@ -61,6 +60,7 @@ class GroupInfoTerminatedTest {
|
||||
group,
|
||||
DistributionId.create(),
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
|
||||
@ -91,7 +91,7 @@ class StorageSyncLoopDetectorTest {
|
||||
}
|
||||
|
||||
private static WriteOperationResult writeWithInsert(final int storageIdByte) {
|
||||
final var storageId = new StorageId(99, new byte[]{(byte) storageIdByte});
|
||||
final var storageId = StorageId.forType(new byte[]{(byte) storageIdByte}, 99);
|
||||
final var record = new SignalStorageRecord(storageId, new StorageRecord.Builder().build());
|
||||
return new WriteOperationResult(null, List.of(record), List.of());
|
||||
}
|
||||
|
||||
@ -839,6 +839,7 @@ public class DbusManagerImpl implements Manager {
|
||||
0,
|
||||
false,
|
||||
contactBlocked,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
||||
@ -3768,6 +3768,32 @@
|
||||
"java.lang.String"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": [
|
||||
"int",
|
||||
"long",
|
||||
"java.lang.String",
|
||||
"boolean",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"int",
|
||||
"boolean",
|
||||
"java.lang.String",
|
||||
"org.asamk.signal.manager.storage.SignalAccount$Storage$AccountData",
|
||||
"org.asamk.signal.manager.storage.SignalAccount$Storage$AccountData",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String",
|
||||
"java.lang.String"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": [
|
||||
@ -3818,6 +3844,10 @@
|
||||
"name": "aciAccountData",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "authCredentialSalt",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "deviceId",
|
||||
"parameterTypes": []
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user