]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java
Improve behavior when pin data doesn't exist on the server
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / internal / ManagerImpl.java
index 403b9adf7d3ac5ebd9ec7818d2c70eb9ea7187d4..ffb74de26a2b0e32d3b11b4b80d09b169d3b8461 100644 (file)
@@ -35,6 +35,7 @@ import org.asamk.signal.manager.api.IdentityVerificationCode;
 import org.asamk.signal.manager.api.InactiveGroupLinkException;
 import org.asamk.signal.manager.api.IncorrectPinException;
 import org.asamk.signal.manager.api.InvalidDeviceLinkException;
+import org.asamk.signal.manager.api.InvalidNumberException;
 import org.asamk.signal.manager.api.InvalidStickerException;
 import org.asamk.signal.manager.api.InvalidUsernameException;
 import org.asamk.signal.manager.api.LastGroupAdminException;
@@ -47,6 +48,7 @@ import org.asamk.signal.manager.api.NotPrimaryDeviceException;
 import org.asamk.signal.manager.api.Pair;
 import org.asamk.signal.manager.api.PendingAdminApprovalException;
 import org.asamk.signal.manager.api.PhoneNumberSharingMode;
+import org.asamk.signal.manager.api.PinLockMissingException;
 import org.asamk.signal.manager.api.PinLockedException;
 import org.asamk.signal.manager.api.Profile;
 import org.asamk.signal.manager.api.RateLimitException;
@@ -87,12 +89,12 @@ import org.asamk.signal.manager.storage.stickers.StickerPack;
 import org.asamk.signal.manager.util.AttachmentUtils;
 import org.asamk.signal.manager.util.KeyUtils;
 import org.asamk.signal.manager.util.MimeUtils;
+import org.asamk.signal.manager.util.PhoneNumberFormatter;
 import org.asamk.signal.manager.util.StickerUtils;
 import org.signal.libsignal.protocol.InvalidMessageException;
 import org.signal.libsignal.usernames.BaseUsernameException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.whispersystems.signalservice.api.SignalSessionLock;
 import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
 import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
 import org.whispersystems.signalservice.api.messages.SignalServicePreview;
@@ -106,8 +108,6 @@ import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhauste
 import org.whispersystems.signalservice.api.push.exceptions.UsernameMalformedException;
 import org.whispersystems.signalservice.api.push.exceptions.UsernameTakenException;
 import org.whispersystems.signalservice.api.util.DeviceNameUtil;
-import org.whispersystems.signalservice.api.util.InvalidNumberException;
-import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
 import org.whispersystems.signalservice.api.util.StreamDetails;
 import org.whispersystems.signalservice.internal.util.Hex;
 import org.whispersystems.signalservice.internal.util.Util;
@@ -132,7 +132,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -142,6 +142,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
 import okio.Utf8;
 
 import static org.asamk.signal.manager.config.ServiceConfig.MAX_MESSAGE_SIZE_BYTES;
