]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java
0ca9b0abbdebf4588b0d19f3e210572ab92d1efd
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / SignalAccountFiles.java
1 package org.asamk.signal.manager;
2
3 import org.asamk.signal.manager.api.AccountCheckException;
4 import org.asamk.signal.manager.api.NotRegisteredException;
5 import org.asamk.signal.manager.config.ServiceConfig;
6 import org.asamk.signal.manager.config.ServiceEnvironment;
7 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
8 import org.asamk.signal.manager.storage.SignalAccount;
9 import org.asamk.signal.manager.storage.accounts.AccountsStore;
10 import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
11 import org.asamk.signal.manager.util.KeyUtils;
12 import org.signal.libsignal.protocol.util.KeyHelper;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.util.Objects;
19 import java.util.Set;
20 import java.util.function.Consumer;
21
22 public class SignalAccountFiles {
23
24 private static final Logger logger = LoggerFactory.getLogger(MultiAccountManager.class);
25
26 private final PathConfig pathConfig;
27 private final ServiceEnvironmentConfig serviceEnvironmentConfig;
28 private final String userAgent;
29 private final TrustNewIdentity trustNewIdentity;
30 private final AccountsStore accountsStore;
31
32 public SignalAccountFiles(
33 final File settingsPath,
34 final ServiceEnvironment serviceEnvironment,
35 final String userAgent,
36 final TrustNewIdentity trustNewIdentity
37 ) throws IOException {
38 this.pathConfig = PathConfig.createDefault(settingsPath);
39 this.serviceEnvironmentConfig = ServiceConfig.getServiceEnvironmentConfig(serviceEnvironment, userAgent);
40 this.userAgent = userAgent;
41 this.trustNewIdentity = trustNewIdentity;
42 this.accountsStore = new AccountsStore(pathConfig.dataPath());
43 }
44
45 public Set<String> getAllLocalAccountNumbers() {
46 return accountsStore.getAllNumbers();
47 }
48
49 public MultiAccountManager initMultiAccountManager() {
50 final var managers = accountsStore.getAllAccounts().parallelStream().map(a -> {
51 try {
52 return initManager(a.number(), a.path());
53 } catch (NotRegisteredException | IOException | AccountCheckException e) {
54 logger.warn("Ignoring {}: {} ({})", a.number(), e.getMessage(), e.getClass().getSimpleName());
55 return null;
56 }
57 }).filter(Objects::nonNull).toList();
58
59 return new MultiAccountManagerImpl(managers, this);
60 }
61
62 public Manager initManager(String number) throws IOException, NotRegisteredException, AccountCheckException {
63 final var accountPath = accountsStore.getPathByNumber(number);
64 return this.initManager(number, accountPath);
65 }
66
67 private Manager initManager(
68 String number, String accountPath
69 ) throws IOException, NotRegisteredException, AccountCheckException {
70 if (accountPath == null) {
71 throw new NotRegisteredException();
72 }
73 if (!SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)) {
74 throw new NotRegisteredException();
75 }
76
77 var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, trustNewIdentity);
78 if (!number.equals(account.getNumber())) {
79 account.close();
80 throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
81 }
82
83 if (!account.isRegistered()) {
84 account.close();
85 throw new NotRegisteredException();
86 }
87
88 account.initDatabase();
89
90 final var manager = new ManagerImpl(account,
91 pathConfig,
92 (newNumber, newAci) -> accountsStore.updateAccount(accountPath, newNumber, newAci),
93 serviceEnvironmentConfig,
94 userAgent);
95
96 try {
97 manager.checkAccountState();
98 } catch (IOException e) {
99 manager.close();
100 throw new AccountCheckException("Error while checking account " + number + ": " + e.getMessage(), e);
101 }
102
103 return manager;
104 }
105
106 public ProvisioningManager initProvisioningManager() {
107 return initProvisioningManager(null);
108 }
109
110 public ProvisioningManager initProvisioningManager(Consumer<Manager> newManagerListener) {
111 return new ProvisioningManagerImpl(pathConfig,
112 serviceEnvironmentConfig,
113 userAgent,
114 newManagerListener,
115 accountsStore);
116 }
117
118 public RegistrationManager initRegistrationManager(String number) throws IOException {
119 return initRegistrationManager(number, null);
120 }
121
122 public RegistrationManager initRegistrationManager(
123 String number, Consumer<Manager> newManagerListener
124 ) throws IOException {
125 final var accountPath = accountsStore.getPathByNumber(number);
126 if (accountPath == null || !SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)) {
127 final var newAccountPath = accountPath == null ? accountsStore.addAccount(number, null) : accountPath;
128 var aciIdentityKey = KeyUtils.generateIdentityKeyPair();
129 var pniIdentityKey = KeyUtils.generateIdentityKeyPair();
130 var registrationId = KeyHelper.generateRegistrationId(false);
131
132 var profileKey = KeyUtils.createProfileKey();
133 var account = SignalAccount.create(pathConfig.dataPath(),
134 newAccountPath,
135 number,
136 aciIdentityKey,
137 pniIdentityKey,
138 registrationId,
139 profileKey,
140 trustNewIdentity);
141
142 return new RegistrationManagerImpl(account,
143 pathConfig,
144 serviceEnvironmentConfig,
145 userAgent,
146 newManagerListener,
147 (newNumber, newAci) -> accountsStore.updateAccount(newAccountPath, newNumber, newAci));
148 }
149
150 var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, trustNewIdentity);
151 if (!number.equals(account.getNumber())) {
152 account.close();
153 throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
154 }
155
156 return new RegistrationManagerImpl(account,
157 pathConfig,
158 serviceEnvironmentConfig,
159 userAgent,
160 newManagerListener,
161 (newNumber, newAci) -> accountsStore.updateAccount(accountPath, newNumber, newAci));
162 }
163 }