From: AsamK Date: Thu, 11 Nov 2021 17:27:16 +0000 (+0100) Subject: Implement startLink and finishLink for jsonrpc daemon X-Git-Tag: v0.10.0~52 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/b7005884fdcfa8d95f54e557ddbf2fe4201962f8 Implement startLink and finishLink for jsonrpc daemon --- diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index ebca03a5..d254d85f 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -443,6 +443,20 @@ "allDeclaredMethods":true, "allDeclaredClasses":true} , +{ + "name":"org.asamk.signal.commands.FinishLinkCommand$FinishLinkParams", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String"] }]} +, +{ + "name":"org.asamk.signal.commands.FinishLinkCommand$JsonFinishLink", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"number","parameterTypes":[] }]} +, { "name":"org.asamk.signal.commands.GetUserStatusCommand$JsonUserStatus", "allDeclaredFields":true, @@ -493,6 +507,13 @@ "queryAllDeclaredConstructors":true, "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.String"] }]} , +{ + "name":"org.asamk.signal.commands.StartLinkCommand$JsonLink", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"deviceLinkUri","parameterTypes":[] }]} +, { "name":"org.asamk.signal.commands.VerifyCommand$VerifyParams", "allDeclaredFields":true, @@ -703,6 +724,29 @@ "allDeclaredMethods":true, "allDeclaredConstructors":true} , +{ + "name":"org.asamk.signal.manager.JsonStickerPack", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[ + {"name":"author","parameterTypes":[] }, + {"name":"cover","parameterTypes":[] }, + {"name":"stickers","parameterTypes":[] }, + {"name":"title","parameterTypes":[] } + ]} +, +{ + "name":"org.asamk.signal.manager.JsonStickerPack$JsonSticker", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[ + {"name":"contentType","parameterTypes":[] }, + {"name":"emoji","parameterTypes":[] }, + {"name":"file","parameterTypes":[] } + ]} +, { "name":"org.asamk.signal.manager.api.PhoneNumberSharingMode", "allDeclaredFields":true, @@ -2353,6 +2397,38 @@ {"name":"revision_"} ]} , +{ + "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$GroupDetails", + "fields":[ + {"name":"active_"}, + {"name":"archived_"}, + {"name":"avatar_"}, + {"name":"bitField0_"}, + {"name":"blocked_"}, + {"name":"color_"}, + {"name":"expireTimer_"}, + {"name":"id_"}, + {"name":"inboxPosition_"}, + {"name":"membersE164_"}, + {"name":"members_"}, + {"name":"name_"} + ]} +, +{ + "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$GroupDetails$Avatar", + "fields":[ + {"name":"bitField0_"}, + {"name":"contentType_"}, + {"name":"length_"} + ]} +, +{ + "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$GroupDetails$Member", + "fields":[ + {"name":"bitField0_"}, + {"name":"e164_"} + ]} +, { "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$NullMessage", "fields":[ @@ -2569,6 +2645,25 @@ {"name":"metadata_"} ]} , +{ + "name":"org.whispersystems.signalservice.internal.sticker.StickerProtos$Pack", + "fields":[ + {"name":"author_"}, + {"name":"bitField0_"}, + {"name":"cover_"}, + {"name":"stickers_"}, + {"name":"title_"} + ]} +, +{ + "name":"org.whispersystems.signalservice.internal.sticker.StickerProtos$Pack$Sticker", + "fields":[ + {"name":"bitField0_"}, + {"name":"contentType_"}, + {"name":"emoji_"}, + {"name":"id_"} + ]} +, { "name":"org.whispersystems.signalservice.internal.storage.protos.AccountRecord", "allDeclaredFields":true} diff --git a/graalvm-config-dir/resource-config.json b/graalvm-config-dir/resource-config.json index 0ec65b60..3957fcad 100644 --- a/graalvm-config-dir/resource-config.json +++ b/graalvm-config-dir/resource-config.json @@ -55,9 +55,15 @@ { "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN\\E" }, + { + "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_PA\\E" + }, { "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_PL\\E" }, + { + "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_RO\\E" + }, { "pattern":"\\Qcom/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_RU\\E" }, diff --git a/lib/src/main/java/org/asamk/signal/manager/MultiAccountManager.java b/lib/src/main/java/org/asamk/signal/manager/MultiAccountManager.java index e7205276..7f041845 100644 --- a/lib/src/main/java/org/asamk/signal/manager/MultiAccountManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/MultiAccountManager.java @@ -1,7 +1,9 @@ package org.asamk.signal.manager; import java.io.IOException; +import java.net.URI; import java.util.List; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; public interface MultiAccountManager extends AutoCloseable { @@ -14,6 +16,10 @@ public interface MultiAccountManager extends AutoCloseable { Manager getManager(String phoneNumber); + URI getNewProvisioningDeviceLinkUri() throws TimeoutException, IOException; + + ProvisioningManager getProvisioningManagerFor(URI deviceLinkUri); + ProvisioningManager getNewProvisioningManager(); RegistrationManager getNewRegistrationManager(String username) throws IOException; diff --git a/lib/src/main/java/org/asamk/signal/manager/MultiAccountManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/MultiAccountManagerImpl.java index df74cf42..26f8b961 100644 --- a/lib/src/main/java/org/asamk/signal/manager/MultiAccountManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/MultiAccountManagerImpl.java @@ -6,10 +6,14 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.net.URI; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -20,6 +24,7 @@ public class MultiAccountManagerImpl implements MultiAccountManager { private final Set> onManagerAddedHandlers = new HashSet<>(); private final Set> onManagerRemovedHandlers = new HashSet<>(); private final Set managers = new HashSet<>(); + private final Map provisioningManagers = new HashMap<>(); private final File dataPath; private final ServiceEnvironment serviceEnvironment; private final String userAgent; @@ -78,6 +83,19 @@ public class MultiAccountManagerImpl implements MultiAccountManager { } } + @Override + public URI getNewProvisioningDeviceLinkUri() throws TimeoutException, IOException { + final var provisioningManager = getNewProvisioningManager(); + final var deviceLinkUri = provisioningManager.getDeviceLinkUri(); + provisioningManagers.put(deviceLinkUri, provisioningManager); + return deviceLinkUri; + } + + @Override + public ProvisioningManager getProvisioningManagerFor(final URI deviceLinkUri) { + return provisioningManagers.remove(deviceLinkUri); + } + @Override public ProvisioningManager getNewProvisioningManager() { return ProvisioningManager.init(dataPath, serviceEnvironment, userAgent, this::addManager); diff --git a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java index 6445e511..cfb4fe4b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java @@ -146,6 +146,7 @@ public class ProvisioningManager { ManagerImpl m = null; try { m = new ManagerImpl(account, pathConfig, serviceEnvironmentConfig, userAgent); + account = null; logger.debug("Refreshing pre keys"); try { diff --git a/src/main/java/org/asamk/signal/commands/Commands.java b/src/main/java/org/asamk/signal/commands/Commands.java index 54d5bf80..a3c4a863 100644 --- a/src/main/java/org/asamk/signal/commands/Commands.java +++ b/src/main/java/org/asamk/signal/commands/Commands.java @@ -13,6 +13,7 @@ public class Commands { addCommand(new AddDeviceCommand()); addCommand(new BlockCommand()); addCommand(new DaemonCommand()); + addCommand(new FinishLinkCommand()); addCommand(new GetUserStatusCommand()); addCommand(new JoinGroupCommand()); addCommand(new JsonRpcDispatcherCommand()); @@ -36,6 +37,7 @@ public class Commands { addCommand(new SendTypingCommand()); addCommand(new SetPinCommand()); addCommand(new SubmitRateLimitChallengeCommand()); + addCommand(new StartLinkCommand()); addCommand(new TrustCommand()); addCommand(new UnblockCommand()); addCommand(new UnregisterCommand()); diff --git a/src/main/java/org/asamk/signal/commands/FinishLinkCommand.java b/src/main/java/org/asamk/signal/commands/FinishLinkCommand.java new file mode 100644 index 00000000..40c241a2 --- /dev/null +++ b/src/main/java/org/asamk/signal/commands/FinishLinkCommand.java @@ -0,0 +1,73 @@ +package org.asamk.signal.commands; + +import com.fasterxml.jackson.core.type.TypeReference; + +import org.asamk.signal.JsonWriter; +import org.asamk.signal.commands.exceptions.CommandException; +import org.asamk.signal.commands.exceptions.IOErrorException; +import org.asamk.signal.commands.exceptions.UserErrorException; +import org.asamk.signal.manager.MultiAccountManager; +import org.asamk.signal.manager.UserAlreadyExists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.TimeoutException; + +public class FinishLinkCommand implements JsonRpcMultiCommand { + + private final static Logger logger = LoggerFactory.getLogger(FinishLinkCommand.class); + + @Override + public String getName() { + return "finishLink"; + } + + @Override + public TypeReference getRequestType() { + return new TypeReference<>() {}; + } + + @Override + public void handleCommand( + final FinishLinkParams request, final MultiAccountManager m, final JsonWriter jsonWriter + ) throws CommandException { + final URI deviceLinkUri; + try { + deviceLinkUri = new URI(request.deviceLinkUri()); + } catch (URISyntaxException e) { + throw new UserErrorException("Invalid device link uri."); + } + final var provisioningManager = m.getProvisioningManagerFor(deviceLinkUri); + if (provisioningManager == null) { + throw new UserErrorException("Unknown device link uri."); + } + + var deviceName = request.deviceName(); + if (deviceName == null) { + deviceName = "cli"; + } + final String number; + try { + number = provisioningManager.finishDeviceLink(deviceName); + } catch (TimeoutException e) { + throw new UserErrorException("Link request timed out, please try again."); + } catch (IOException e) { + throw new IOErrorException("Link request error: " + e.getMessage(), e); + } catch (UserAlreadyExists e) { + throw new UserErrorException("The user " + + e.getNumber() + + " already exists\nDelete \"" + + e.getFileName() + + "\" before trying again."); + } + + jsonWriter.write(new JsonFinishLink(number)); + } + + record FinishLinkParams(String deviceLinkUri, String deviceName) {} + + private record JsonFinishLink(String number) {} +} diff --git a/src/main/java/org/asamk/signal/commands/StartLinkCommand.java b/src/main/java/org/asamk/signal/commands/StartLinkCommand.java new file mode 100644 index 00000000..4a171140 --- /dev/null +++ b/src/main/java/org/asamk/signal/commands/StartLinkCommand.java @@ -0,0 +1,41 @@ +package org.asamk.signal.commands; + +import org.asamk.signal.JsonWriter; +import org.asamk.signal.commands.exceptions.CommandException; +import org.asamk.signal.commands.exceptions.IOErrorException; +import org.asamk.signal.commands.exceptions.UserErrorException; +import org.asamk.signal.manager.MultiAccountManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.TimeoutException; + +public class StartLinkCommand implements JsonRpcMultiCommand { + + private final static Logger logger = LoggerFactory.getLogger(StartLinkCommand.class); + + @Override + public String getName() { + return "startLink"; + } + + @Override + public void handleCommand( + final Void request, final MultiAccountManager m, final JsonWriter jsonWriter + ) throws CommandException { + final URI deviceLinkUri; + try { + deviceLinkUri = m.getNewProvisioningDeviceLinkUri(); + } catch (TimeoutException e) { + throw new UserErrorException("Device link creation timed out, please try again."); + } catch (IOException e) { + throw new IOErrorException("Link request error: " + e.getMessage(), e); + } + + jsonWriter.write(new JsonLink(deviceLinkUri.toString())); + } + + private record JsonLink(String deviceLinkUri) {} +} diff --git a/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java b/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java index 440759d6..c4e9775a 100644 --- a/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java +++ b/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java @@ -122,7 +122,6 @@ public class SignalJsonRpcDispatcherHandler { final ObjectMapper objectMapper, final String method, ContainerNode params ) throws JsonRpcException { var command = getCommand(method); - // TODO implement link if (c != null) { if (command instanceof JsonRpcMultiCommand jsonRpcCommand) { return runCommand(objectMapper, params, new MultiCommandRunnerImpl<>(c, jsonRpcCommand));