]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/helper/PinHelper.java
Refactor identity key store
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / helper / PinHelper.java
1 package org.asamk.signal.manager.helper;
2
3 import org.asamk.signal.manager.api.IncorrectPinException;
4 import org.asamk.signal.manager.util.PinHashing;
5 import org.signal.libsignal.protocol.InvalidKeyException;
6 import org.whispersystems.signalservice.api.KbsPinData;
7 import org.whispersystems.signalservice.api.KeyBackupService;
8 import org.whispersystems.signalservice.api.KeyBackupServicePinException;
9 import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
10 import org.whispersystems.signalservice.api.kbs.MasterKey;
11 import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
12 import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
13 import org.whispersystems.signalservice.internal.push.LockedException;
14
15 import java.io.IOException;
16
17 public class PinHelper {
18
19 private final KeyBackupService keyBackupService;
20
21 public PinHelper(final KeyBackupService keyBackupService) {
22 this.keyBackupService = keyBackupService;
23 }
24
25 public void setRegistrationLockPin(
26 String pin, MasterKey masterKey
27 ) throws IOException {
28 final var pinChangeSession = keyBackupService.newPinChangeSession();
29 final var hashedPin = PinHashing.hashPin(pin, pinChangeSession);
30
31 try {
32 pinChangeSession.setPin(hashedPin, masterKey);
33 } catch (UnauthenticatedResponseException e) {
34 throw new IOException(e);
35 }
36 pinChangeSession.enableRegistrationLock(masterKey);
37 }
38
39 public void removeRegistrationLockPin() throws IOException {
40 final var pinChangeSession = keyBackupService.newPinChangeSession();
41 pinChangeSession.disableRegistrationLock();
42 try {
43 pinChangeSession.removePin();
44 } catch (UnauthenticatedResponseException e) {
45 throw new IOException(e);
46 }
47 }
48
49 public KbsPinData getRegistrationLockData(
50 String pin, LockedException e
51 ) throws IOException, IncorrectPinException {
52 var basicStorageCredentials = e.getBasicStorageCredentials();
53 if (basicStorageCredentials == null) {
54 return null;
55 }
56
57 try {
58 return getRegistrationLockData(pin, basicStorageCredentials);
59 } catch (KeyBackupSystemNoDataException ex) {
60 throw new IOException(e);
61 } catch (KeyBackupServicePinException ex) {
62 throw new IncorrectPinException(ex.getTriesRemaining());
63 }
64 }
65
66 private KbsPinData getRegistrationLockData(
67 String pin, String basicStorageCredentials
68 ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException {
69 var tokenResponse = keyBackupService.getToken(basicStorageCredentials);
70 if (tokenResponse == null || tokenResponse.getTries() == 0) {
71 throw new IOException("KBS Account locked, maximum pin attempts reached.");
72 }
73
74 var registrationLockData = restoreMasterKey(pin, basicStorageCredentials, tokenResponse);
75 if (registrationLockData == null) {
76 throw new AssertionError("Failed to restore master key");
77 }
78 return registrationLockData;
79 }
80
81 private KbsPinData restoreMasterKey(
82 String pin, String basicStorageCredentials, TokenResponse tokenResponse
83 ) throws IOException, KeyBackupSystemNoDataException, KeyBackupServicePinException {
84 if (pin == null) return null;
85
86 if (basicStorageCredentials == null) {
87 throw new AssertionError("Cannot restore KBS key, no storage credentials supplied");
88 }
89
90 var session = keyBackupService.newRegistrationSession(basicStorageCredentials, tokenResponse);
91
92 try {
93 var hashedPin = PinHashing.hashPin(pin, session);
94 var kbsData = session.restorePin(hashedPin);
95 if (kbsData == null) {
96 throw new AssertionError("Null not expected");
97 }
98 return kbsData;
99 } catch (UnauthenticatedResponseException | InvalidKeyException e) {
100 throw new IOException(e);
101 }
102 }
103 }