import org.asamk.signal.manager.internal.SignalDependencies;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.recipients.RecipientId;
+import org.jetbrains.annotations.Nullable;
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
import org.signal.libsignal.metadata.certificate.SenderCertificate;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.whispersystems.signalservice.api.crypto.SealedSenderAccess;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
-import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
import java.io.IOException;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.TimeUnit;
+import static org.asamk.signal.manager.util.Utils.handleResponseException;
+
public class UnidentifiedAccessHelper {
private static final Logger logger = LoggerFactory.getLogger(UnidentifiedAccessHelper.class);
senderCertificate = null;
}
- public List<Optional<UnidentifiedAccessPair>> getAccessFor(List<RecipientId> recipients) {
+ public List<SealedSenderAccess> getSealedSenderAccessFor(List<RecipientId> recipients) {
+ return recipients.stream().map(this::getAccessFor).map(SealedSenderAccess::forIndividual).toList();
+ }
+
+ public @Nullable SealedSenderAccess getSealedSenderAccessFor(RecipientId recipient) {
+ return getSealedSenderAccessFor(recipient, false);
+ }
+
+ public @Nullable SealedSenderAccess getSealedSenderAccessFor(RecipientId recipient, boolean noRefresh) {
+ return SealedSenderAccess.forIndividual(getAccessFor(recipient, noRefresh));
+ }
+
+ public List<UnidentifiedAccess> getAccessFor(List<RecipientId> recipients) {
return recipients.stream().map(this::getAccessFor).toList();
}
- public Optional<UnidentifiedAccessPair> getAccessFor(RecipientId recipient) {
+ private @Nullable UnidentifiedAccess getAccessFor(RecipientId recipient) {
return getAccessFor(recipient, false);
}
- public Optional<UnidentifiedAccessPair> getAccessFor(RecipientId recipientId, boolean noRefresh) {
+ private @Nullable UnidentifiedAccess getAccessFor(RecipientId recipientId, boolean noRefresh) {
var recipientUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipientId, noRefresh);
if (recipientUnidentifiedAccessKey == null) {
logger.trace("Unidentified access not available for {}", recipientId);
- return Optional.empty();
+ return null;
}
var selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(noRefresh);
if (selfUnidentifiedAccessKey == null) {
logger.trace("Unidentified access not available for self");
- return Optional.empty();
+ return null;
}
var senderCertificate = getSenderCertificateFor(recipientId);
if (senderCertificate == null) {
logger.trace("Unidentified access not available due to missing sender certificate");
- return Optional.empty();
- }
-
- try {
- return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(recipientUnidentifiedAccessKey,
- senderCertificate,
- false), new UnidentifiedAccess(selfUnidentifiedAccessKey, senderCertificate, false)));
- } catch (InvalidCertificateException e) {
- return Optional.empty();
- }
- }
-
- public Optional<UnidentifiedAccessPair> getAccessForSync() {
- var selfUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(false);
- var selfUnidentifiedAccessCertificate = getSenderCertificate();
-
- if (selfUnidentifiedAccessKey == null || selfUnidentifiedAccessCertificate == null) {
- return Optional.empty();
+ return null;
}
try {
- return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(selfUnidentifiedAccessKey,
- selfUnidentifiedAccessCertificate,
- false),
- new UnidentifiedAccess(selfUnidentifiedAccessKey, selfUnidentifiedAccessCertificate, false)));
+ return new UnidentifiedAccess(recipientUnidentifiedAccessKey, senderCertificate, false);
} catch (InvalidCertificateException e) {
- return Optional.empty();
+ return null;
}
}
private byte[] getSenderCertificateFor(final RecipientId recipientId) {
final var sharingMode = account.getConfigurationStore().getPhoneNumberSharingMode();
- if (sharingMode == null || sharingMode == PhoneNumberSharingMode.EVERYBODY || (
+ if (sharingMode == PhoneNumberSharingMode.EVERYBODY || (
sharingMode == PhoneNumberSharingMode.CONTACTS
&& account.getContactStore().getContact(recipientId) != null
)) {
return privacySenderCertificate.getSerialized();
}
try {
- final var certificate = dependencies.getAccountManager().getSenderCertificateForPhoneNumberPrivacy();
+ final var certificate = handleResponseException(dependencies.getCertificateApi()
+ .getSenderCertificateForPhoneNumberPrivacy());
privacySenderCertificate = new SenderCertificate(certificate);
return certificate;
} catch (IOException | InvalidCertificateException e) {
- logger.warn("Failed to get sender certificate, ignoring: {}", e.getMessage());
+ logger.warn("Failed to get sender certificate (pnp), ignoring: {}", e.getMessage());
return null;
}
}
return senderCertificate.getSerialized();
}
try {
- final var certificate = dependencies.getAccountManager().getSenderCertificate();
+ final var certificate = handleResponseException(dependencies.getCertificateApi().getSenderCertificate());
this.senderCertificate = new SenderCertificate(certificate);
return certificate;
} catch (IOException | InvalidCertificateException e) {
}
private static byte[] getTargetUnidentifiedAccessKey(
- final Profile targetProfile, final ProfileKey theirProfileKey
+ final Profile targetProfile,
+ final ProfileKey theirProfileKey
) {
return switch (targetProfile.getUnidentifiedAccessMode()) {
case ENABLED -> theirProfileKey == null ? null : UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);