]> nmode's Git Repositories - signal-cli/commitdiff
Implement startLink and finishLink for jsonrpc daemon
authorAsamK <asamk@gmx.de>
Thu, 11 Nov 2021 17:27:16 +0000 (18:27 +0100)
committerAsamK <asamk@gmx.de>
Thu, 11 Nov 2021 18:15:20 +0000 (19:15 +0100)
graalvm-config-dir/reflect-config.json
graalvm-config-dir/resource-config.json
lib/src/main/java/org/asamk/signal/manager/MultiAccountManager.java
lib/src/main/java/org/asamk/signal/manager/MultiAccountManagerImpl.java
lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java
src/main/java/org/asamk/signal/commands/Commands.java
src/main/java/org/asamk/signal/commands/FinishLinkCommand.java [new file with mode: 0644]
src/main/java/org/asamk/signal/commands/StartLinkCommand.java [new file with mode: 0644]
src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java

index ebca03a5285cc8412fd9adb7e15cb16f81f4a613..d254d85f832361a5be4b5c60018b6eb6bdee933b 100644 (file)
   "allDeclaredMethods":true,
   "allDeclaredClasses":true}
 ,
+{
+  "name":"org.asamk.signal.commands.FinishLinkCommand$FinishLinkParams",
+  "allDeclaredFields":true,
+  "queryAllDeclaredMethods":true,
+  "queryAllDeclaredConstructors":true,
+  "methods":[{"name":"<init>","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,
   "queryAllDeclaredConstructors":true,
   "methods":[{"name":"<init>","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,
   "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,
     {"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":[
     {"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}
index 0ec65b60a9667662d49a9827fcf03dd92d759fcc..3957fcad30560aa6a00b2fd09e62de765d2be756 100644 (file)
     {
       "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"
     }, 
index e7205276e32f7e68476411b5be58dfddec68c523..7f041845d0e16e161ff0e87a64f4b5c32a00f008 100644 (file)
@@ -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;
index df74cf42418cf83078e96784a0899bcd10a63b0a..26f8b961b089b80c34e71179a1f9d8be37ccdd17 100644 (file)
@@ -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<Consumer<Manager>> onManagerAddedHandlers = new HashSet<>();
     private final Set<Consumer<Manager>> onManagerRemovedHandlers = new HashSet<>();
     private final Set<Manager> managers = new HashSet<>();
+    private final Map<URI, ProvisioningManager> 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);
index 6445e5111fc8f68e6fd3150971123cf22d0deeb3..cfb4fe4b5863f319a9aa6e5a8170e21536ff2b13 100644 (file)
@@ -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 {
index 54d5bf80d758d47661c1003073df8a31279f13c2..a3c4a863eb927ef075528b8fa2edea619cc82ec5 100644 (file)
@@ -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 (file)
index 0000000..40c241a
--- /dev/null
@@ -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<FinishLinkCommand.FinishLinkParams> {
+
+    private final static Logger logger = LoggerFactory.getLogger(FinishLinkCommand.class);
+
+    @Override
+    public String getName() {
+        return "finishLink";
+    }
+
+    @Override
+    public TypeReference<FinishLinkParams> 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 (file)
index 0000000..4a17114
--- /dev/null
@@ -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<Void> {
+
+    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) {}
+}
index 440759d614e517826dfeae453daa05a03290056f..c4e9775aefb52f273e378286d830427a15fbf8c0 100644 (file)
@@ -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));