# Changelog
## [Unreleased]
-**Attention**: Now requires native libsignal-client version 0.5.1
+**Attention**: Now requires native libsignal-client version 0.8.1
### Added
- Added new parameters to `updateGroup` for group v2 features:
{"name":"bitField0_", "allowUnsafeAccess":true},
{"name":"callMessage_", "allowUnsafeAccess":true},
{"name":"dataMessage_", "allowUnsafeAccess":true},
+ {"name":"decryptionErrorMessage_", "allowUnsafeAccess":true},
{"name":"nullMessage_", "allowUnsafeAccess":true},
{"name":"receiptMessage_", "allowUnsafeAccess":true},
+ {"name":"senderKeyDistributionMessage_", "allowUnsafeAccess":true},
{"name":"syncMessage_", "allowUnsafeAccess":true},
{"name":"typingMessage_", "allowUnsafeAccess":true}
]
"fields":[
{"name":"address_", "allowUnsafeAccess":true},
{"name":"bitField0_", "allowUnsafeAccess":true},
+ {"name":"groupId_", "allowUnsafeAccess":true},
{"name":"needsReceipt_", "allowUnsafeAccess":true},
{"name":"senderDevice_", "allowUnsafeAccess":true},
{"name":"serverDeliveredTimestamp_", "allowUnsafeAccess":true},
}
dependencies {
- api("com.github.turasa:signal-service-java:2.15.3_unofficial_23")
+ api("com.github.turasa:signal-service-java:2.15.3_unofficial_24")
implementation("com.google.protobuf:protobuf-javalite:3.10.0")
implementation("org.bouncycastle:bcprov-jdk15on:1.68")
implementation("org.slf4j:slf4j-api:1.7.30")
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalSessionLock;
+import org.whispersystems.signalservice.api.crypto.ContentHint;
import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
private void sendSyncMessage(SignalServiceSyncMessage message) throws IOException, UntrustedIdentityException {
var messageSender = createMessageSender();
- messageSender.sendMessage(message, unidentifiedAccessHelper.getAccessForSync());
+ messageSender.sendSyncMessage(message, unidentifiedAccessHelper.getAccessForSync());
}
private Set<RecipientId> getSignalServiceAddresses(Collection<String> numbers) throws InvalidNumberException {
final var addresses = recipientIdList.stream()
.map(this::resolveSignalServiceAddress)
.collect(Collectors.toList());
- var result = messageSender.sendMessage(addresses,
+ var result = messageSender.sendDataMessage(addresses,
unidentifiedAccessHelper.getAccessFor(recipientIdList),
isRecipientUpdate,
+ ContentHint.DEFAULT,
message);
for (var r : result) {
try {
var startTime = System.currentTimeMillis();
- messageSender.sendMessage(syncMessage, unidentifiedAccess);
+ messageSender.sendSyncMessage(syncMessage, unidentifiedAccess);
return SendMessageResult.success(recipient,
unidentifiedAccess.isPresent(),
false,
final var address = resolveSignalServiceAddress(recipientId);
try {
try {
- return messageSender.sendMessage(address, unidentifiedAccessHelper.getAccessFor(recipientId), message);
+ return messageSender.sendDataMessage(address,
+ unidentifiedAccessHelper.getAccessFor(recipientId),
+ ContentHint.DEFAULT,
+ message);
} catch (UnregisteredUserException e) {
final var newRecipientId = refreshRegisteredUser(recipientId);
- return messageSender.sendMessage(resolveSignalServiceAddress(newRecipientId),
+ return messageSender.sendDataMessage(resolveSignalServiceAddress(newRecipientId),
unidentifiedAccessHelper.getAccessFor(newRecipientId),
+ ContentHint.DEFAULT,
message);
}
} catch (UntrustedIdentityException e) {
} catch (Throwable ignored) {
zkGroupAvailable = false;
}
- capabilities = new AccountAttributes.Capabilities(false, zkGroupAvailable, false, zkGroupAvailable);
+ capabilities = new AccountAttributes.Capabilities(false, zkGroupAvailable, false, zkGroupAvailable, false);
try {
TrustStore contactTrustStore = new IasTrustStore();
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyIdException;
+import org.whispersystems.libsignal.NoSessionException;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.groups.state.SenderKeyRecord;
import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.libsignal.state.SignedPreKeyStore;
import org.whispersystems.signalservice.api.SignalServiceProtocolStore;
import org.whispersystems.signalservice.api.SignalServiceSessionStore;
+import org.whispersystems.signalservice.api.push.DistributionId;
+import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.UUID;
public class SignalProtocolStore implements SignalServiceProtocolStore {
return sessionStore.loadSession(address);
}
+ @Override
+ public List<SessionRecord> loadExistingSessions(final List<SignalProtocolAddress> addresses) throws NoSessionException {
+ return sessionStore.loadExistingSessions(addresses);
+ }
+
@Override
public List<Integer> getSubDeviceSessions(String name) {
return sessionStore.getSubDeviceSessions(name);
public void storeSenderKey(
final SignalProtocolAddress sender, final UUID distributionId, final SenderKeyRecord record
) {
+ // TODO
}
@Override
public SenderKeyRecord loadSenderKey(final SignalProtocolAddress sender, final UUID distributionId) {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public Set<SignalProtocolAddress> getSenderKeySharedWith(final DistributionId distributionId) {
+ // TODO
return null;
}
+
+ @Override
+ public void markSenderKeySharedWith(
+ final DistributionId distributionId, final Collection<SignalProtocolAddress> addresses
+ ) {
+ // TODO
+ }
+
+ @Override
+ public void clearSenderKeySharedWith(
+ final DistributionId distributionId, final Collection<SignalProtocolAddress> addresses
+ ) {
+ // TODO
+ }
}
public enum Capability {
gv2,
storage,
- gv1Migration;
+ gv1Migration,
+ senderKey;
static Capability valueOfOrNull(String value) {
try {
import org.asamk.signal.manager.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.whispersystems.libsignal.NoSessionException;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.protocol.CiphertextMessage;
import org.whispersystems.libsignal.state.SessionRecord;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
}
}
+ @Override
+ public List<SessionRecord> loadExistingSessions(final List<SignalProtocolAddress> addresses) throws NoSessionException {
+ final var keys = addresses.stream().map(this::getKey).collect(Collectors.toList());
+
+ synchronized (cachedSessions) {
+ final var sessions = keys.stream()
+ .map(this::loadSessionLocked)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ if (sessions.size() != addresses.size()) {
+ String message = "Mismatch! Asked for "
+ + addresses.size()
+ + " sessions, but only found "
+ + sessions.size()
+ + "!";
+ logger.warn(message);
+ throw new NoSessionException(message);
+ }
+
+ return sessions;
+ }
+ }
+
@Override
public List<Integer> getSubDeviceSessions(String name) {
final var recipientId = resolveRecipient(name);
if (encryptedProfile.getCapabilities().isStorage()) {
capabilities.add(Profile.Capability.storage);
}
+ if (encryptedProfile.getCapabilities().isSenderKey()) {
+ capabilities.add(Profile.Capability.senderKey);
+ }
return capabilities;
}