diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index b2baf2f4..75a25fcb 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -54,6 +54,7 @@ import org.asamk.signal.manager.api.UserStatus; import org.asamk.signal.manager.api.UsernameLinkUrl; import org.asamk.signal.manager.api.UsernameStatus; import org.asamk.signal.manager.api.VerificationMethodNotAvailableException; +import org.signal.core.util.UuidUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,6 +75,10 @@ public interface Manager extends Closeable { return PhoneNumberUtil.getInstance().isPossibleNumber(e164Number, countryCode); } + static boolean isValidAci(final String aci) { + return UuidUtil.INSTANCE.isUuid(aci); + } + static boolean isSignalClientAvailable() { final Logger logger = LoggerFactory.getLogger(Manager.class); try { diff --git a/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java b/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java index 9ce9e313..d5856d97 100644 --- a/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java +++ b/lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java @@ -5,7 +5,6 @@ import org.asamk.signal.manager.api.NotRegisteredException; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.ServiceEnvironment; import org.asamk.signal.manager.config.ServiceConfig; -import org.signal.core.models.ServiceId.ACI; import org.asamk.signal.manager.config.ServiceEnvironmentConfig; import org.asamk.signal.manager.internal.AccountFileUpdaterImpl; import org.asamk.signal.manager.internal.ManagerImpl; @@ -16,6 +15,7 @@ import org.asamk.signal.manager.internal.RegistrationManagerImpl; import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.accounts.AccountsStore; import org.asamk.signal.manager.util.KeyUtils; +import org.signal.core.models.ServiceId.ACI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; @@ -68,7 +68,7 @@ public class SignalAccountFiles { public MultiAccountManager initMultiAccountManager() throws IOException { final var managerPairs = accountsStore.getAllAccounts().parallelStream().map(a -> { try { - return new Pair(initManager(a.number(), a.path()), null); + return new Pair(initManagerByNumber(a.number(), a.path()), null); } catch (NotRegisteredException e) { logger.warn("Ignoring {}: {} ({})", a.number(), e.getMessage(), e.getClass().getSimpleName()); return null; @@ -91,39 +91,31 @@ public class SignalAccountFiles { return new MultiAccountManagerImpl(managers, this); } - public Manager initManager(String number) throws IOException, NotRegisteredException, AccountCheckException { + public Manager initManagerByNumber(String number) throws IOException, NotRegisteredException, AccountCheckException { final var accountPath = accountsStore.getPathByNumber(number); - return this.initManager(number, accountPath); - } - - public String getAccountNumberByAci(final String aciStr) throws IOException { - final var accounts = accountsStore.getAllAccounts(); - final var account = accounts.stream() - .filter(a -> aciStr.equals(a.uuid())) - .findFirst() - .orElse(null); - if (account == null || account.number() == null) { - return null; - } - return account.number(); + return this.initManagerByNumber(number, accountPath); } public Manager initManagerByAci(String aciStr) throws IOException, NotRegisteredException, AccountCheckException { - final var phoneNumber = getAccountNumberByAci(aciStr); - if (phoneNumber == null) { - throw new NotRegisteredException(); - } - final var accountPath = accountsStore.getPathByNumber(phoneNumber); - if (accountPath == null) { - throw new NotRegisteredException(); - } - return this.initManager(phoneNumber, accountPath); + final var aci = ACI.parseOrThrow(aciStr); + final var accountPath = accountsStore.getPathByAci(aci); + return this.initManagerByAci(aci, accountPath); } - private Manager initManager( + private Manager initManagerByNumber( String number, String accountPath ) throws IOException, NotRegisteredException, AccountCheckException { + final var account = loadAccount(accountPath); + if (!number.equals(account.getNumber())) { + account.close(); + throw new IOException("Number in account file doesn't match expected number: " + account.getNumber()); + } + + return initManagerFromAccount(number, accountPath, account); + } + + private SignalAccount loadAccount(final String accountPath) throws NotRegisteredException, IOException { if (accountPath == null) { throw new NotRegisteredException(); } @@ -131,12 +123,27 @@ public class SignalAccountFiles { throw new NotRegisteredException(); } - var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, settings); - if (!number.equals(account.getNumber())) { + return SignalAccount.load(pathConfig.dataPath(), accountPath, true, settings); + } + + private Manager initManagerByAci( + ACI aci, + String accountPath + ) throws IOException, NotRegisteredException, AccountCheckException { + final var account = loadAccount(accountPath); + if (!aci.equals(account.getAci())) { account.close(); - throw new IOException("Number in account file doesn't match expected number: " + account.getNumber()); + throw new IOException("ACI in account file doesn't match expected ACI: " + account.getAci()); } + return initManagerFromAccount(aci.toString(), accountPath, account); + } + + private ManagerImpl initManagerFromAccount( + final String identifier, + final String accountPath, + final SignalAccount account + ) throws NotRegisteredException, IOException, AccountCheckException { if (!account.isRegistered()) { account.close(); throw new NotRegisteredException(); @@ -161,7 +168,7 @@ public class SignalAccountFiles { throw new IOException("signal-cli version is too old for the Signal-Server, please update."); } catch (IOException e) { manager.close(); - throw new AccountCheckException("Error while checking account " + number + ": " + e.getMessage(), e); + throw new AccountCheckException("Error while checking account " + identifier + ": " + e.getMessage(), e); } if (account.getServiceEnvironment() == null) { diff --git a/lib/src/main/java/org/asamk/signal/manager/internal/MultiAccountManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/internal/MultiAccountManagerImpl.java index 3adefbef..560fe62c 100644 --- a/lib/src/main/java/org/asamk/signal/manager/internal/MultiAccountManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/internal/MultiAccountManagerImpl.java @@ -7,8 +7,8 @@ import org.asamk.signal.manager.RegistrationManager; import org.asamk.signal.manager.SignalAccountFiles; import org.asamk.signal.manager.api.AccountCheckException; import org.asamk.signal.manager.api.NotRegisteredException; -import org.slf4j.Logger; import org.signal.core.util.UuidUtil; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; @@ -100,20 +100,13 @@ public class MultiAccountManagerImpl implements MultiAccountManager { synchronized (managers) { if (UuidUtil.INSTANCE.isUuid(identifier)) { // Check if UUID corresponds to an already-loaded manager - try { - final var phoneNumber = signalAccountFiles.getAccountNumberByAci(identifier); - if (phoneNumber != null) { - final var existing = managers.stream() - .filter(m -> m.getSelfNumber().equals(phoneNumber)) - .findFirst() - .orElse(null); - if (existing != null) { - logger.debug("Found already loaded manager for ACI: {}", identifier); - return existing; - } - } - } catch (IOException e) { - logger.warn("Failed to lookup ACI in accounts: {}", identifier, e); + final var existing = managers.stream() + .filter(m -> m.getSelfACI().equals(identifier)) + .findFirst() + .orElse(null); + if (existing != null) { + logger.debug("Found already loaded manager for ACI: {}", identifier); + return existing; } // Load by ACI try { @@ -136,7 +129,7 @@ public class MultiAccountManagerImpl implements MultiAccountManager { } // Load by phone number try { - final var newManager = signalAccountFiles.initManager(identifier); + final var newManager = signalAccountFiles.initManagerByNumber(identifier); managers.add(newManager); return newManager; } catch (NotRegisteredException | IOException | IllegalArgumentException | AccountCheckException e) { diff --git a/src/main/java/org/asamk/signal/App.java b/src/main/java/org/asamk/signal/App.java index fb940602..fa18e597 100644 --- a/src/main/java/org/asamk/signal/App.java +++ b/src/main/java/org/asamk/signal/App.java @@ -184,16 +184,20 @@ public class App { } account = getAccountIfOnlyOne(signalAccountFiles); - } else if (!Manager.isValidNumber(account, null)) { - throw new UserErrorException("Invalid account (phone number), make sure you include the country code."); } if (command instanceof RegistrationCommand registrationCommand) { + if (!Manager.isValidNumber(account, null)) { + throw new UserErrorException("Invalid account (phone number), make sure you include the country code."); + } handleRegistrationCommand(registrationCommand, account, signalAccountFiles, commandHandler); return; } if (command instanceof LocalCommand localCommand) { + if (!Manager.isValidNumber(account, null) && !Manager.isValidAci(account)) { + throw new UserErrorException("Invalid account (phone number), make sure you include the country code."); + } handleLocalCommand(localCommand, account, signalAccountFiles, commandHandler); return; } @@ -330,7 +334,11 @@ public class App { ) throws CommandException { logger.trace("Loading account file for {}", account); try { - return signalAccountFiles.initManager(account); + if (Manager.isValidAci(account)) { + return signalAccountFiles.initManagerByAci(account); + } else { + return signalAccountFiles.initManagerByNumber(account); + } } catch (NotRegisteredException e) { throw new UserErrorException("User " + account + " is not registered."); } catch (AccountCheckException ace) {