package org.asamk.signal.manager.helper;
-import org.asamk.signal.manager.util.PinHashing;
-import org.whispersystems.libsignal.InvalidKeyException;
-import org.whispersystems.signalservice.api.KbsPinData;
-import org.whispersystems.signalservice.api.KeyBackupService;
-import org.whispersystems.signalservice.api.KeyBackupServicePinException;
-import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
-import org.whispersystems.signalservice.api.kbs.HashedPin;
+import org.asamk.signal.manager.api.IncorrectPinException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.kbs.MasterKey;
-import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
-import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
+import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
+import org.whispersystems.signalservice.internal.push.AuthCredentials;
import org.whispersystems.signalservice.internal.push.LockedException;
import java.io.IOException;
+import java.util.List;
public class PinHelper {
- private final KeyBackupService keyBackupService;
+ private static final Logger logger = LoggerFactory.getLogger(PinHelper.class);
- public PinHelper(final KeyBackupService keyBackupService) {
- this.keyBackupService = keyBackupService;
- }
-
- public void setRegistrationLockPin(
- String pin, MasterKey masterKey
- ) throws IOException, UnauthenticatedResponseException {
- final KeyBackupService.PinChangeSession pinChangeSession = keyBackupService.newPinChangeSession();
- final HashedPin hashedPin = PinHashing.hashPin(pin, pinChangeSession);
-
- pinChangeSession.setPin(hashedPin, masterKey);
- pinChangeSession.enableRegistrationLock(masterKey);
- }
+ private final List<SecureValueRecovery> secureValueRecoveries;
- public void removeRegistrationLockPin() throws IOException, UnauthenticatedResponseException {
- final KeyBackupService.PinChangeSession pinChangeSession = keyBackupService.newPinChangeSession();
- pinChangeSession.disableRegistrationLock();
- pinChangeSession.removePin();
+ public PinHelper(final List<SecureValueRecovery> secureValueRecoveries) {
+ this.secureValueRecoveries = secureValueRecoveries;
}
- public KbsPinData getRegistrationLockData(
- String pin, LockedException e
- ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException {
- String basicStorageCredentials = e.getBasicStorageCredentials();
- if (basicStorageCredentials == null) {
- return null;
+ public void setRegistrationLockPin(String pin, MasterKey masterKey) throws IOException {
+ IOException exception = null;
+ for (final var secureValueRecovery : secureValueRecoveries) {
+ try {
+ final var backupResponse = secureValueRecovery.setPin(pin, masterKey).execute();
+ switch (backupResponse) {
+ case SecureValueRecovery.BackupResponse.Success success -> {
+ }
+ case SecureValueRecovery.BackupResponse.ServerRejected serverRejected ->
+ logger.warn("Backup svr failed: ServerRejected");
+ case SecureValueRecovery.BackupResponse.EnclaveNotFound enclaveNotFound ->
+ logger.warn("Backup svr failed: EnclaveNotFound");
+ case SecureValueRecovery.BackupResponse.ExposeFailure exposeFailure ->
+ logger.warn("Backup svr failed: ExposeFailure");
+ case SecureValueRecovery.BackupResponse.ApplicationError error ->
+ throw new IOException(error.getException());
+ case SecureValueRecovery.BackupResponse.NetworkError error -> throw error.getException();
+ case null, default -> throw new AssertionError("Unexpected response");
+ }
+ } catch (IOException e) {
+ exception = e;
+ }
+ }
+ if (exception != null) {
+ throw exception;
}
+ }
- return getRegistrationLockData(pin, basicStorageCredentials);
+ public void migrateRegistrationLockPin(String pin, MasterKey masterKey) throws IOException {
+ setRegistrationLockPin(pin, masterKey);
}
- private KbsPinData getRegistrationLockData(
- String pin, String basicStorageCredentials
- ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException {
- TokenResponse tokenResponse = keyBackupService.getToken(basicStorageCredentials);
- if (tokenResponse == null || tokenResponse.getTries() == 0) {
- throw new IOException("KBS Account locked");
+ public void removeRegistrationLockPin() throws IOException {
+ IOException exception = null;
+ for (final var secureValueRecovery : secureValueRecoveries) {
+ try {
+ final var deleteResponse = secureValueRecovery.deleteData();
+ switch (deleteResponse) {
+ case SecureValueRecovery.DeleteResponse.Success success -> {
+ }
+ case SecureValueRecovery.DeleteResponse.ServerRejected serverRejected ->
+ logger.warn("Delete svr2 failed: ServerRejected");
+ case SecureValueRecovery.DeleteResponse.EnclaveNotFound enclaveNotFound ->
+ logger.warn("Delete svr2 failed: EnclaveNotFound");
+ case SecureValueRecovery.DeleteResponse.ApplicationError error ->
+ throw new IOException(error.getException());
+ case SecureValueRecovery.DeleteResponse.NetworkError error -> throw error.getException();
+ case null, default -> throw new AssertionError("Unexpected response");
+ }
+ } catch (IOException e) {
+ exception = e;
+ }
}
-
- KbsPinData registrationLockData = restoreMasterKey(pin, basicStorageCredentials, tokenResponse);
- if (registrationLockData == null) {
- throw new AssertionError("Failed to restore master key");
+ if (exception != null) {
+ throw exception;
}
- return registrationLockData;
}
- private KbsPinData restoreMasterKey(
- String pin, String basicStorageCredentials, TokenResponse tokenResponse
- ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException {
- if (pin == null) return null;
-
- if (basicStorageCredentials == null) {
- throw new AssertionError("Cannot restore KBS key, no storage credentials supplied");
+ public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
+ String pin,
+ LockedException lockedException
+ ) throws IOException, IncorrectPinException {
+ var svr2Credentials = lockedException.getSvr2Credentials();
+ if (svr2Credentials != null) {
+ IOException exception = null;
+ for (final var secureValueRecovery : secureValueRecoveries) {
+ try {
+ final var lockData = getRegistrationLockData(secureValueRecovery, svr2Credentials, pin);
+ if (lockData == null) {
+ continue;
+ }
+ return lockData;
+ } catch (IOException e) {
+ exception = e;
+ }
+ }
+ if (exception != null) {
+ throw exception;
+ }
}
- KeyBackupService.RestoreSession session = keyBackupService.newRegistrationSession(basicStorageCredentials,
- tokenResponse);
+ return null;
+ }
+
+ public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
+ SecureValueRecovery secureValueRecovery,
+ AuthCredentials authCredentials,
+ String pin
+ ) throws IOException, IncorrectPinException {
+ final var restoreResponse = secureValueRecovery.restoreDataPreRegistration(authCredentials, null, pin);
- try {
- HashedPin hashedPin = PinHashing.hashPin(pin, session);
- KbsPinData kbsData = session.restorePin(hashedPin);
- if (kbsData == null) {
- throw new AssertionError("Null not expected");
+ switch (restoreResponse) {
+ case SecureValueRecovery.RestoreResponse.Success s -> {
+ return s;
+ }
+ case SecureValueRecovery.RestoreResponse.PinMismatch pinMismatch ->
+ throw new IncorrectPinException(pinMismatch.getTriesRemaining());
+ case SecureValueRecovery.RestoreResponse.ApplicationError error ->
+ throw new IOException(error.getException());
+ case SecureValueRecovery.RestoreResponse.NetworkError error -> throw error.getException();
+ case SecureValueRecovery.RestoreResponse.Missing missing -> {
+ logger.debug("No SVR data stored for the given credentials.");
+ return null;
}
- return kbsData;
- } catch (UnauthenticatedResponseException | InvalidKeyException e) {
- throw new IOException(e);
+ case null, default ->
+ throw new AssertionError("Unexpected response: " + restoreResponse.getClass().getSimpleName());
}
}
}