]> nmode's Git Repositories - signal-cli/commitdiff
Encrypt/decrypt device names
authorAsamK <asamk@gmx.de>
Sat, 8 May 2021 17:31:09 +0000 (19:31 +0200)
committerAsamK <asamk@gmx.de>
Sat, 8 May 2021 19:25:12 +0000 (21:25 +0200)
lib/build.gradle.kts
lib/src/main/java/org/asamk/signal/manager/Manager.java
lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java
lib/src/main/java/org/asamk/signal/manager/api/Device.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java
src/main/java/org/asamk/signal/commands/ListDevicesCommand.java

index 327d1538b45697890cde2cdae98008962f582a45..a9b5a95fca05effe0b71d99c1f88d413d42b6232 100644 (file)
@@ -14,7 +14,7 @@ repositories {
 }
 
 dependencies {
-    api("com.github.turasa:signal-service-java:2.15.3_unofficial_20")
+    api("com.github.turasa:signal-service-java:2.15.3_unofficial_21")
     implementation("com.google.protobuf:protobuf-javalite:3.10.0")
     implementation("org.bouncycastle:bcprov-jdk15on:1.68")
     implementation("org.slf4j:slf4j-api:1.7.30")
index a1a4b278f8160ac9d7bb9cf899b08913ffc81f33..acd48c34e3153281697737cac41944f3950a37e0 100644 (file)
@@ -16,6 +16,7 @@
  */
 package org.asamk.signal.manager;
 
+import org.asamk.signal.manager.api.Device;
 import org.asamk.signal.manager.config.ServiceConfig;
 import org.asamk.signal.manager.config.ServiceEnvironment;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
@@ -108,7 +109,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsO
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
 import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
-import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
 import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
 import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
 import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
@@ -119,6 +119,7 @@ import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
 import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
+import org.whispersystems.signalservice.api.util.DeviceNameUtil;
 import org.whispersystems.signalservice.api.util.InvalidNumberException;
 import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
 import org.whispersystems.signalservice.api.util.SleepTimer;
@@ -341,7 +342,7 @@ public class Manager implements Closeable {
     }
 
     public void updateAccountAttributes() throws IOException {
-        accountManager.setAccountAttributes(account.getDeviceName(),
+        accountManager.setAccountAttributes(account.getEncryptedDeviceName(),
                 null,
                 account.getLocalRegistrationId(),
                 true,
@@ -422,10 +423,21 @@ public class Manager implements Closeable {
         account.setRegistered(false);
     }
 
-    public List<DeviceInfo> getLinkedDevices() throws IOException {
+    public List<Device> getLinkedDevices() throws IOException {
         var devices = accountManager.getDevices();
         account.setMultiDevice(devices.size() > 1);
-        return devices;
+        var identityKey = account.getIdentityKeyPair().getPrivateKey();
+        return devices.stream().map(d -> {
+            String deviceName = d.getName();
+            if (deviceName != null) {
+                try {
+                    deviceName = DeviceNameUtil.decryptDeviceName(deviceName, identityKey);
+                } catch (IOException e) {
+                    logger.debug("Failed to decrypt device name, maybe plain text?", e);
+                }
+            }
+            return new Device(d.getId(), deviceName, d.getCreated(), d.getLastSeen());
+        }).collect(Collectors.toList());
     }
 
     public void removeLinkedDevices(int deviceId) throws IOException {
index d27d911e4b3185b5616d515c0c8136acf0bc5bec..e813340e383052a3a08abc80f4f497b54f4cc708 100644 (file)
@@ -29,6 +29,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
 import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
 import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.api.util.DeviceNameUtil;
 import org.whispersystems.signalservice.api.util.SleepTimer;
 import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
 import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
@@ -47,7 +48,7 @@ public class ProvisioningManager {
     private final String userAgent;
 
     private final SignalServiceAccountManager accountManager;
-    private final IdentityKeyPair identityKey;
+    private final IdentityKeyPair tempIdentityKey;
     private final int registrationId;
     private final String password;
 
@@ -56,7 +57,7 @@ public class ProvisioningManager {
         this.serviceEnvironmentConfig = serviceEnvironmentConfig;
         this.userAgent = userAgent;
 
-        identityKey = KeyUtils.generateIdentityKeyPair();
+        tempIdentityKey = KeyUtils.generateIdentityKeyPair();
         registrationId = KeyHelper.generateRegistrationId(false);
         password = KeyUtils.createPassword();
         final SleepTimer timer = new UptimeSleepTimer();
@@ -87,22 +88,26 @@ public class ProvisioningManager {
     public URI getDeviceLinkUri() throws TimeoutException, IOException {
         var deviceUuid = accountManager.getNewDeviceUuid();
 
-        return new DeviceLinkInfo(deviceUuid, identityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
+        return new DeviceLinkInfo(deviceUuid, tempIdentityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
     }
 
     public Manager finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists {
-        var ret = accountManager.getNewDeviceRegistration(identityKey);
+        var ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
         var number = ret.getNumber();
 
         if (SignalAccount.userExists(pathConfig.getDataPath(), number)) {
             throw new UserAlreadyExists(number, SignalAccount.getFileName(pathConfig.getDataPath(), number));
         }
 
+        var encryptedDeviceName = deviceName == null
+                ? null
+                : DeviceNameUtil.encryptDeviceName(deviceName, ret.getIdentity().getPrivateKey());
+
         var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
                 false,
                 true,
                 registrationId,
-                deviceName);
+                encryptedDeviceName);
 
         // Create new account with the synced identity
         var profileKey = ret.getProfileKey() == null ? KeyUtils.createProfileKey() : ret.getProfileKey();
@@ -113,7 +118,7 @@ public class ProvisioningManager {
                     number,
                     ret.getUuid(),
                     password,
-                    deviceName,
+                    encryptedDeviceName,
                     deviceId,
                     ret.getIdentity(),
                     registrationId,
diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Device.java b/lib/src/main/java/org/asamk/signal/manager/api/Device.java
new file mode 100644 (file)
index 0000000..76074cb
--- /dev/null
@@ -0,0 +1,32 @@
+package org.asamk.signal.manager.api;
+
+public class Device {
+
+    private final long id;
+    private final String name;
+    private final long created;
+    private final long lastSeen;
+
+    public Device(long id, String name, long created, long lastSeen) {
+        this.id = id;
+        this.name = name;
+        this.created = created;
+        this.lastSeen = lastSeen;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public long getCreated() {
+        return created;
+    }
+
+    public long getLastSeen() {
+        return lastSeen;
+    }
+}
index f12361a1532ccab1130998806373fab70a05cfc1..93178a91766430df6027c6ce28604547dddf3442 100644 (file)
@@ -74,7 +74,7 @@ public class SignalAccount implements Closeable {
 
     private String username;
     private UUID uuid;
-    private String deviceName;
+    private String encryptedDeviceName;
     private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
     private boolean isMultiDevice = false;
     private String password;
@@ -172,7 +172,7 @@ public class SignalAccount implements Closeable {
             String username,
             UUID uuid,
             String password,
-            String deviceName,
+            String encryptedDeviceName,
             int deviceId,
             IdentityKeyPair identityKey,
             int registrationId,
@@ -191,7 +191,7 @@ public class SignalAccount implements Closeable {
         account.uuid = uuid;
         account.password = password;
         account.profileKey = profileKey;
-        account.deviceName = deviceName;
+        account.encryptedDeviceName = encryptedDeviceName;
         account.deviceId = deviceId;
 
         account.initStores(dataPath, identityKey, registrationId);
@@ -307,7 +307,7 @@ public class SignalAccount implements Closeable {
             }
         }
         if (rootNode.hasNonNull("deviceName")) {
-            deviceName = rootNode.get("deviceName").asText();
+            encryptedDeviceName = rootNode.get("deviceName").asText();
         }
         if (rootNode.hasNonNull("deviceId")) {
             deviceId = rootNode.get("deviceId").asInt();
@@ -579,7 +579,7 @@ public class SignalAccount implements Closeable {
             rootNode.put("version", CURRENT_STORAGE_VERSION)
                     .put("username", username)
                     .put("uuid", uuid == null ? null : uuid.toString())
-                    .put("deviceName", deviceName)
+                    .put("deviceName", encryptedDeviceName)
                     .put("deviceId", deviceId)
                     .put("isMultiDevice", isMultiDevice)
                     .put("password", password)
@@ -708,8 +708,8 @@ public class SignalAccount implements Closeable {
         return recipientStore.resolveRecipientTrusted(getSelfAddress());
     }
 
-    public String getDeviceName() {
-        return deviceName;
+    public String getEncryptedDeviceName() {
+        return encryptedDeviceName;
     }
 
     public int getDeviceId() {
@@ -823,7 +823,7 @@ public class SignalAccount implements Closeable {
 
     public void finishRegistration(final UUID uuid, final MasterKey masterKey, final String pin) {
         this.pinMasterKey = masterKey;
-        this.deviceName = null;
+        this.encryptedDeviceName = null;
         this.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
         this.isMultiDevice = false;
         this.registered = true;
index 7165d07c4666a3ce933813bbc2ed5d0d9320bc74..d6c59498302e746795e9b57b8cff0bc0ffc872ac 100644 (file)
@@ -7,10 +7,10 @@ import org.asamk.signal.PlainTextWriterImpl;
 import org.asamk.signal.commands.exceptions.CommandException;
 import org.asamk.signal.commands.exceptions.IOErrorException;
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.api.Device;
 import org.asamk.signal.util.DateUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
 
 import java.io.IOException;
 import java.util.List;
@@ -27,7 +27,7 @@ public class ListDevicesCommand implements LocalCommand {
     public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
         final var writer = new PlainTextWriterImpl(System.out);
 
-        List<DeviceInfo> devices;
+        List<Device> devices;
         try {
             devices = m.getLinkedDevices();
         } catch (IOException e) {