X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/997b3c6a2a1f2e9a50fe579ac726677ea0d57d0c..d4b9356c5c05e36f217ad803d51b8808598d3ae7:/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index a14f2d1f..cc90de5c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -38,6 +38,7 @@ import org.asamk.signal.manager.helper.AttachmentHelper; import org.asamk.signal.manager.helper.ContactHelper; import org.asamk.signal.manager.helper.GroupHelper; import org.asamk.signal.manager.helper.GroupV2Helper; +import org.asamk.signal.manager.helper.IdentityHelper; import org.asamk.signal.manager.helper.IncomingMessageHandler; import org.asamk.signal.manager.helper.PinHelper; import org.asamk.signal.manager.helper.PreKeyHelper; @@ -59,15 +60,10 @@ import org.asamk.signal.manager.storage.stickers.Sticker; import org.asamk.signal.manager.storage.stickers.StickerPackId; import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.StickerUtils; -import org.asamk.signal.manager.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.ecc.ECPublicKey; -import org.whispersystems.libsignal.fingerprint.Fingerprint; -import org.whispersystems.libsignal.fingerprint.FingerprintParsingException; -import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException; import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalSessionLock; @@ -98,9 +94,7 @@ import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.SignatureException; -import java.util.Arrays; import java.util.Collection; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -112,7 +106,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import java.util.stream.Collectors; import static org.asamk.signal.manager.config.ServiceConfig.capabilities; @@ -138,6 +131,7 @@ public class ManagerImpl implements Manager { private final ContactHelper contactHelper; private final IncomingMessageHandler incomingMessageHandler; private final PreKeyHelper preKeyHelper; + private final IdentityHelper identityHelper; private final Context context; private boolean hasCaughtUpWithOldMessages = false; @@ -238,6 +232,11 @@ public class ManagerImpl implements Manager { syncHelper, this::getRecipientProfile, jobExecutor); + this.identityHelper = new IdentityHelper(account, + dependencies, + this::resolveSignalServiceAddress, + syncHelper, + profileHelper); } @Override @@ -888,6 +887,8 @@ public class ManagerImpl implements Manager { signalWebSocket.connect(); hasCaughtUpWithOldMessages = false; + var backOffCounter = 0; + final var MAX_BACKOFF_COUNTER = 9; while (!Thread.interrupted()) { SignalServiceEnvelope envelope; @@ -902,6 +903,8 @@ public class ManagerImpl implements Manager { // store message on disk, before acknowledging receipt to the server cachedMessage[0] = account.getMessageCache().cacheMessage(envelope1, recipientId); }); + backOffCounter = 0; + if (result.isPresent()) { envelope = result.get(); logger.debug("New message received from server"); @@ -925,11 +928,24 @@ public class ManagerImpl implements Manager { } else { throw e; } - } catch (WebSocketUnavailableException e) { - logger.debug("Pipe unexpectedly unavailable, connecting"); - signalWebSocket.connect(); - continue; + } catch (IOException e) { + logger.debug("Pipe unexpectedly unavailable: {}", e.getMessage()); + if (e instanceof WebSocketUnavailableException || "Connection closed!".equals(e.getMessage())) { + final var sleepMilliseconds = 100 * (long) Math.pow(2, backOffCounter); + backOffCounter = Math.min(backOffCounter + 1, MAX_BACKOFF_COUNTER); + logger.warn("Connection closed unexpectedly, reconnecting in {} ms", sleepMilliseconds); + try { + Thread.sleep(sleepMilliseconds); + } catch (InterruptedException interruptedException) { + return; + } + hasCaughtUpWithOldMessages = false; + signalWebSocket.connect(); + continue; + } + throw e; } catch (TimeoutException e) { + backOffCounter = 0; if (returnOnTimeout) return; continue; } @@ -940,9 +956,11 @@ public class ManagerImpl implements Manager { if (hasCaughtUpWithOldMessages) { handleQueuedActions(queuedActions); + queuedActions.clear(); } if (cachedMessage[0] != null) { if (exception instanceof UntrustedIdentityException) { + logger.debug("Keeping message with untrusted identity in message cache"); final var address = ((UntrustedIdentityException) exception).getSender(); final var recipientId = resolveRecipient(address); if (!envelope.hasSourceUuid()) { @@ -959,6 +977,7 @@ public class ManagerImpl implements Manager { } } handleQueuedActions(queuedActions); + queuedActions.clear(); } @Override @@ -967,6 +986,7 @@ public class ManagerImpl implements Manager { } private void handleQueuedActions(final Collection queuedActions) { + logger.debug("Handling message actions"); var interrupted = false; for (var action : queuedActions) { try { @@ -1042,7 +1062,7 @@ public class ManagerImpl implements Manager { return toGroup(groupHelper.getGroup(groupId)); } - public GroupInfo getGroupInfo(GroupId groupId) { + private GroupInfo getGroupInfo(GroupId groupId) { return groupHelper.getGroup(groupId); } @@ -1061,10 +1081,12 @@ public class ManagerImpl implements Manager { } final var address = account.getRecipientStore().resolveRecipientAddress(identityInfo.getRecipientId()); + final var scannableFingerprint = identityHelper.computeSafetyNumberForScanning(identityInfo.getRecipientId(), + identityInfo.getIdentityKey()); return new Identity(address, identityInfo.getIdentityKey(), - computeSafetyNumber(address.toSignalServiceAddress(), identityInfo.getIdentityKey()), - computeSafetyNumberForScanning(address.toSignalServiceAddress(), identityInfo.getIdentityKey()), + identityHelper.computeSafetyNumber(identityInfo.getRecipientId(), identityInfo.getIdentityKey()), + scannableFingerprint == null ? null : scannableFingerprint.getSerialized(), identityInfo.getTrustLevel(), identityInfo.getDateAdded()); } @@ -1094,9 +1116,7 @@ public class ManagerImpl implements Manager { } catch (UnregisteredUserException e) { return false; } - return trustIdentity(recipientId, - identityKey -> Arrays.equals(identityKey.serialize(), fingerprint), - TrustLevel.TRUSTED_VERIFIED); + return identityHelper.trustIdentityVerified(recipientId, fingerprint); } /** @@ -1113,10 +1133,7 @@ public class ManagerImpl implements Manager { } catch (UnregisteredUserException e) { return false; } - var address = resolveSignalServiceAddress(recipientId); - return trustIdentity(recipientId, - identityKey -> safetyNumber.equals(computeSafetyNumber(address, identityKey)), - TrustLevel.TRUSTED_VERIFIED); + return identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber); } /** @@ -1133,15 +1150,7 @@ public class ManagerImpl implements Manager { } catch (UnregisteredUserException e) { return false; } - var address = resolveSignalServiceAddress(recipientId); - return trustIdentity(recipientId, identityKey -> { - final var fingerprint = computeSafetyNumberFingerprint(address, identityKey); - try { - return fingerprint != null && fingerprint.getScannableFingerprint().compareTo(safetyNumber); - } catch (FingerprintVersionMismatchException | FingerprintParsingException e) { - return false; - } - }, TrustLevel.TRUSTED_VERIFIED); + return identityHelper.trustIdentityVerifiedSafetyNumber(recipientId, safetyNumber); } /** @@ -1157,66 +1166,13 @@ public class ManagerImpl implements Manager { } catch (UnregisteredUserException e) { return false; } - return trustIdentity(recipientId, identityKey -> true, TrustLevel.TRUSTED_UNVERIFIED); - } - - private boolean trustIdentity( - RecipientId recipientId, Function verifier, TrustLevel trustLevel - ) { - var identity = account.getIdentityKeyStore().getIdentity(recipientId); - if (identity == null) { - return false; - } - - if (!verifier.apply(identity.getIdentityKey())) { - return false; - } - - account.getIdentityKeyStore().setIdentityTrustLevel(recipientId, identity.getIdentityKey(), trustLevel); - try { - var address = resolveSignalServiceAddress(recipientId); - syncHelper.sendVerifiedMessage(address, identity.getIdentityKey(), trustLevel); - } catch (IOException e) { - logger.warn("Failed to send verification sync message: {}", e.getMessage()); - } - - return true; + return identityHelper.trustIdentityAllKeys(recipientId); } private void handleIdentityFailure( final RecipientId recipientId, final SendMessageResult.IdentityFailure identityFailure ) { - final var identityKey = identityFailure.getIdentityKey(); - if (identityKey != null) { - final var newIdentity = account.getIdentityKeyStore().saveIdentity(recipientId, identityKey, new Date()); - if (newIdentity) { - account.getSessionStore().archiveSessions(recipientId); - } - } else { - // Retrieve profile to get the current identity key from the server - profileHelper.refreshRecipientProfile(recipientId); - } - } - - @Override - public String computeSafetyNumber(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { - final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey); - return fingerprint == null ? null : fingerprint.getDisplayableFingerprint().getDisplayText(); - } - - private byte[] computeSafetyNumberForScanning(SignalServiceAddress theirAddress, IdentityKey theirIdentityKey) { - final Fingerprint fingerprint = computeSafetyNumberFingerprint(theirAddress, theirIdentityKey); - return fingerprint == null ? null : fingerprint.getScannableFingerprint().getSerialized(); - } - - private Fingerprint computeSafetyNumberFingerprint( - final SignalServiceAddress theirAddress, final IdentityKey theirIdentityKey - ) { - return Utils.computeSafetyNumber(capabilities.isUuid(), - account.getSelfAddress(), - account.getIdentityKeyPair().getPublicKey(), - theirAddress, - theirIdentityKey); + this.identityHelper.handleIdentityFailure(recipientId, identityFailure); } @Override @@ -1291,5 +1247,4 @@ public class ManagerImpl implements Manager { } account = null; } - }