package org.asamk.signal.manager.helper;
import org.asamk.signal.manager.api.IncorrectPinException;
-import org.asamk.signal.manager.api.Pair;
-import org.signal.libsignal.protocol.InvalidKeyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.KeyBackupService;
-import org.whispersystems.signalservice.api.KeyBackupServicePinException;
-import org.whispersystems.signalservice.api.SvrNoDataException;
-import org.whispersystems.signalservice.api.SvrPinData;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
+import org.whispersystems.signalservice.api.svr.SecureValueRecovery;
+import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV1;
+import org.whispersystems.signalservice.api.svr.SecureValueRecoveryV2;
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
-import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
import org.whispersystems.signalservice.internal.push.AuthCredentials;
import org.whispersystems.signalservice.internal.push.LockedException;
import java.io.IOException;
import java.util.Collection;
-import java.util.stream.Stream;
public class PinHelper {
private final static Logger logger = LoggerFactory.getLogger(PinHelper.class);
private final KeyBackupService keyBackupService;
+ private final SecureValueRecoveryV1 secureValueRecoveryV1;
+ private final SecureValueRecoveryV2 secureValueRecoveryV2;
private final Collection<KeyBackupService> fallbackKeyBackupServices;
public PinHelper(
- final KeyBackupService keyBackupService, final Collection<KeyBackupService> fallbackKeyBackupServices
+ final KeyBackupService keyBackupService,
+ final Collection<KeyBackupService> fallbackKeyBackupServices,
+ SecureValueRecoveryV2 secureValueRecoveryV2
) {
this.keyBackupService = keyBackupService;
this.fallbackKeyBackupServices = fallbackKeyBackupServices;
+ this.secureValueRecoveryV1 = new SecureValueRecoveryV1(keyBackupService);
+ this.secureValueRecoveryV2 = secureValueRecoveryV2;
}
public void setRegistrationLockPin(
throw new IOException(e);
}
pinChangeSession.enableRegistrationLock(masterKey);
+
+ final var backupResponse = secureValueRecoveryV2.setPin(pin, masterKey).execute();
+ if (backupResponse instanceof SecureValueRecovery.BackupResponse.Success) {
+ } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ServerRejected) {
+ logger.warn("Backup svr2 failed: ServerRejected");
+ } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.EnclaveNotFound) {
+ logger.warn("Backup svr2 failed: EnclaveNotFound");
+ } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ExposeFailure) {
+ logger.warn("Backup svr2 failed: ExposeFailure");
+ } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ApplicationError error) {
+ throw new IOException(error.getException());
+ } else if (backupResponse instanceof SecureValueRecovery.BackupResponse.NetworkError error) {
+ throw error.getException();
+ } else {
+ throw new AssertionError("Unexpected response");
+ }
}
public void migrateRegistrationLockPin(String pin, MasterKey masterKey) throws IOException {
} catch (UnauthenticatedResponseException e) {
throw new IOException(e);
}
+
+ final var deleteResponse = secureValueRecoveryV2.deleteData();
+ if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.Success) {
+ } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.ServerRejected) {
+ logger.warn("Delete svr2 failed: ServerRejected");
+ } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.EnclaveNotFound) {
+ logger.warn("Delete svr2 failed: EnclaveNotFound");
+ } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.ApplicationError error) {
+ throw new IOException(error.getException());
+ } else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.NetworkError error) {
+ throw error.getException();
+ } else {
+ throw new AssertionError("Unexpected response");
+ }
}
- public SvrPinData getRegistrationLockData(
+ public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
String pin, LockedException e
) throws IOException, IncorrectPinException {
- var basicStorageCredentials = e.getSvr1Credentials();
- if (basicStorageCredentials == null) {
- return null;
- }
-
- try {
- return getRegistrationLockData(pin, basicStorageCredentials);
- } catch (SvrNoDataException ex) {
- throw new IOException(e);
- } catch (KeyBackupServicePinException ex) {
- throw new IncorrectPinException(ex.getTriesRemaining());
+ var svr1Credentials = e.getSvr1Credentials();
+ if (svr1Credentials != null) {
+ return getRegistrationLockData(secureValueRecoveryV1, svr1Credentials, pin);
}
- }
- private SvrPinData getRegistrationLockData(
- String pin, AuthCredentials authCredentials
- ) throws IOException, SvrNoDataException, KeyBackupServicePinException {
- final var basicStorageCredentials = authCredentials.asBasic();
- var tokenResponsePair = getTokenResponse(basicStorageCredentials);
- final var tokenResponse = tokenResponsePair.first();
- final var keyBackupService = tokenResponsePair.second();
-
- var registrationLockData = restoreMasterKey(pin, basicStorageCredentials, tokenResponse, keyBackupService);
- if (registrationLockData == null) {
- throw new AssertionError("Failed to restore master key");
+ var svr2Credentials = e.getSvr2Credentials();
+ if (svr2Credentials != null) {
+ return getRegistrationLockData(secureValueRecoveryV2, svr2Credentials, pin);
}
- return registrationLockData;
- }
- private Pair<TokenResponse, KeyBackupService> getTokenResponse(String basicStorageCredentials) throws IOException {
- final var keyBackupServices = Stream.concat(Stream.of(keyBackupService), fallbackKeyBackupServices.stream())
- .toList();
- for (final var keyBackupService : keyBackupServices) {
- var tokenResponse = keyBackupService.getToken(basicStorageCredentials);
- if (tokenResponse != null && tokenResponse.getTries() > 0) {
- return new Pair<>(tokenResponse, keyBackupService);
- }
- }
- throw new IOException("KBS Account locked, maximum pin attempts reached.");
+ return null;
}
- private SvrPinData restoreMasterKey(
- String pin,
- String basicStorageCredentials,
- TokenResponse tokenResponse,
- final KeyBackupService keyBackupService
- ) throws IOException, SvrNoDataException, KeyBackupServicePinException {
- if (pin == null) return null;
-
- if (basicStorageCredentials == null) {
- throw new AssertionError("Cannot restore KBS key, no storage credentials supplied");
- }
-
- var session = keyBackupService.newRegistrationSession(basicStorageCredentials, tokenResponse);
-
- try {
- var hashedPin = PinHashUtil.hashPin(pin, session.hashSalt());
- var kbsData = session.restorePin(hashedPin);
- if (kbsData == null) {
- throw new AssertionError("Null not expected");
- }
- return kbsData;
- } catch (UnauthenticatedResponseException | InvalidKeyException e) {
- throw new IOException(e);
+ public SecureValueRecovery.RestoreResponse.Success getRegistrationLockData(
+ SecureValueRecovery secureValueRecovery, AuthCredentials authCredentials, String pin
+ ) throws IOException, IncorrectPinException {
+ final var restoreResponse = secureValueRecovery.restoreDataPreRegistration(authCredentials, pin);
+
+ if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.Success s) {
+ return s;
+ } else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.PinMismatch pinMismatch) {
+ throw new IncorrectPinException(pinMismatch.getTriesRemaining());
+ } else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.ApplicationError error) {
+ throw new IOException(error.getException());
+ } else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.NetworkError error) {
+ throw error.getException();
+ } else {
+ throw new AssertionError("Unexpected response");
}
}
}