From: AsamK Date: Fri, 8 Apr 2016 21:32:26 +0000 (+0200) Subject: Add possiblity to add new device, as master X-Git-Tag: v0.4.0~22 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/947818d3172a4257b6d1a160496f1504d8f514ab Add possiblity to add new device, as master --- diff --git a/src/main/java/org/asamk/signal/Main.java b/src/main/java/org/asamk/signal/Main.java index 0d2e6f06..f2c83dfc 100644 --- a/src/main/java/org/asamk/signal/Main.java +++ b/src/main/java/org/asamk/signal/Main.java @@ -40,6 +40,8 @@ import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.security.Security; import java.util.ArrayList; import java.util.List; @@ -177,6 +179,28 @@ public class Main { System.exit(3); } break; + case "addDevice": + if (dBusConn != null) { + System.err.println("link is not yet implemented via dbus"); + System.exit(1); + } + if (!m.isRegistered()) { + System.err.println("User is not registered."); + System.exit(1); + } + try { + m.addDeviceLink(new URI(ns.getString("uri"))); + } catch (IOException e) { + e.printStackTrace(); + System.exit(3); + } catch (InvalidKeyException e) { + e.printStackTrace(); + System.exit(2); + } catch (URISyntaxException e) { + e.printStackTrace(); + System.exit(2); + } + break; case "send": if (dBusConn == null && !m.isRegistered()) { System.err.println("User is not registered."); @@ -462,6 +486,11 @@ public class Main { parserLink.addArgument("-n", "--name") .help("Specify a name to describe this new device."); + Subparser parserAddDevice = subparsers.addParser("addDevice"); + parserAddDevice.addArgument("--uri") + .required(true) + .help("Specify the uri contained in the QR code shown by the new device."); + Subparser parserRegister = subparsers.addParser("register"); parserRegister.addArgument("-v", "--voice") .help("The verification should be done over voice, not sms.") diff --git a/src/main/java/org/asamk/signal/Manager.java b/src/main/java/org/asamk/signal/Manager.java index d442224a..eb883bb8 100644 --- a/src/main/java/org/asamk/signal/Manager.java +++ b/src/main/java/org/asamk/signal/Manager.java @@ -23,10 +23,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.http.util.TextUtils; import org.asamk.Signal; import org.whispersystems.libsignal.*; import org.whispersystems.libsignal.ecc.Curve; import org.whispersystems.libsignal.ecc.ECKeyPair; +import org.whispersystems.libsignal.ecc.ECPublicKey; import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.SignalProtocolStore; import org.whispersystems.libsignal.state.SignedPreKeyRecord; @@ -40,6 +42,7 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.*; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.*; +import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.TrustStore; @@ -47,10 +50,12 @@ import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedE import org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptions; import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; +import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import java.io.*; import java.net.URI; import java.net.URISyntaxException; +import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Paths; @@ -245,6 +250,50 @@ class Manager implements Signal { registered = true; refreshPreKeys(); + save(); + } + + + public static Map getQueryMap(String query) { + String[] params = query.split("&"); + Map map = new HashMap<>(); + for (String param : params) { + String name = null; + try { + name = URLDecoder.decode(param.split("=")[0], "utf-8"); + } catch (UnsupportedEncodingException e) { + // Impossible + } + String value = null; + try { + value = URLDecoder.decode(param.split("=")[1], "utf-8"); + } catch (UnsupportedEncodingException e) { + // Impossible + } + map.put(name, value); + } + return map; + } + + public void addDeviceLink(URI linkUri) throws IOException, InvalidKeyException { + Map query = getQueryMap(linkUri.getQuery()); + String deviceIdentifier = query.get("uuid"); + String publicKeyEncoded = query.get("pub_key"); + + if (TextUtils.isEmpty(deviceIdentifier) || TextUtils.isEmpty(publicKeyEncoded)) { + throw new RuntimeException("Invalid device link uri"); + } + + ECPublicKey deviceKey = Curve.decodePoint(Base64.decode(publicKeyEncoded), 0); + + addDeviceLink(deviceIdentifier, deviceKey); + } + + private void addDeviceLink(String deviceIdentifier, ECPublicKey deviceKey) throws IOException, InvalidKeyException { + IdentityKeyPair identityKeyPair = signalProtocolStore.getIdentityKeyPair(); + String verificationCode = accountManager.getNewDeviceVerificationCode(); + + accountManager.addDevice(deviceIdentifier, deviceKey, identityKeyPair, verificationCode); } private List generatePreKeys() {