mirror of
https://github.com/AsamK/signal-cli.git
synced 2026-08-22 04:56:04 +00:00
Fix HTTP handler to accept ACI/UUID account parameter in SSE endpoint (#2079)
* Fix HTTP handler to accept ACI/UUID account parameter in SSE endpoint MultiAccountManagerImpl.getManager() only looked up accounts by phone number, causing HTTP 400 errors when the SSE events endpoint was called with ?account=<ACI-UUID> (e.g., cc528f93-527e-4566-8c62-d12dc99dbce0). Changes: - SignalAccountFiles: Add initManagerByAci() method for ACI-based lookup - MultiAccountManagerImpl: getManager() now tries ACI lookup when phone number lookup fails - HttpServerHandler: getManagerFromQuery() falls back to returning all managers when the specific account identifier is not found (instead of HTTP 400) * Fix SSE endpoint for UUID account parameter & preserve '+' in phone numbers Three interrelated fixes for the HTTP SSE endpoint: 1. **SignalAccountFiles** — Replace ACI.parseOrThrow() with UUID-string lookup from accountsStore.getAllAccounts(). The old approach failed when a raw UUID string (from URL query param) was passed. Added getAccountNumberByAci() helper to reduce duplication. 2. **MultiAccountManagerImpl** — Catch IllegalArgumentException in getManager() for both phone number and ACI lookup paths. Also check if the UUID corresponds to an already-loaded manager before trying to initByAci(), preventing OverlappingFileLockException when SSE requests arrive with a UUID for an account that was loaded at startup. 3. **Util.getQueryMap()** — Preserve '+' characters in query parameter values by escaping them before URLDecoder.decode(). Without this, URLDecoder converts '+' to space, breaking phone numbers like '+4915422389' which become ' 4915422389'. * fix: address AsamK's review comments - HttpServerHandler.getManagerFromQuery(): return null when account not found instead of falling back to all managers (AsamK: 'should stay return null here') - MultiAccountManagerImpl.getManager(): use UuidUtil.isUuid() to branch early on ACI vs phone number, eliminating the try-number-then-fallback pattern (AsamK: 'check if identifier is a uuid first') --------- Co-authored-by: Till L T <tilllt@users.noreply.github.com>
This commit is contained in:
parent
e70bddd790
commit
248c0c0dab
@ -5,6 +5,7 @@ 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;
|
||||
@ -95,6 +96,30 @@ public class SignalAccountFiles {
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private Manager initManager(
|
||||
String number,
|
||||
String accountPath
|
||||
|
||||
@ -8,6 +8,7 @@ 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.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -95,23 +96,54 @@ public class MultiAccountManagerImpl implements MultiAccountManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manager getManager(final String number) {
|
||||
public Manager getManager(final String identifier) {
|
||||
synchronized (managers) {
|
||||
final var manager = managers.stream()
|
||||
.filter(m -> m.getSelfNumber().equals(number))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (manager != null) {
|
||||
return manager;
|
||||
}
|
||||
try {
|
||||
final var newManager = signalAccountFiles.initManager(number);
|
||||
managers.add(newManager);
|
||||
return newManager;
|
||||
} catch (IOException | NotRegisteredException | AccountCheckException e) {
|
||||
logger.warn("Failed to load new manager", e);
|
||||
return null;
|
||||
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);
|
||||
}
|
||||
// Load by ACI
|
||||
try {
|
||||
final var newManager = signalAccountFiles.initManagerByAci(identifier);
|
||||
managers.add(newManager);
|
||||
return newManager;
|
||||
} catch (NotRegisteredException e) {
|
||||
logger.debug("Manager not found by ACI: {}", identifier);
|
||||
} catch (IOException | IllegalArgumentException | AccountCheckException e) {
|
||||
logger.warn("Failed to load new manager by ACI: {}", identifier, e);
|
||||
}
|
||||
} else {
|
||||
// Phone number — check already loaded managers
|
||||
var existing = managers.stream()
|
||||
.filter(m -> m.getSelfNumber().equals(identifier))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
// Load by phone number
|
||||
try {
|
||||
final var newManager = signalAccountFiles.initManager(identifier);
|
||||
managers.add(newManager);
|
||||
return newManager;
|
||||
} catch (NotRegisteredException | IOException | IllegalArgumentException | AccountCheckException e) {
|
||||
logger.warn("Failed to load manager by number: {}", identifier, e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -262,6 +262,9 @@ public class HttpServerHandler implements AutoCloseable {
|
||||
} else {
|
||||
final var manager = c.getManager(account);
|
||||
if (manager == null) {
|
||||
// Account not found by the given identifier (number or ACI/UUID)
|
||||
// Log the available accounts to help debug
|
||||
logger.warn("Account not found for identifier: {}", account);
|
||||
return null;
|
||||
}
|
||||
return List.of(manager);
|
||||
|
||||
@ -79,7 +79,7 @@ public class Util {
|
||||
for (var param : params) {
|
||||
final var paramParts = param.split("=", 2);
|
||||
var name = URLDecoder.decode(paramParts[0], StandardCharsets.UTF_8);
|
||||
var value = paramParts.length == 1 ? null : URLDecoder.decode(paramParts[1], StandardCharsets.UTF_8);
|
||||
var value = paramParts.length == 1 ? null : URLDecoder.decode(paramParts[1].replace("+", "%2B"), StandardCharsets.UTF_8);
|
||||
map.put(name, value);
|
||||
}
|
||||
return map;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user