]> nmode's Git Repositories - signal-cli/blobdiff - src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java
Handle UnauthenticatedResponseException internally
[signal-cli] / src / main / java / org / asamk / signal / dbus / DbusManagerImpl.java
index ea776797b7182c3c841804e734667ba367cfd6b5..df0bb86925e2fe63914f5207fb89ea9a1b786ad9 100644 (file)
@@ -1,6 +1,7 @@
 package org.asamk.signal.dbus;
 
 import org.asamk.Signal;
+import org.asamk.signal.DbusConfig;
 import org.asamk.signal.manager.AttachmentInvalidException;
 import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.NotMasterDeviceException;
@@ -9,14 +10,17 @@ import org.asamk.signal.manager.UntrustedIdentityException;
 import org.asamk.signal.manager.api.Device;
 import org.asamk.signal.manager.api.Group;
 import org.asamk.signal.manager.api.Identity;
+import org.asamk.signal.manager.api.InactiveGroupLinkException;
+import org.asamk.signal.manager.api.InvalidDeviceLinkException;
 import org.asamk.signal.manager.api.Message;
+import org.asamk.signal.manager.api.Pair;
 import org.asamk.signal.manager.api.RecipientIdentifier;
 import org.asamk.signal.manager.api.SendGroupMessageResults;
 import org.asamk.signal.manager.api.SendMessageResults;
 import org.asamk.signal.manager.api.TypingAction;
+import org.asamk.signal.manager.api.UpdateGroup;
 import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
-import org.asamk.signal.manager.groups.GroupLinkState;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupPermission;
 import org.asamk.signal.manager.groups.GroupSendingNotAllowedException;
@@ -25,16 +29,14 @@ import org.asamk.signal.manager.groups.NotAGroupMemberException;
 import org.asamk.signal.manager.storage.recipients.Contact;
 import org.asamk.signal.manager.storage.recipients.Profile;
 import org.asamk.signal.manager.storage.recipients.RecipientAddress;
-import org.whispersystems.libsignal.IdentityKey;
-import org.whispersystems.libsignal.InvalidKeyException;
-import org.whispersystems.libsignal.util.Pair;
-import org.whispersystems.libsignal.util.guava.Optional;
-import org.whispersystems.signalservice.api.groupsv2.GroupLinkNotActiveException;
+import org.freedesktop.dbus.DBusPath;
+import org.freedesktop.dbus.connections.impl.DBusConnection;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.interfaces.DBusInterface;
 import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
 import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
 import org.whispersystems.signalservice.api.util.UuidUtil;
-import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
 
 import java.io.File;
 import java.io.IOException;
