]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/util/NumberVerificationUtils.java
Extract number verification code logic
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / util / NumberVerificationUtils.java
diff --git a/lib/src/main/java/org/asamk/signal/manager/util/NumberVerificationUtils.java b/lib/src/main/java/org/asamk/signal/manager/util/NumberVerificationUtils.java
new file mode 100644 (file)
index 0000000..1874bab
--- /dev/null
@@ -0,0 +1,101 @@
+package org.asamk.signal.manager.util;
+
+import org.asamk.signal.manager.api.CaptchaRequiredException;
+import org.asamk.signal.manager.api.IncorrectPinException;
+import org.asamk.signal.manager.api.Pair;
+import org.asamk.signal.manager.api.PinLockedException;
+import org.asamk.signal.manager.helper.PinHelper;
+import org.whispersystems.libsignal.util.guava.Optional;
+import org.whispersystems.signalservice.api.KbsPinData;
+import org.whispersystems.signalservice.api.SignalServiceAccountManager;
+import org.whispersystems.signalservice.api.kbs.MasterKey;
+import org.whispersystems.signalservice.internal.ServiceResponse;
+import org.whispersystems.signalservice.internal.push.LockedException;
+import org.whispersystems.signalservice.internal.push.RequestVerificationCodeResponse;
+import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
+
+import java.io.IOException;
+
+public class NumberVerificationUtils {
+
+    public static void requestVerificationCode(
+            SignalServiceAccountManager accountManager, String captcha, boolean voiceVerification
+    ) throws IOException, CaptchaRequiredException {
+        captcha = captcha == null ? null : captcha.replace("signalcaptcha://", "");
+
+        final ServiceResponse<RequestVerificationCodeResponse> response;
+        if (voiceVerification) {
+            response = accountManager.requestVoiceVerificationCode(Utils.getDefaultLocale(null),
+                    Optional.fromNullable(captcha),
+                    Optional.absent(),
+                    Optional.absent());
+        } else {
+            response = accountManager.requestSmsVerificationCode(false,
+                    Optional.fromNullable(captcha),
+                    Optional.absent(),
+                    Optional.absent());
+        }
+        try {
+            handleResponseException(response);
+        } catch (org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredException e) {
+            throw new CaptchaRequiredException(e.getMessage(), e);
+        }
+    }
+
+    public static Pair<VerifyAccountResponse, MasterKey> verifyNumber(
+            String verificationCode, String pin, PinHelper pinHelper, Verifier verifier
+    ) throws IOException, PinLockedException, IncorrectPinException {
+        verificationCode = verificationCode.replace("-", "");
+        try {
+            final var response = verifyAccountWithCode(verificationCode, null, verifier);
+
+            return new Pair<>(response, null);
+        } catch (LockedException e) {
+            if (pin == null) {
+                throw new PinLockedException(e.getTimeRemaining());
+            }
+
+            KbsPinData registrationLockData;
+            registrationLockData = pinHelper.getRegistrationLockData(pin, e);
+            if (registrationLockData == null) {
+                throw e;
+            }
+
+            var registrationLock = registrationLockData.getMasterKey().deriveRegistrationLock();
+            VerifyAccountResponse response;
+            try {
+                response = verifyAccountWithCode(verificationCode, registrationLock, verifier);
+            } catch (LockedException _e) {
+                throw new AssertionError("KBS Pin appeared to matched but reg lock still failed!");
+            }
+
+            return new Pair<>(response, registrationLockData.getMasterKey());
+        }
+    }
+
+    private static VerifyAccountResponse verifyAccountWithCode(
+            final String verificationCode, final String registrationLock, final Verifier verifier
+    ) throws IOException {
+        final var response = verifier.verify(verificationCode, registrationLock);
+        handleResponseException(response);
+        return response.getResult().get();
+    }
+
+    private static void handleResponseException(final ServiceResponse<?> response) throws IOException {
+        final var throwableOptional = response.getExecutionError().or(response.getApplicationError());
+        if (throwableOptional.isPresent()) {
+            if (throwableOptional.get() instanceof IOException) {
+                throw (IOException) throwableOptional.get();
+            } else {
+                throw new IOException(throwableOptional.get());
+            }
+        }
+    }
+
+    public interface Verifier {
+
+        ServiceResponse<VerifyAccountResponse> verify(
+                String verificationCode, String registrationLock
+        );
+    }
+}