Improve loading accounts by aci

This commit is contained in:
AsamK 2026-07-11 19:03:48 +02:00
parent 4dda7582a3
commit 54d713ea7d
4 changed files with 62 additions and 49 deletions

View File

@ -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 {

View File

@ -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<Manager, Throwable>(initManager(a.number(), a.path()), null);
return new Pair<Manager, Throwable>(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) {

View File

@ -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) {

View File

@ -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) {