+import static org.asamk.signal.manager.util.Utils.handleResponseException;
 import static org.signal.core.util.StringExtensionsKt.splitByByteLength;
 
 public class ManagerImpl implements Manager {
@@ -161,6 +162,7 @@ public class ManagerImpl implements Manager {
     private final List<Runnable> closedListeners = new ArrayList<>();
     private final List<Runnable> addressChangedListeners = new ArrayList<>();
     private final CompositeDisposable disposable = new CompositeDisposable();
+    private final AtomicLong lastMessageTimestamp = new AtomicLong();
 
     public ManagerImpl(
             SignalAccount account,
@@ -171,15 +173,7 @@ public class ManagerImpl implements Manager {
     ) {
         this.account = account;
 
-        final var sessionLock = new SignalSessionLock() {
-            private final ReentrantLock LEGACY_LOCK = new ReentrantLock();
-
-            @Override
-            public Lock acquire() {
-                LEGACY_LOCK.lock();
-                return LEGACY_LOCK::unlock;
-            }
-        };
+        final var sessionLock = new ReentrantSignalSessionLock();
         this.dependencies = new SignalDependencies(serviceEnvironmentConfig,
                 userAgent,
                 account.getCredentialsProvider(),
@@ -435,7 +429,7 @@ public class ManagerImpl implements Manager {
             String newNumber,
             String verificationCode,
             String pin
-    ) throws IncorrectPinException, PinLockedException, IOException, NotPrimaryDeviceException {
+    ) throws IncorrectPinException, PinLockedException, IOException, NotPrimaryDeviceException, PinLockMissingException {
         if (!account.isPrimaryDevice()) {
             throw new NotPrimaryDeviceException();
         }
@@ -457,10 +451,10 @@ public class ManagerImpl implements Manager {
             String challenge,
             String captcha
     ) throws IOException, CaptchaRejectedException {
-        captcha = captcha == null ? null : captcha.replace("signalcaptcha://", "");
+        captcha = captcha == null ? "" : captcha.replace("signalcaptcha://", "");
 
         try {
-            dependencies.getAccountManager().submitRateLimitRecaptchaChallenge(challenge, captcha);
+            handleResponseException(dependencies.getRateLimitChallengeApi().submitCaptchaChallenge(challenge, captcha));
         } catch (org.whispersystems.signalservice.internal.push.exceptions.CaptchaRejectedException ignored) {
             throw new CaptchaRejectedException();
         }
@@ -468,7 +462,7 @@ public class ManagerImpl implements Manager {
 
     @Override
     public List<Device> getLinkedDevices() throws IOException {
-        var devices = dependencies.getAccountManager().getDevices();
+        var devices = handleResponseException(dependencies.getLinkDeviceApi().getDevices());
         account.setMultiDevice(devices.size() > 1);
         var identityKey = account.getAciIdentityKeyPair().getPrivateKey();
         return devices.stream().map(d -> {
@@ -607,6 +601,24 @@ public class ManagerImpl implements Manager {
         return context.getGroupHelper().joinGroup(inviteLinkUrl);
     }
 
+    private long getNextMessageTimestamp() {
+        while (true) {
+            final var last = lastMessageTimestamp.get();
+            final var timestamp = System.currentTimeMillis();
+            if (last == timestamp) {
+                try {
+                    Thread.sleep(1);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+                continue;
+            }
+            if (lastMessageTimestamp.compareAndSet(last, timestamp)) {
+                return timestamp;
+            }
+        }
+    }
+
     private SendMessageResults sendMessage(
             SignalServiceDataMessage.Builder messageBuilder,
             Set<RecipientIdentifier> recipients,
@@ -622,7 +634,7 @@ public class ManagerImpl implements Manager {
             Optional<Long> editTargetTimestamp
     ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
         var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>();
-        long timestamp = System.currentTimeMillis();
+        long timestamp = getNextMessageTimestamp();
         messageBuilder.withTimestamp(timestamp);
         for (final var recipient : recipients) {
             if (recipient instanceof RecipientIdentifier.NoteToSelf || (
@@ -662,7 +674,7 @@ public class ManagerImpl implements Manager {
             Set<RecipientIdentifier> recipients
     ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
         var results = new HashMap<RecipientIdentifier, List<SendMessageResult>>();
-        final var timestamp = System.currentTimeMillis();
+        final var timestamp = getNextMessageTimestamp();
         for (var recipient : recipients) {
             if (recipient instanceof RecipientIdentifier.Single single) {
                 final var message = new SignalServiceTypingMessage(action, timestamp, Optional.empty());
@@ -694,7 +706,7 @@ public class ManagerImpl implements Manager {
 
     @Override
     public SendMessageResults sendReadReceipt(RecipientIdentifier.Single sender, List<Long> messageIds) {
-        final var timestamp = System.currentTimeMillis();
+        final var timestamp = getNextMessageTimestamp();
         var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ,
                 messageIds,
                 timestamp);
@@ -704,7 +716,7 @@ public class ManagerImpl implements Manager {
 
     @Override
     public SendMessageResults sendViewedReceipt(RecipientIdentifier.Single sender, List<Long> messageIds) {
-        final var timestamp = System.currentTimeMillis();
+        final var timestamp = getNextMessageTimestamp();
         var receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED,
                 messageIds,
                 timestamp);
@@ -1594,7 +1606,8 @@ public class ManagerImpl implements Manager {
         context.close();
         executor.close();
 
-        dependencies.getSignalWebSocket().disconnect();
+        dependencies.getAuthenticatedSignalWebSocket().disconnect();
+        dependencies.getUnauthenticatedSignalWebSocket().disconnect();
         dependencies.getPushServiceSocket().close();
         disposable.dispose();