mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
Add MultiAccountManager
This commit is contained in:
parent
6261934dda
commit
4a1af0786c
18 changed files with 221 additions and 131 deletions
|
@ -403,6 +403,8 @@ public class ManagerImpl implements Manager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void submitRateLimitRecaptchaChallenge(String challenge, String captcha) throws IOException {
|
public void submitRateLimitRecaptchaChallenge(String challenge, String captcha) throws IOException {
|
||||||
|
captcha = captcha == null ? null : captcha.replace("signalcaptcha://", "");
|
||||||
|
|
||||||
dependencies.getAccountManager().submitRateLimitRecaptchaChallenge(challenge, captcha);
|
dependencies.getAccountManager().submitRateLimitRecaptchaChallenge(challenge, captcha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
package org.asamk.signal.commands;
|
package org.asamk.signal.manager;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
|
||||||
import org.asamk.signal.manager.ProvisioningManager;
|
|
||||||
import org.asamk.signal.manager.RegistrationManager;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public interface SignalCreator {
|
public interface MultiAccountManager extends AutoCloseable {
|
||||||
|
|
||||||
List<String> getAccountNumbers();
|
List<String> getAccountNumbers();
|
||||||
|
|
||||||
void addManager(Manager m);
|
|
||||||
|
|
||||||
void addOnManagerAddedHandler(Consumer<Manager> handler);
|
void addOnManagerAddedHandler(Consumer<Manager> handler);
|
||||||
|
|
||||||
|
void addOnManagerRemovedHandler(Consumer<Manager> handler);
|
||||||
|
|
||||||
Manager getManager(String phoneNumber);
|
Manager getManager(String phoneNumber);
|
||||||
|
|
||||||
ProvisioningManager getNewProvisioningManager();
|
ProvisioningManager getNewProvisioningManager();
|
||||||
|
|
||||||
RegistrationManager getNewRegistrationManager(String username) throws IOException;
|
RegistrationManager getNewRegistrationManager(String username) throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void close();
|
||||||
}
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package org.asamk.signal.manager;
|
||||||
|
|
||||||
|
import org.asamk.signal.manager.config.ServiceEnvironment;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class MultiAccountManagerImpl implements MultiAccountManager {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(MultiAccountManagerImpl.class);
|
||||||
|
|
||||||
|
private final Set<Consumer<Manager>> onManagerAddedHandlers = new HashSet<>();
|
||||||
|
private final Set<Consumer<Manager>> onManagerRemovedHandlers = new HashSet<>();
|
||||||
|
private final Set<Manager> managers = new HashSet<>();
|
||||||
|
private final File dataPath;
|
||||||
|
private final ServiceEnvironment serviceEnvironment;
|
||||||
|
private final String userAgent;
|
||||||
|
|
||||||
|
public MultiAccountManagerImpl(
|
||||||
|
final Collection<Manager> managers,
|
||||||
|
final File dataPath,
|
||||||
|
final ServiceEnvironment serviceEnvironment,
|
||||||
|
final String userAgent
|
||||||
|
) {
|
||||||
|
this.managers.addAll(managers);
|
||||||
|
this.dataPath = dataPath;
|
||||||
|
this.serviceEnvironment = serviceEnvironment;
|
||||||
|
this.userAgent = userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAccountNumbers() {
|
||||||
|
synchronized (managers) {
|
||||||
|
return managers.stream().map(Manager::getSelfNumber).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addManager(final Manager m) {
|
||||||
|
synchronized (managers) {
|
||||||
|
if (managers.contains(m)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
managers.add(m);
|
||||||
|
}
|
||||||
|
synchronized (onManagerAddedHandlers) {
|
||||||
|
for (final var handler : onManagerAddedHandlers) {
|
||||||
|
handler.accept(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addOnManagerAddedHandler(final Consumer<Manager> handler) {
|
||||||
|
synchronized (onManagerAddedHandlers) {
|
||||||
|
onManagerAddedHandlers.add(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addOnManagerRemovedHandler(final Consumer<Manager> handler) {
|
||||||
|
synchronized (onManagerRemovedHandlers) {
|
||||||
|
onManagerRemovedHandlers.add(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Manager getManager(final String account) {
|
||||||
|
synchronized (managers) {
|
||||||
|
return managers.stream().filter(m -> m.getSelfNumber().equals(account)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProvisioningManager getNewProvisioningManager() {
|
||||||
|
return ProvisioningManager.init(dataPath, serviceEnvironment, userAgent, this::addManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RegistrationManager getNewRegistrationManager(String account) throws IOException {
|
||||||
|
return RegistrationManager.init(account, dataPath, serviceEnvironment, userAgent, this::addManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
synchronized (managers) {
|
||||||
|
for (var m : managers) {
|
||||||
|
try {
|
||||||
|
m.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Cleanup failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
managers.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class ProvisioningManager {
|
public class ProvisioningManager {
|
||||||
|
|
||||||
|
@ -46,16 +47,23 @@ public class ProvisioningManager {
|
||||||
private final PathConfig pathConfig;
|
private final PathConfig pathConfig;
|
||||||
private final ServiceEnvironmentConfig serviceEnvironmentConfig;
|
private final ServiceEnvironmentConfig serviceEnvironmentConfig;
|
||||||
private final String userAgent;
|
private final String userAgent;
|
||||||
|
private final Consumer<Manager> newManagerListener;
|
||||||
|
|
||||||
private final SignalServiceAccountManager accountManager;
|
private final SignalServiceAccountManager accountManager;
|
||||||
private final IdentityKeyPair tempIdentityKey;
|
private final IdentityKeyPair tempIdentityKey;
|
||||||
private final int registrationId;
|
private final int registrationId;
|
||||||
private final String password;
|
private final String password;
|
||||||
|
|
||||||
ProvisioningManager(PathConfig pathConfig, ServiceEnvironmentConfig serviceEnvironmentConfig, String userAgent) {
|
ProvisioningManager(
|
||||||
|
PathConfig pathConfig,
|
||||||
|
ServiceEnvironmentConfig serviceEnvironmentConfig,
|
||||||
|
String userAgent,
|
||||||
|
final Consumer<Manager> newManagerListener
|
||||||
|
) {
|
||||||
this.pathConfig = pathConfig;
|
this.pathConfig = pathConfig;
|
||||||
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
|
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
|
this.newManagerListener = newManagerListener;
|
||||||
|
|
||||||
tempIdentityKey = KeyUtils.generateIdentityKeyPair();
|
tempIdentityKey = KeyUtils.generateIdentityKeyPair();
|
||||||
registrationId = KeyHelper.generateRegistrationId(false);
|
registrationId = KeyHelper.generateRegistrationId(false);
|
||||||
|
@ -75,12 +83,21 @@ public class ProvisioningManager {
|
||||||
|
|
||||||
public static ProvisioningManager init(
|
public static ProvisioningManager init(
|
||||||
File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
|
File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
|
||||||
|
) {
|
||||||
|
return init(settingsPath, serviceEnvironment, userAgent, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProvisioningManager init(
|
||||||
|
File settingsPath,
|
||||||
|
ServiceEnvironment serviceEnvironment,
|
||||||
|
String userAgent,
|
||||||
|
Consumer<Manager> newManagerListener
|
||||||
) {
|
) {
|
||||||
var pathConfig = PathConfig.createDefault(settingsPath);
|
var pathConfig = PathConfig.createDefault(settingsPath);
|
||||||
|
|
||||||
final var serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(serviceEnvironment, userAgent);
|
final var serviceConfiguration = ServiceConfig.getServiceEnvironmentConfig(serviceEnvironment, userAgent);
|
||||||
|
|
||||||
return new ProvisioningManager(pathConfig, serviceConfiguration, userAgent);
|
return new ProvisioningManager(pathConfig, serviceConfiguration, userAgent, newManagerListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public URI getDeviceLinkUri() throws TimeoutException, IOException {
|
public URI getDeviceLinkUri() throws TimeoutException, IOException {
|
||||||
|
@ -89,7 +106,7 @@ public class ProvisioningManager {
|
||||||
return new DeviceLinkInfo(deviceUuid, tempIdentityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
|
return new DeviceLinkInfo(deviceUuid, tempIdentityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Manager finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists {
|
public String finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists {
|
||||||
var ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
|
var ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
|
||||||
var number = ret.getNumber();
|
var number = ret.getNumber();
|
||||||
|
|
||||||
|
@ -145,11 +162,11 @@ public class ProvisioningManager {
|
||||||
"Failed to request sync messages from linked device, data can be requested again with `sendSyncRequest`.");
|
"Failed to request sync messages from linked device, data can be requested again with `sendSyncRequest`.");
|
||||||
}
|
}
|
||||||
|
|
||||||
final var result = m;
|
if (newManagerListener != null) {
|
||||||
account = null;
|
newManagerListener.accept(m);
|
||||||
m = null;
|
m = null;
|
||||||
|
}
|
||||||
return result;
|
return number;
|
||||||
} finally {
|
} finally {
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
m.close();
|
m.close();
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class RegistrationManager implements Closeable {
|
public class RegistrationManager implements Closeable {
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ public class RegistrationManager implements Closeable {
|
||||||
private final PathConfig pathConfig;
|
private final PathConfig pathConfig;
|
||||||
private final ServiceEnvironmentConfig serviceEnvironmentConfig;
|
private final ServiceEnvironmentConfig serviceEnvironmentConfig;
|
||||||
private final String userAgent;
|
private final String userAgent;
|
||||||
|
private final Consumer<Manager> newManagerListener;
|
||||||
|
|
||||||
private final SignalServiceAccountManager accountManager;
|
private final SignalServiceAccountManager accountManager;
|
||||||
private final PinHelper pinHelper;
|
private final PinHelper pinHelper;
|
||||||
|
@ -66,12 +68,14 @@ public class RegistrationManager implements Closeable {
|
||||||
SignalAccount account,
|
SignalAccount account,
|
||||||
PathConfig pathConfig,
|
PathConfig pathConfig,
|
||||||
ServiceEnvironmentConfig serviceEnvironmentConfig,
|
ServiceEnvironmentConfig serviceEnvironmentConfig,
|
||||||
String userAgent
|
String userAgent,
|
||||||
|
Consumer<Manager> newManagerListener
|
||||||
) {
|
) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.pathConfig = pathConfig;
|
this.pathConfig = pathConfig;
|
||||||
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
|
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
|
this.newManagerListener = newManagerListener;
|
||||||
|
|
||||||
GroupsV2Operations groupsV2Operations;
|
GroupsV2Operations groupsV2Operations;
|
||||||
try {
|
try {
|
||||||
|
@ -96,6 +100,16 @@ public class RegistrationManager implements Closeable {
|
||||||
|
|
||||||
public static RegistrationManager init(
|
public static RegistrationManager init(
|
||||||
String number, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
|
String number, File settingsPath, ServiceEnvironment serviceEnvironment, String userAgent
|
||||||
|
) throws IOException {
|
||||||
|
return init(number, settingsPath, serviceEnvironment, userAgent, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegistrationManager init(
|
||||||
|
String number,
|
||||||
|
File settingsPath,
|
||||||
|
ServiceEnvironment serviceEnvironment,
|
||||||
|
String userAgent,
|
||||||
|
Consumer<Manager> newManagerListener
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
var pathConfig = PathConfig.createDefault(settingsPath);
|
var pathConfig = PathConfig.createDefault(settingsPath);
|
||||||
|
|
||||||
|
@ -112,15 +126,16 @@ public class RegistrationManager implements Closeable {
|
||||||
profileKey,
|
profileKey,
|
||||||
TrustNewIdentity.ON_FIRST_USE);
|
TrustNewIdentity.ON_FIRST_USE);
|
||||||
|
|
||||||
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent);
|
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent, newManagerListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
var account = SignalAccount.load(pathConfig.dataPath(), number, true, TrustNewIdentity.ON_FIRST_USE);
|
var account = SignalAccount.load(pathConfig.dataPath(), number, true, TrustNewIdentity.ON_FIRST_USE);
|
||||||
|
|
||||||
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent);
|
return new RegistrationManager(account, pathConfig, serviceConfiguration, userAgent, newManagerListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(boolean voiceVerification, String captcha) throws IOException, CaptchaRequiredException {
|
public void register(boolean voiceVerification, String captcha) throws IOException, CaptchaRequiredException {
|
||||||
|
captcha = captcha == null ? null : captcha.replace("signalcaptcha://", "");
|
||||||
final ServiceResponse<RequestVerificationCodeResponse> response;
|
final ServiceResponse<RequestVerificationCodeResponse> response;
|
||||||
if (voiceVerification) {
|
if (voiceVerification) {
|
||||||
response = accountManager.requestVoiceVerificationCode(Utils.getDefaultLocale(),
|
response = accountManager.requestVoiceVerificationCode(Utils.getDefaultLocale(),
|
||||||
|
@ -140,7 +155,7 @@ public class RegistrationManager implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Manager verifyAccount(
|
public void verifyAccount(
|
||||||
String verificationCode, String pin
|
String verificationCode, String pin
|
||||||
) throws IOException, PinLockedException, IncorrectPinException {
|
) throws IOException, PinLockedException, IncorrectPinException {
|
||||||
verificationCode = verificationCode.replace("-", "");
|
verificationCode = verificationCode.replace("-", "");
|
||||||
|
@ -196,10 +211,10 @@ public class RegistrationManager implements Closeable {
|
||||||
logger.warn("Failed to set default profile: {}", e.getMessage());
|
logger.warn("Failed to set default profile: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
final var result = m;
|
if (newManagerListener != null) {
|
||||||
|
newManagerListener.accept(m);
|
||||||
m = null;
|
m = null;
|
||||||
|
}
|
||||||
return result;
|
|
||||||
} finally {
|
} finally {
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
m.close();
|
m.close();
|
||||||
|
|
|
@ -12,13 +12,13 @@ import org.asamk.signal.commands.LocalCommand;
|
||||||
import org.asamk.signal.commands.MultiLocalCommand;
|
import org.asamk.signal.commands.MultiLocalCommand;
|
||||||
import org.asamk.signal.commands.ProvisioningCommand;
|
import org.asamk.signal.commands.ProvisioningCommand;
|
||||||
import org.asamk.signal.commands.RegistrationCommand;
|
import org.asamk.signal.commands.RegistrationCommand;
|
||||||
import org.asamk.signal.commands.SignalCreator;
|
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
|
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||||
import org.asamk.signal.dbus.DbusManagerImpl;
|
import org.asamk.signal.dbus.DbusManagerImpl;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManagerImpl;
|
||||||
import org.asamk.signal.manager.NotRegisteredException;
|
import org.asamk.signal.manager.NotRegisteredException;
|
||||||
import org.asamk.signal.manager.ProvisioningManager;
|
import org.asamk.signal.manager.ProvisioningManager;
|
||||||
import org.asamk.signal.manager.RegistrationManager;
|
import org.asamk.signal.manager.RegistrationManager;
|
||||||
|
@ -39,8 +39,6 @@ import java.io.OutputStreamWriter;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static net.sourceforge.argparse4j.DefaultSettings.VERSION_0_9_0_DEFAULT_SETTINGS;
|
import static net.sourceforge.argparse4j.DefaultSettings.VERSION_0_9_0_DEFAULT_SETTINGS;
|
||||||
|
|
||||||
|
@ -186,7 +184,7 @@ public class App {
|
||||||
throw new UserErrorException("No local users found, you first need to register or link an account");
|
throw new UserErrorException("No local users found, you first need to register or link an account");
|
||||||
} else if (accounts.size() > 1) {
|
} else if (accounts.size() > 1) {
|
||||||
throw new UserErrorException(
|
throw new UserErrorException(
|
||||||
"Multiple users found, you need to specify a account (phone number) with -u");
|
"Multiple users found, you need to specify an account (phone number) with -a");
|
||||||
}
|
}
|
||||||
|
|
||||||
account = accounts.get(0);
|
account = accounts.get(0);
|
||||||
|
@ -237,8 +235,8 @@ public class App {
|
||||||
+ e.getClass().getSimpleName()
|
+ e.getClass().getSimpleName()
|
||||||
+ ")", e);
|
+ ")", e);
|
||||||
}
|
}
|
||||||
try (var m = manager) {
|
try (manager) {
|
||||||
command.handleCommand(ns, m);
|
command.handleCommand(ns, manager);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Cleanup failed", e);
|
logger.warn("Cleanup failed", e);
|
||||||
}
|
}
|
||||||
|
@ -268,73 +266,19 @@ public class App {
|
||||||
final TrustNewIdentity trustNewIdentity
|
final TrustNewIdentity trustNewIdentity
|
||||||
) throws CommandException {
|
) throws CommandException {
|
||||||
final var managers = new ArrayList<Manager>();
|
final var managers = new ArrayList<Manager>();
|
||||||
|
for (String a : accounts) {
|
||||||
try {
|
try {
|
||||||
for (String u : accounts) {
|
managers.add(loadManager(a, dataPath, serviceEnvironment, trustNewIdentity));
|
||||||
try {
|
|
||||||
managers.add(loadManager(u, dataPath, serviceEnvironment, trustNewIdentity));
|
|
||||||
} catch (CommandException e) {
|
} catch (CommandException e) {
|
||||||
logger.warn("Ignoring {}: {}", u, e.getMessage());
|
logger.warn("Ignoring {}: {}", a, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
command.handleCommand(ns, new SignalCreator() {
|
try (var multiAccountManager = new MultiAccountManagerImpl(managers,
|
||||||
private final List<Consumer<Manager>> onManagerAddedHandlers = new ArrayList<>();
|
dataPath,
|
||||||
|
serviceEnvironment,
|
||||||
@Override
|
BaseConfig.USER_AGENT)) {
|
||||||
public List<String> getAccountNumbers() {
|
command.handleCommand(ns, multiAccountManager, outputWriter);
|
||||||
synchronized (managers) {
|
|
||||||
return managers.stream().map(Manager::getSelfNumber).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addManager(final Manager m) {
|
|
||||||
synchronized (managers) {
|
|
||||||
if (!managers.contains(m)) {
|
|
||||||
managers.add(m);
|
|
||||||
for (final var handler : onManagerAddedHandlers) {
|
|
||||||
handler.accept(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addOnManagerAddedHandler(final Consumer<Manager> handler) {
|
|
||||||
onManagerAddedHandlers.add(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Manager getManager(final String phoneNumber) {
|
|
||||||
synchronized (managers) {
|
|
||||||
return managers.stream()
|
|
||||||
.filter(m -> m.getSelfNumber().equals(phoneNumber))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProvisioningManager getNewProvisioningManager() {
|
|
||||||
return ProvisioningManager.init(dataPath, serviceEnvironment, BaseConfig.USER_AGENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RegistrationManager getNewRegistrationManager(String account) throws IOException {
|
|
||||||
return RegistrationManager.init(account, dataPath, serviceEnvironment, BaseConfig.USER_AGENT);
|
|
||||||
}
|
|
||||||
}, outputWriter);
|
|
||||||
} finally {
|
|
||||||
synchronized (managers) {
|
|
||||||
for (var m : managers) {
|
|
||||||
try {
|
|
||||||
m.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warn("Cleanup failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
managers.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.asamk.signal.dbus.DbusSignalControlImpl;
|
||||||
import org.asamk.signal.dbus.DbusSignalImpl;
|
import org.asamk.signal.dbus.DbusSignalImpl;
|
||||||
import org.asamk.signal.jsonrpc.SignalJsonRpcDispatcherHandler;
|
import org.asamk.signal.jsonrpc.SignalJsonRpcDispatcherHandler;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
import org.asamk.signal.util.IOUtils;
|
import org.asamk.signal.util.IOUtils;
|
||||||
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
||||||
import org.freedesktop.dbus.exceptions.DBusException;
|
import org.freedesktop.dbus.exceptions.DBusException;
|
||||||
|
@ -141,7 +142,7 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleCommand(
|
public void handleCommand(
|
||||||
final Namespace ns, final SignalCreator c, final OutputWriter outputWriter
|
final Namespace ns, final MultiAccountManager c, final OutputWriter outputWriter
|
||||||
) throws CommandException {
|
) throws CommandException {
|
||||||
logger.info("Starting daemon in multi-account mode");
|
logger.info("Starting daemon in multi-account mode");
|
||||||
final var noReceiveStdOut = Boolean.TRUE.equals(ns.getBoolean("no-receive-stdout"));
|
final var noReceiveStdOut = Boolean.TRUE.equals(ns.getBoolean("no-receive-stdout"));
|
||||||
|
@ -220,7 +221,7 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runSocketMultiAccount(
|
private void runSocketMultiAccount(
|
||||||
final SignalCreator c, final ServerSocketChannel serverChannel, final boolean noReceiveOnStart
|
final MultiAccountManager c, final ServerSocketChannel serverChannel, final boolean noReceiveOnStart
|
||||||
) {
|
) {
|
||||||
runSocket(serverChannel, channel -> {
|
runSocket(serverChannel, channel -> {
|
||||||
final var handler = getSignalJsonRpcDispatcherHandler(channel, noReceiveOnStart);
|
final var handler = getSignalJsonRpcDispatcherHandler(channel, noReceiveOnStart);
|
||||||
|
@ -276,7 +277,7 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runDbusMultiAccount(
|
private void runDbusMultiAccount(
|
||||||
final SignalCreator c, final boolean noReceiveOnStart, final boolean isDbusSystem
|
final MultiAccountManager c, final boolean noReceiveOnStart, final boolean isDbusSystem
|
||||||
) throws UnexpectedErrorException {
|
) throws UnexpectedErrorException {
|
||||||
runDbus(isDbusSystem, (connection, objectPath) -> {
|
runDbus(isDbusSystem, (connection, objectPath) -> {
|
||||||
final var signalControl = new DbusSignalControlImpl(c, objectPath);
|
final var signalControl = new DbusSignalControlImpl(c, objectPath);
|
||||||
|
|
|
@ -2,8 +2,9 @@ package org.asamk.signal.commands;
|
||||||
|
|
||||||
import org.asamk.signal.JsonWriter;
|
import org.asamk.signal.JsonWriter;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
|
|
||||||
public interface JsonRpcMultiCommand<T> extends JsonRpcCommand<T> {
|
public interface JsonRpcMultiCommand<T> extends JsonRpcCommand<T> {
|
||||||
|
|
||||||
void handleCommand(T request, SignalCreator c, JsonWriter jsonWriter) throws CommandException;
|
void handleCommand(T request, MultiAccountManager c, JsonWriter jsonWriter) throws CommandException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
import org.asamk.signal.JsonWriter;
|
import org.asamk.signal.JsonWriter;
|
||||||
import org.asamk.signal.OutputType;
|
import org.asamk.signal.OutputType;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -18,7 +19,7 @@ public interface JsonRpcMultiLocalCommand extends JsonRpcMultiCommand<Map<String
|
||||||
}
|
}
|
||||||
|
|
||||||
default void handleCommand(
|
default void handleCommand(
|
||||||
Map<String, Object> request, SignalCreator c, JsonWriter jsonWriter
|
Map<String, Object> request, MultiAccountManager c, JsonWriter jsonWriter
|
||||||
) throws CommandException {
|
) throws CommandException {
|
||||||
Namespace commandNamespace = new JsonRpcNamespace(request == null ? Map.of() : request);
|
Namespace commandNamespace = new JsonRpcNamespace(request == null ? Map.of() : request);
|
||||||
handleCommand(commandNamespace, c, jsonWriter);
|
handleCommand(commandNamespace, c, jsonWriter);
|
||||||
|
|
|
@ -43,9 +43,8 @@ public class LinkCommand implements ProvisioningCommand {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
writer.println("{}", m.getDeviceLinkUri());
|
writer.println("{}", m.getDeviceLinkUri());
|
||||||
try (var manager = m.finishDeviceLink(deviceName)) {
|
var number = m.finishDeviceLink(deviceName);
|
||||||
writer.println("Associated with: {}", manager.getSelfNumber());
|
writer.println("Associated with: {}", number);
|
||||||
}
|
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
throw new UserErrorException("Link request timed out, please try again.");
|
throw new UserErrorException("Link request timed out, please try again.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.asamk.signal.JsonWriter;
|
||||||
import org.asamk.signal.OutputWriter;
|
import org.asamk.signal.OutputWriter;
|
||||||
import org.asamk.signal.PlainTextWriter;
|
import org.asamk.signal.PlainTextWriter;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ public class ListAccountsCommand implements JsonRpcMultiLocalCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleCommand(
|
public void handleCommand(
|
||||||
final Namespace ns, final SignalCreator c, final OutputWriter outputWriter
|
final Namespace ns, final MultiAccountManager c, final OutputWriter outputWriter
|
||||||
) throws CommandException {
|
) throws CommandException {
|
||||||
final var accountNumbers = c.getAccountNumbers();
|
final var accountNumbers = c.getAccountNumbers();
|
||||||
if (outputWriter instanceof JsonWriter jsonWriter) {
|
if (outputWriter instanceof JsonWriter jsonWriter) {
|
||||||
|
|
|
@ -4,8 +4,9 @@ import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
|
|
||||||
import org.asamk.signal.OutputWriter;
|
import org.asamk.signal.OutputWriter;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
|
|
||||||
public interface MultiLocalCommand extends CliCommand {
|
public interface MultiLocalCommand extends CliCommand {
|
||||||
|
|
||||||
void handleCommand(Namespace ns, SignalCreator c, OutputWriter outputWriter) throws CommandException;
|
void handleCommand(Namespace ns, MultiAccountManager c, OutputWriter outputWriter) throws CommandException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,7 @@ public class SubmitRateLimitChallengeCommand implements JsonRpcLocalCommand {
|
||||||
@Override
|
@Override
|
||||||
public void handleCommand(final Namespace ns, final Manager m, OutputWriter outputWriter) throws CommandException {
|
public void handleCommand(final Namespace ns, final Manager m, OutputWriter outputWriter) throws CommandException {
|
||||||
final var challenge = ns.getString("challenge");
|
final var challenge = ns.getString("challenge");
|
||||||
final var captchaString = ns.getString("captcha");
|
final var captcha = ns.getString("captcha");
|
||||||
final var captcha = captchaString == null ? null : captchaString.replace("signalcaptcha://", "");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m.submitRateLimitRecaptchaChallenge(challenge, captcha);
|
m.submitRateLimitRecaptchaChallenge(challenge, captcha);
|
||||||
|
|
|
@ -32,8 +32,7 @@ public class VerifyCommand implements RegistrationCommand {
|
||||||
var pin = ns.getString("pin");
|
var pin = ns.getString("pin");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final var manager = m.verifyAccount(verificationCode, pin);
|
m.verifyAccount(verificationCode, pin);
|
||||||
manager.close();
|
|
||||||
} catch (PinLockedException e) {
|
} catch (PinLockedException e) {
|
||||||
throw new UserErrorException(
|
throw new UserErrorException(
|
||||||
"Verification failed! This number is locked with a pin. Hours remaining until reset: "
|
"Verification failed! This number is locked with a pin. Hours remaining until reset: "
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.asamk.signal.BaseConfig;
|
||||||
import org.asamk.signal.JsonWriter;
|
import org.asamk.signal.JsonWriter;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ public class VersionCommand implements JsonRpcSingleCommand<Void>, JsonRpcMultiC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleCommand(
|
public void handleCommand(
|
||||||
final Void request, final SignalCreator c, final JsonWriter jsonWriter
|
final Void request, final MultiAccountManager c, final JsonWriter jsonWriter
|
||||||
) throws CommandException {
|
) throws CommandException {
|
||||||
outputVersion(jsonWriter);
|
outputVersion(jsonWriter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ package org.asamk.signal.dbus;
|
||||||
import org.asamk.SignalControl;
|
import org.asamk.SignalControl;
|
||||||
import org.asamk.signal.BaseConfig;
|
import org.asamk.signal.BaseConfig;
|
||||||
import org.asamk.signal.DbusConfig;
|
import org.asamk.signal.DbusConfig;
|
||||||
import org.asamk.signal.commands.SignalCreator;
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
import org.asamk.signal.manager.ProvisioningManager;
|
import org.asamk.signal.manager.ProvisioningManager;
|
||||||
import org.asamk.signal.manager.RegistrationManager;
|
import org.asamk.signal.manager.RegistrationManager;
|
||||||
import org.asamk.signal.manager.UserAlreadyExists;
|
import org.asamk.signal.manager.UserAlreadyExists;
|
||||||
|
@ -21,11 +21,11 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
||||||
|
|
||||||
private final SignalCreator c;
|
private final MultiAccountManager c;
|
||||||
|
|
||||||
private final String objectPath;
|
private final String objectPath;
|
||||||
|
|
||||||
public DbusSignalControlImpl(final SignalCreator c, final String objectPath) {
|
public DbusSignalControlImpl(final MultiAccountManager c, final String objectPath) {
|
||||||
this.c = c;
|
this.c = c;
|
||||||
this.objectPath = objectPath;
|
this.objectPath = objectPath;
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,7 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
||||||
final String number, final String verificationCode, final String pin
|
final String number, final String verificationCode, final String pin
|
||||||
) throws Error.Failure, Error.InvalidNumber {
|
) throws Error.Failure, Error.InvalidNumber {
|
||||||
try (final RegistrationManager registrationManager = c.getNewRegistrationManager(number)) {
|
try (final RegistrationManager registrationManager = c.getNewRegistrationManager(number)) {
|
||||||
final Manager manager = registrationManager.verifyAccount(verificationCode, pin);
|
registrationManager.verifyAccount(verificationCode, pin);
|
||||||
c.addManager(manager);
|
|
||||||
} catch (IOException | PinLockedException | IncorrectPinException e) {
|
} catch (IOException | PinLockedException | IncorrectPinException e) {
|
||||||
throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
|
throw new SignalControl.Error.Failure(e.getClass().getSimpleName() + " " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -89,8 +88,7 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
||||||
final URI deviceLinkUri = provisioningManager.getDeviceLinkUri();
|
final URI deviceLinkUri = provisioningManager.getDeviceLinkUri();
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
final Manager manager = provisioningManager.finishDeviceLink(newDeviceName);
|
provisioningManager.finishDeviceLink(newDeviceName);
|
||||||
c.addManager(manager);
|
|
||||||
} catch (IOException | TimeoutException | UserAlreadyExists e) {
|
} catch (IOException | TimeoutException | UserAlreadyExists e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,9 +129,7 @@ public class DbusSignalImpl implements Signal {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void submitRateLimitChallenge(String challenge, String captchaString) {
|
public void submitRateLimitChallenge(String challenge, String captcha) {
|
||||||
final var captcha = captchaString == null ? null : captchaString.replace("signalcaptcha://", "");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m.submitRateLimitRecaptchaChallenge(challenge, captcha);
|
m.submitRateLimitRecaptchaChallenge(challenge, captcha);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.JsonMappingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ContainerNode;
|
import com.fasterxml.jackson.databind.node.ContainerNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import org.asamk.signal.JsonReceiveMessageHandler;
|
import org.asamk.signal.JsonReceiveMessageHandler;
|
||||||
import org.asamk.signal.JsonWriter;
|
import org.asamk.signal.JsonWriter;
|
||||||
|
@ -13,12 +14,12 @@ import org.asamk.signal.commands.Command;
|
||||||
import org.asamk.signal.commands.Commands;
|
import org.asamk.signal.commands.Commands;
|
||||||
import org.asamk.signal.commands.JsonRpcMultiCommand;
|
import org.asamk.signal.commands.JsonRpcMultiCommand;
|
||||||
import org.asamk.signal.commands.JsonRpcSingleCommand;
|
import org.asamk.signal.commands.JsonRpcSingleCommand;
|
||||||
import org.asamk.signal.commands.SignalCreator;
|
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.UntrustedKeyErrorException;
|
import org.asamk.signal.commands.exceptions.UntrustedKeyErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
|
import org.asamk.signal.manager.MultiAccountManager;
|
||||||
import org.asamk.signal.util.Util;
|
import org.asamk.signal.util.Util;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -42,7 +43,7 @@ public class SignalJsonRpcDispatcherHandler {
|
||||||
private final JsonRpcReader jsonRpcReader;
|
private final JsonRpcReader jsonRpcReader;
|
||||||
private final boolean noReceiveOnStart;
|
private final boolean noReceiveOnStart;
|
||||||
|
|
||||||
private SignalCreator c;
|
private MultiAccountManager c;
|
||||||
private final Map<Manager, Manager.ReceiveMessageHandler> receiveHandlers = new HashMap<>();
|
private final Map<Manager, Manager.ReceiveMessageHandler> receiveHandlers = new HashMap<>();
|
||||||
|
|
||||||
private Manager m;
|
private Manager m;
|
||||||
|
@ -56,7 +57,7 @@ public class SignalJsonRpcDispatcherHandler {
|
||||||
this.jsonRpcReader = new JsonRpcReader(jsonRpcSender, lineSupplier);
|
this.jsonRpcReader = new JsonRpcReader(jsonRpcSender, lineSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleConnection(final SignalCreator c) {
|
public void handleConnection(final MultiAccountManager c) {
|
||||||
this.c = c;
|
this.c = c;
|
||||||
|
|
||||||
if (!noReceiveOnStart) {
|
if (!noReceiveOnStart) {
|
||||||
|
@ -120,19 +121,19 @@ public class SignalJsonRpcDispatcherHandler {
|
||||||
) throws JsonRpcException {
|
) throws JsonRpcException {
|
||||||
var command = getCommand(method);
|
var command = getCommand(method);
|
||||||
// TODO implement register, verify, link
|
// TODO implement register, verify, link
|
||||||
if (c != null && command instanceof JsonRpcMultiCommand<?> jsonRpcCommand) {
|
if (c != null) {
|
||||||
|
if (command instanceof JsonRpcMultiCommand<?> jsonRpcCommand) {
|
||||||
return runCommand(objectMapper, params, new MultiCommandRunnerImpl<>(c, jsonRpcCommand));
|
return runCommand(objectMapper, params, new MultiCommandRunnerImpl<>(c, jsonRpcCommand));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (command instanceof JsonRpcSingleCommand<?> jsonRpcCommand) {
|
if (command instanceof JsonRpcSingleCommand<?> jsonRpcCommand) {
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
return runCommand(objectMapper, params, new CommandRunnerImpl<>(m, jsonRpcCommand));
|
return runCommand(objectMapper, params, new CommandRunnerImpl<>(m, jsonRpcCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.has("account")) {
|
final var manager = getManagerFromParams(params);
|
||||||
Manager manager = c.getManager(params.get("account").asText());
|
|
||||||
if (manager != null) {
|
if (manager != null) {
|
||||||
return runCommand(objectMapper, params, new CommandRunnerImpl<>(manager, jsonRpcCommand));
|
return runCommand(objectMapper, params, new CommandRunnerImpl<>(manager, jsonRpcCommand));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new JsonRpcException(new JsonRpcResponse.Error(JsonRpcResponse.Error.INVALID_PARAMS,
|
throw new JsonRpcException(new JsonRpcResponse.Error(JsonRpcResponse.Error.INVALID_PARAMS,
|
||||||
"Method requires valid account parameter",
|
"Method requires valid account parameter",
|
||||||
|
@ -145,6 +146,15 @@ public class SignalJsonRpcDispatcherHandler {
|
||||||
null));
|
null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Manager getManagerFromParams(final ContainerNode<?> params) {
|
||||||
|
if (params.has("account")) {
|
||||||
|
final var manager = c.getManager(params.get("account").asText());
|
||||||
|
((ObjectNode) params).remove("account");
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private Command getCommand(final String method) {
|
private Command getCommand(final String method) {
|
||||||
if ("subscribeReceive".equals(method)) {
|
if ("subscribeReceive".equals(method)) {
|
||||||
return new SubscribeReceiveCommand();
|
return new SubscribeReceiveCommand();
|
||||||
|
@ -169,7 +179,7 @@ public class SignalJsonRpcDispatcherHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record MultiCommandRunnerImpl<T>(
|
private record MultiCommandRunnerImpl<T>(
|
||||||
SignalCreator c, JsonRpcMultiCommand<T> command
|
MultiAccountManager c, JsonRpcMultiCommand<T> command
|
||||||
) implements CommandRunner<T> {
|
) implements CommandRunner<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue