From: AsamK Date: Thu, 11 Nov 2021 14:49:23 +0000 (+0100) Subject: Implement register and verify commands for json rpc X-Git-Tag: v0.10.0~53 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/79cc225869b9a97bbb5b3f054970d5a6bb2222ee?ds=inline Implement register and verify commands for json rpc --- diff --git a/graalvm-config-dir/reflect-config.json b/graalvm-config-dir/reflect-config.json index 3c028979..ebca03a5 100644 --- a/graalvm-config-dir/reflect-config.json +++ b/graalvm-config-dir/reflect-config.json @@ -486,6 +486,20 @@ "allDeclaredMethods":true, "allDeclaredConstructors":true} , +{ + "name":"org.asamk.signal.commands.RegisterCommand$RegistrationParams", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.String"] }]} +, +{ + "name":"org.asamk.signal.commands.VerifyCommand$VerifyParams", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":["java.lang.String","java.lang.String"] }]} +, { "name":"org.asamk.signal.json.JsonAttachment", "allDeclaredFields":true, @@ -2410,6 +2424,13 @@ {"name":"type_"} ]} , +{ + "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$SyncMessage$Groups", + "fields":[ + {"name":"bitField0_"}, + {"name":"blob_"} + ]} +, { "name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$SyncMessage$Keys", "fields":[ diff --git a/src/main/java/org/asamk/signal/Main.java b/src/main/java/org/asamk/signal/Main.java index eaa85c12..fb9d92b6 100644 --- a/src/main/java/org/asamk/signal/Main.java +++ b/src/main/java/org/asamk/signal/Main.java @@ -100,7 +100,7 @@ public class Main { } SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); - // java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.FINEST); + java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.FINEST); } private static int getStatusForError(final CommandException e) { diff --git a/src/main/java/org/asamk/signal/commands/JsonRpcRegistrationCommand.java b/src/main/java/org/asamk/signal/commands/JsonRpcRegistrationCommand.java new file mode 100644 index 00000000..c68fe9d0 --- /dev/null +++ b/src/main/java/org/asamk/signal/commands/JsonRpcRegistrationCommand.java @@ -0,0 +1,10 @@ +package org.asamk.signal.commands; + +import org.asamk.signal.JsonWriter; +import org.asamk.signal.commands.exceptions.CommandException; +import org.asamk.signal.manager.RegistrationManager; + +public interface JsonRpcRegistrationCommand extends JsonRpcCommand { + + void handleCommand(T request, RegistrationManager m, JsonWriter jsonWriter) throws CommandException; +} diff --git a/src/main/java/org/asamk/signal/commands/RegisterCommand.java b/src/main/java/org/asamk/signal/commands/RegisterCommand.java index da72e1a4..afb4ee11 100644 --- a/src/main/java/org/asamk/signal/commands/RegisterCommand.java +++ b/src/main/java/org/asamk/signal/commands/RegisterCommand.java @@ -1,9 +1,13 @@ package org.asamk.signal.commands; +import com.fasterxml.jackson.core.type.TypeReference; + import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Subparser; +import org.asamk.signal.JsonWriter; +import org.asamk.signal.OutputType; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; @@ -11,8 +15,9 @@ import org.asamk.signal.manager.RegistrationManager; import org.asamk.signal.manager.api.CaptchaRequiredException; import java.io.IOException; +import java.util.List; -public class RegisterCommand implements RegistrationCommand { +public class RegisterCommand implements RegistrationCommand, JsonRpcRegistrationCommand { @Override public String getName() { @@ -32,9 +37,31 @@ public class RegisterCommand implements RegistrationCommand { @Override public void handleCommand(final Namespace ns, final RegistrationManager m) throws CommandException { final boolean voiceVerification = Boolean.TRUE.equals(ns.getBoolean("voice")); - final var captchaString = ns.getString("captcha"); - final var captcha = captchaString == null ? null : captchaString.replace("signalcaptcha://", ""); + final var captcha = ns.getString("captcha"); + + register(m, voiceVerification, captcha); + } + @Override + public TypeReference getRequestType() { + return new TypeReference<>() {}; + } + + @Override + public List getSupportedOutputTypes() { + return List.of(OutputType.PLAIN_TEXT, OutputType.JSON); + } + + @Override + public void handleCommand( + final RegistrationParams request, final RegistrationManager m, final JsonWriter jsonWriter + ) throws CommandException { + register(m, Boolean.TRUE.equals(request.voice()), request.captcha()); + } + + private void register( + final RegistrationManager m, final boolean voiceVerification, final String captcha + ) throws UserErrorException, IOErrorException { try { m.register(voiceVerification, captcha); } catch (CaptchaRequiredException e) { @@ -53,4 +80,6 @@ public class RegisterCommand implements RegistrationCommand { throw new IOErrorException("Request verify error: " + e.getMessage(), e); } } + + record RegistrationParams(Boolean voice, String captcha) {} } diff --git a/src/main/java/org/asamk/signal/commands/VerifyCommand.java b/src/main/java/org/asamk/signal/commands/VerifyCommand.java index 155cdb09..ae0017af 100644 --- a/src/main/java/org/asamk/signal/commands/VerifyCommand.java +++ b/src/main/java/org/asamk/signal/commands/VerifyCommand.java @@ -1,18 +1,27 @@ package org.asamk.signal.commands; +import com.fasterxml.jackson.core.type.TypeReference; + import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Subparser; +import org.asamk.signal.JsonWriter; +import org.asamk.signal.OutputType; 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.RegistrationManager; import org.asamk.signal.manager.api.IncorrectPinException; import org.asamk.signal.manager.api.PinLockedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.List; + +public class VerifyCommand implements RegistrationCommand, JsonRpcRegistrationCommand { -public class VerifyCommand implements RegistrationCommand { + private final static Logger logger = LoggerFactory.getLogger(VerifyCommand.class); @Override public String getName() { @@ -22,15 +31,38 @@ public class VerifyCommand implements RegistrationCommand { @Override public void attachToSubparser(final Subparser subparser) { subparser.help("Verify the number using the code received via SMS or voice."); - subparser.addArgument("verificationCode").help("The verification code you received via sms or voice call."); + subparser.addArgument("verification-code").help("The verification code you received via sms or voice call."); subparser.addArgument("-p", "--pin").help("The registration lock PIN, that was set by the user (Optional)"); } @Override public void handleCommand(final Namespace ns, final RegistrationManager m) throws CommandException { - var verificationCode = ns.getString("verificationCode"); + var verificationCode = ns.getString("verification-code"); var pin = ns.getString("pin"); + verify(m, verificationCode, pin); + } + + @Override + public TypeReference getRequestType() { + return new TypeReference<>() {}; + } + + @Override + public List getSupportedOutputTypes() { + return List.of(OutputType.PLAIN_TEXT, OutputType.JSON); + } + + @Override + public void handleCommand( + final VerifyParams request, final RegistrationManager m, final JsonWriter jsonWriter + ) throws CommandException { + verify(m, request.verificationCode(), request.pin()); + } + + private void verify( + final RegistrationManager m, final String verificationCode, final String pin + ) throws UserErrorException, IOErrorException { try { m.verifyAccount(verificationCode, pin); } catch (PinLockedException e) { @@ -44,4 +76,6 @@ public class VerifyCommand implements RegistrationCommand { throw new IOErrorException("Verify error: " + e.getMessage(), e); } } + + record VerifyParams(String verificationCode, String pin) {} } diff --git a/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java b/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java index 112bc5a9..440759d6 100644 --- a/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java +++ b/src/main/java/org/asamk/signal/jsonrpc/SignalJsonRpcDispatcherHandler.java @@ -13,6 +13,7 @@ import org.asamk.signal.JsonWriter; import org.asamk.signal.commands.Command; import org.asamk.signal.commands.Commands; import org.asamk.signal.commands.JsonRpcMultiCommand; +import org.asamk.signal.commands.JsonRpcRegistrationCommand; import org.asamk.signal.commands.JsonRpcSingleCommand; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; @@ -20,6 +21,7 @@ import org.asamk.signal.commands.exceptions.UntrustedKeyErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.MultiAccountManager; +import org.asamk.signal.manager.RegistrationManager; import org.asamk.signal.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -120,11 +122,26 @@ public class SignalJsonRpcDispatcherHandler { final ObjectMapper objectMapper, final String method, ContainerNode params ) throws JsonRpcException { var command = getCommand(method); - // TODO implement register, verify, link + // TODO implement link if (c != null) { if (command instanceof JsonRpcMultiCommand jsonRpcCommand) { return runCommand(objectMapper, params, new MultiCommandRunnerImpl<>(c, jsonRpcCommand)); } + if (command instanceof JsonRpcRegistrationCommand jsonRpcCommand) { + try (var manager = getRegistrationManagerFromParams(params)) { + if (manager != null) { + return runCommand(objectMapper, + params, + new RegistrationCommandRunnerImpl<>(manager, c, jsonRpcCommand)); + } else { + throw new JsonRpcException(new JsonRpcResponse.Error(JsonRpcResponse.Error.INVALID_PARAMS, + "Method requires valid account parameter", + null)); + } + } catch (IOException e) { + logger.warn("Failed to close registration manager", e); + } + } } if (command instanceof JsonRpcSingleCommand jsonRpcCommand) { if (m != null) { @@ -147,7 +164,7 @@ public class SignalJsonRpcDispatcherHandler { } private Manager getManagerFromParams(final ContainerNode params) { - if (params.has("account")) { + if (params != null && params.has("account")) { final var manager = c.getManager(params.get("account").asText()); ((ObjectNode) params).remove("account"); return manager; @@ -155,6 +172,20 @@ public class SignalJsonRpcDispatcherHandler { return null; } + private RegistrationManager getRegistrationManagerFromParams(final ContainerNode params) { + if (params != null && params.has("account")) { + try { + final var registrationManager = c.getNewRegistrationManager(params.get("account").asText()); + ((ObjectNode) params).remove("account"); + return registrationManager; + } catch (IOException | IllegalStateException e) { + logger.warn("Failed to load registration manager", e); + return null; + } + } + return null; + } + private Command getCommand(final String method) { if ("subscribeReceive".equals(method)) { return new SubscribeReceiveCommand(); @@ -178,6 +209,21 @@ public class SignalJsonRpcDispatcherHandler { } } + private record RegistrationCommandRunnerImpl( + RegistrationManager m, MultiAccountManager c, JsonRpcRegistrationCommand command + ) implements CommandRunner { + + @Override + public void handleCommand(final T request, final JsonWriter jsonWriter) throws CommandException { + command.handleCommand(request, m, jsonWriter); + } + + @Override + public TypeReference getRequestType() { + return command.getRequestType(); + } + } + private record MultiCommandRunnerImpl( MultiAccountManager c, JsonRpcMultiCommand command ) implements CommandRunner {