@@ -44,6 +46,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
@@ -58,9 +61,11 @@ import java.util.stream.Collectors;
 public class DbusManagerImpl implements Manager {
 
     private final Signal signal;
+    private final DBusConnection connection;
 
-    public DbusManagerImpl(final Signal signal) {
+    public DbusManagerImpl(final Signal signal, DBusConnection connection) {
         this.signal = signal;
+        this.connection = connection;
     }
 
     @Override
@@ -89,7 +94,8 @@ public class DbusManagerImpl implements Manager {
     @Override
     public void updateAccountAttributes(final String deviceName) throws IOException {
         if (deviceName != null) {
-            signal.updateDeviceName(deviceName);
+            final var devicePath = signal.getThisDevice();
+            getRemoteObject(devicePath, Signal.Device.class).Set("org.asamk.Signal.Device", "Name", deviceName);
         }
     }
 
@@ -115,7 +121,7 @@ public class DbusManagerImpl implements Manager {
                 emptyIfNull(familyName),
                 emptyIfNull(about),
                 emptyIfNull(aboutEmoji),
-                avatar == null ? "" : avatar.transform(File::getPath).or(""),
+                avatar == null ? "" : avatar.map(File::getPath).orElse(""),
                 avatar != null && !avatar.isPresent());
     }
 
@@ -136,24 +142,31 @@ public class DbusManagerImpl implements Manager {
 
     @Override
     public List<Device> getLinkedDevices() throws IOException {
-        return signal.listDevices()
-                .stream()
-                .map(name -> new Device(-1, name, 0, 0, false))
-                .collect(Collectors.toList());
+        final var thisDevice = signal.getThisDevice();
+        return signal.listDevices().stream().map(d -> {
+            final var device = getRemoteObject(d.getObjectPath(),
+                    Signal.Device.class).GetAll("org.asamk.Signal.Device");
+            return new Device((long) device.get("Id").getValue(),
+                    (String) device.get("Name").getValue(),
+                    (long) device.get("Created").getValue(),
+                    (long) device.get("LastSeen").getValue(),
+                    thisDevice.equals(d.getObjectPath()));
+        }).collect(Collectors.toList());
     }
 
     @Override
-    public void removeLinkedDevices(final int deviceId) throws IOException {
-        signal.removeDevice(deviceId);
+    public void removeLinkedDevices(final long deviceId) throws IOException {
+        final var devicePath = signal.getDevice(deviceId);
+        getRemoteObject(devicePath, Signal.Device.class).removeDevice();
     }
 
     @Override
-    public void addDeviceLink(final URI linkUri) throws IOException, InvalidKeyException {
+    public void addDeviceLink(final URI linkUri) throws IOException, InvalidDeviceLinkException {
         signal.addDevice(linkUri.toString());
     }
 
     @Override
-    public void setRegistrationLockPin(final Optional<String> pin) throws IOException, UnauthenticatedResponseException {
+    public void setRegistrationLockPin(final Optional<String> pin) throws IOException {
         if (pin.isPresent()) {
             signal.setPin(pin.get());
         } else {
@@ -168,8 +181,8 @@ public class DbusManagerImpl implements Manager {
 
     @Override
     public List<Group> getGroups() {
-        final var groupIds = signal.getGroupIds();
-        return groupIds.stream().map(id -> getGroup(GroupId.unknownVersion(id))).collect(Collectors.toList());
+        final var groups = signal.listGroups();
+        return groups.stream().map(Signal.StructGroup::getObjectPath).map(this::getGroup).collect(Collectors.toList());
     }
 
     @Override
@@ -179,7 +192,8 @@ public class DbusManagerImpl implements Manager {
         if (groupAdmins.size() > 0) {
             throw new UnsupportedOperationException();
         }
-        signal.quitGroup(groupId.serialize());
+        final var group = getRemoteObject(signal.getGroup(groupId.serialize()), Signal.Group.class);
+        group.quitGroup();
         return new SendGroupMessageResults(0, List.of());
     }
 
@@ -192,8 +206,7 @@ public class DbusManagerImpl implements Manager {
     public Pair<GroupId, SendGroupMessageResults> createGroup(
             final String name, final Set<RecipientIdentifier.Single> members, final File avatarFile
     ) throws IOException, AttachmentInvalidException {
-        final var newGroupId = signal.updateGroup(new byte[0],
-                emptyIfNull(name),
+        final var newGroupId = signal.createGroup(emptyIfNull(name),
                 members.stream().map(RecipientIdentifier.Single::getIdentifier).collect(Collectors.toList()),
                 avatarFile == null ? "" : avatarFile.getPath());
         return new Pair<>(GroupId.unknownVersion(newGroupId), new SendGroupMessageResults(0, List.of()));
@@ -201,30 +214,75 @@ public class DbusManagerImpl implements Manager {
 
     @Override
     public SendGroupMessageResults updateGroup(
-            final GroupId groupId,
-            final String name,
-            final String description,
-            final Set<RecipientIdentifier.Single> members,
-            final Set<RecipientIdentifier.Single> removeMembers,
-            final Set<RecipientIdentifier.Single> admins,
-            final Set<RecipientIdentifier.Single> removeAdmins,
-            final boolean resetGroupLink,
-            final GroupLinkState groupLinkState,
-            final GroupPermission addMemberPermission,
-            final GroupPermission editDetailsPermission,
-            final File avatarFile,
-            final Integer expirationTimer,
-            final Boolean isAnnouncementGroup
+            final GroupId groupId, final UpdateGroup updateGroup
     ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException, GroupSendingNotAllowedException {
-        signal.updateGroup(groupId.serialize(),
-                emptyIfNull(name),
-                members.stream().map(RecipientIdentifier.Single::getIdentifier).collect(Collectors.toList()),
-                avatarFile == null ? "" : avatarFile.getPath());
+        final var group = getRemoteObject(signal.getGroup(groupId.serialize()), Signal.Group.class);
+        if (updateGroup.getName() != null) {
+            group.Set("org.asamk.Signal.Group", "Name", updateGroup.getName());
+        }
+        if (updateGroup.getDescription() != null) {
+            group.Set("org.asamk.Signal.Group", "Description", updateGroup.getDescription());
+        }
+        if (updateGroup.getAvatarFile() != null) {
+            group.Set("org.asamk.Signal.Group",
+                    "Avatar",
+                    updateGroup.getAvatarFile() == null ? "" : updateGroup.getAvatarFile().getPath());
+        }
+        if (updateGroup.getExpirationTimer() != null) {
+            group.Set("org.asamk.Signal.Group", "MessageExpirationTimer", updateGroup.getExpirationTimer());
+        }
+        if (updateGroup.getAddMemberPermission() != null) {
+            group.Set("org.asamk.Signal.Group", "PermissionAddMember", updateGroup.getAddMemberPermission().name());
+        }
+        if (updateGroup.getEditDetailsPermission() != null) {
+            group.Set("org.asamk.Signal.Group", "PermissionEditDetails", updateGroup.getEditDetailsPermission().name());
+        }
+        if (updateGroup.getIsAnnouncementGroup() != null) {
+            group.Set("org.asamk.Signal.Group",
+                    "PermissionSendMessage",
+                    updateGroup.getIsAnnouncementGroup()
+                            ? GroupPermission.ONLY_ADMINS.name()
+                            : GroupPermission.EVERY_MEMBER.name());
+        }
+        if (updateGroup.getMembers() != null) {
+            group.addMembers(updateGroup.getMembers()
+                    .stream()
+                    .map(RecipientIdentifier.Single::getIdentifier)
+                    .collect(Collectors.toList()));
+        }
+        if (updateGroup.getRemoveMembers() != null) {
+            group.removeMembers(updateGroup.getRemoveMembers()
+                    .stream()
+                    .map(RecipientIdentifier.Single::getIdentifier)
+                    .collect(Collectors.toList()));
+        }
+        if (updateGroup.getAdmins() != null) {
+            group.addAdmins(updateGroup.getAdmins()
+                    .stream()
+                    .map(RecipientIdentifier.Single::getIdentifier)
+                    .collect(Collectors.toList()));
+        }
+        if (updateGroup.getRemoveAdmins() != null) {
+            group.removeAdmins(updateGroup.getRemoveAdmins()
+                    .stream()
+                    .map(RecipientIdentifier.Single::getIdentifier)
+                    .collect(Collectors.toList()));
+        }
+        if (updateGroup.isResetGroupLink()) {
+            group.resetLink();
+        }
+        if (updateGroup.getGroupLinkState() != null) {
+            switch (updateGroup.getGroupLinkState()) {
+                case DISABLED -> group.disableLink();
+                case ENABLED -> group.enableLink(false);
+                case ENABLED_WITH_APPROVAL -> group.enableLink(true);
+            }
+        }
         return new SendGroupMessageResults(0, List.of());
     }
 
     @Override
-    public Pair<GroupId, SendGroupMessageResults> joinGroup(final GroupInviteLinkUrl inviteLinkUrl) throws IOException, GroupLinkNotActiveException {
+    public Pair<GroupId, SendGroupMessageResults> joinGroup(final GroupInviteLinkUrl inviteLinkUrl) throws IOException, InactiveGroupLinkException {
         final var newGroupId = signal.joinGroup(inviteLinkUrl.getUrl());
         return new Pair<>(GroupId.unknownVersion(newGroupId), new SendGroupMessageResults(0, List.of()));
     }
@@ -262,9 +320,9 @@ public class DbusManagerImpl implements Manager {
             final Message message, final Set<RecipientIdentifier> recipients
     ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
         return handleMessage(recipients,
-                numbers -> signal.sendMessage(message.getMessageText(), message.getAttachments(), numbers),
-                () -> signal.sendNoteToSelfMessage(message.getMessageText(), message.getAttachments()),
-                groupId -> signal.sendGroupMessage(message.getMessageText(), message.getAttachments(), groupId));
+                numbers -> signal.sendMessage(message.messageText(), message.attachments(), numbers),
+                () -> signal.sendNoteToSelfMessage(message.messageText(), message.attachments()),
+                groupId -> signal.sendGroupMessage(message.messageText(), message.attachments(), groupId));
     }
 
     @Override
@@ -329,7 +387,12 @@ public class DbusManagerImpl implements Manager {
     public void setGroupBlocked(
             final GroupId groupId, final boolean blocked
     ) throws GroupNotFoundException, IOException {
-        signal.setGroupBlocked(groupId.serialize(), blocked);
+        setGroupProperty(groupId, "IsBlocked", blocked);
+    }
+
+    private void setGroupProperty(final GroupId groupId, final String propertyName, final boolean blocked) {
+        final var group = getRemoteObject(signal.getGroup(groupId.serialize()), Signal.Group.class);
+        group.Set("org.asamk.Signal.Group", propertyName, blocked);
     }
 
     @Override
@@ -353,17 +416,38 @@ public class DbusManagerImpl implements Manager {
         signal.sendSyncRequest();
     }
 
+    @Override
+    public void addReceiveHandler(final ReceiveMessageHandler handler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeReceiveHandler(final ReceiveMessageHandler handler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isReceiving() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void receiveMessages(final ReceiveMessageHandler handler) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void receiveMessages(
-            final long timeout,
-            final TimeUnit unit,
-            final boolean returnOnTimeout,
-            final boolean ignoreAttachments,
-            final ReceiveMessageHandler handler
+            final long timeout, final TimeUnit unit, final ReceiveMessageHandler handler
     ) throws IOException {
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public void setIgnoreAttachments(final boolean ignoreAttachments) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public boolean hasCaughtUpWithOldMessages() {
         throw new UnsupportedOperationException();
@@ -396,19 +480,41 @@ public class DbusManagerImpl implements Manager {
 
     @Override
     public Group getGroup(final GroupId groupId) {
-        final var id = groupId.serialize();
-        return new Group(groupId,
-                signal.getGroupName(id),
-                null,
-                null,
-                signal.getGroupMembers(id).stream().map(m -> new RecipientAddress(null, m)).collect(Collectors.toSet()),
-                Set.of(),
-                Set.of(),
-                Set.of(),
-                signal.isGroupBlocked(id),
-                0,
-                false,
-                signal.isMember(id));
+        final var groupPath = signal.getGroup(groupId.serialize());
+        return getGroup(groupPath);
+    }
+
+    @SuppressWarnings("unchecked")
+    private Group getGroup(final DBusPath groupPath) {
+        final var group = getRemoteObject(groupPath, Signal.Group.class).GetAll("org.asamk.Signal.Group");
+        final var id = (byte[]) group.get("Id").getValue();
+        try {
+            return new Group(GroupId.unknownVersion(id),
+                    (String) group.get("Name").getValue(),
+                    (String) group.get("Description").getValue(),
+                    GroupInviteLinkUrl.fromUri((String) group.get("GroupInviteLink").getValue()),
+                    ((List<String>) group.get("Members").getValue()).stream()
+                            .map(m -> new RecipientAddress(null, m))
+                            .collect(Collectors.toSet()),
+                    ((List<String>) group.get("PendingMembers").getValue()).stream()
+                            .map(m -> new RecipientAddress(null, m))
+                            .collect(Collectors.toSet()),
+                    ((List<String>) group.get("RequestingMembers").getValue()).stream()
+                            .map(m -> new RecipientAddress(null, m))
+                            .collect(Collectors.toSet()),
+                    ((List<String>) group.get("Admins").getValue()).stream()
+                            .map(m -> new RecipientAddress(null, m))
+                            .collect(Collectors.toSet()),
+                    (boolean) group.get("IsBlocked").getValue(),
+                    (int) group.get("MessageExpirationTimer").getValue(),
+                    GroupPermission.valueOf((String) group.get("PermissionAddMember").getValue()),
+                    GroupPermission.valueOf((String) group.get("PermissionEditDetails").getValue()),
+                    GroupPermission.valueOf((String) group.get("PermissionSendMessage").getValue()),
+                    (boolean) group.get("IsMember").getValue(),
+                    (boolean) group.get("IsAdmin").getValue());
+        } catch (GroupInviteLinkUrl.InvalidGroupLinkException | GroupInviteLinkUrl.UnknownGroupLinkVersionException e) {
+            throw new AssertionError(e);
+        }
     }
 
     @Override
@@ -445,13 +551,6 @@ public class DbusManagerImpl implements Manager {
         throw new UnsupportedOperationException();
     }
 
-    @Override
-    public String computeSafetyNumber(
-            final SignalServiceAddress theirAddress, final IdentityKey theirIdentityKey
-    ) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public SignalServiceAddress resolveSignalServiceAddress(final SignalServiceAddress address) {
         return address;
@@ -494,4 +593,12 @@ public class DbusManagerImpl implements Manager {
     private String emptyIfNull(final String string) {
         return string == null ? "" : string;
     }
+
+    private <T extends DBusInterface> T getRemoteObject(final DBusPath devicePath, final Class<T> type) {
+        try {
+            return connection.getRemoteObject(DbusConfig.getBusname(), devicePath.getPath(), type);
+        } catch (DBusException e) {
+            throw new AssertionError(e);
+        }
+    }
 }