Exceptions: Failure
+==== Identity related methods
+
+listIdentities() -> identities<a(oss)>::
+* identities : Array of structs (objectPath, id, name)
+** objectPath : DBusPath representing the identity object path
+** uuid : Internal uuid of the identity
+** number : Phone number of the identity (or uuid if not known)
+
+Lists all know identities
+
+getIdentity(Number<s>) -> identityPath<o>::
+* Number : Phone number
+* identityPath : DBusPath object for the identity
+
+Gets the identity Dbus path for a given phone number
+
+Exceptions: Failure
+
=== Signal.Group interface
The following methods listen to the group's object path, which can be obtained from the listGroups() method and is constructed as follows:
Exceptions: Failure
+=== Signal.Identity interface
+
+The following methods listen to the Identities object path, which is constructed as follows:
+
+<ACCOUNT_PATH> + "/Identities/" + identity
+
+identity : Either the phone number of a contact with underscore (_) replacing plus (+) , or if not known its uuid
+
+Identities have the following (case-sensitive) properties:
+
+* Number<s> (read-only) : Phone number of the contact
+* Uuid<x> (read-only) : Internal uuid representing the contact
+* Fingerprint<x> (read-only) : Byte array representing the fingerprint
+* SafetyNumber<s> (read-only) : String representation of the safety number used to verify trust
+* TrustLevel<s> (read-only) : Current trust level (UNSTRUSTED, TRUSTED_UNVERIFIED, TRUSTED_VERIFIED)
+* AddedDate<x> (read-only) : Long representing the number of milliseconds since the Unix epoch
+* ScannableSafetyNumber<x> (read-only) : Byte array representation of the safety number
+
+To get a property, use (replacing `--session` with `--system` if needed):
+`dbus-send --session --dest=org.asamk.Signal --print-reply $OBJECT_PATH org.freedesktop.DBus.Properties.Get string:org.asamk.Signal.Identity string:$PROPERTY_NAME`
+
+To get all properties, use:
+`dbus-send --session --dest=org.asamk.Signal --print-reply $OBJECT_PATH org.freedesktop.DBus.Properties.GetAll string:org.asamk.Signal.Identity`
+
+trust() -> <>::
+
+Establish trust with the given identity. TrustLevel will become TRUSTED_UNVERFIED
+
+Exceptions: Failure
+
+trustVerified(SafetyNumber<s>) -> <>::
+
+Establish trust with the given identity using their safety number. TrustLevel will become TRUSTED_VERIFIED
+
+Exceptions: Failure
+
=== Signal.Configuration interface
The configuration's object path, which exists only for primary devices, is constructed as follows:
DBusPath getDevice(long deviceId);
+ public DBusPath getIdentity(String number);
+
+ public List<StructIdentity> listIdentities();
+
List<StructDevice> listDevices() throws Error.Failure;
DBusPath getThisDevice();
void enableLink(boolean requiresApproval) throws Error.Failure;
}
+ class StructIdentity extends Struct {
+
+ @Position(0)
+ DBusPath objectPath;
+
+ @Position(1)
+ String uuid;
+
+ @Position(2)
+ String name;
+
+ public StructIdentity(final DBusPath objectPath, final String uuid, final String name) {
+ this.objectPath = objectPath;
+ this.uuid = uuid;
+ this.name = name;
+ }
+
+ public DBusPath getObjectPath() {
+ return objectPath;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ @DBusProperty(name = "Number", type = String.class, access = DBusProperty.Access.READ)
+ @DBusProperty(name = "Uuid", type = String.class, access = DBusProperty.Access.READ)
+ @DBusProperty(name = "Fingerprint", type = Byte[].class, access = DBusProperty.Access.READ)
+ @DBusProperty(name = "SafetyNumber", type = String.class, access = DBusProperty.Access.READ)
+ @DBusProperty(name = "TrustLevel", type = String.class, access = DBusProperty.Access.READ)
+ @DBusProperty(name = "AddedDate", type = Integer.class, access = DBusProperty.Access.READ)
+ @DBusProperty(name = "ScannableSafetyNumber", type = Byte[].class, access = DBusProperty.Access.READ)
+ interface Identity extends DBusInterface, Properties {
+
+ void trust() throws Error.Failure;
+
+ void trustVerified(String safetyNumber) throws Error.Failure;
+ }
+
interface Error {
class AttachmentInvalid extends DBusExecutionException {
import org.asamk.signal.manager.api.UpdateGroup;
import org.asamk.signal.manager.api.UpdateProfile;
import org.asamk.signal.manager.api.UserStatus;
+import org.asamk.signal.manager.api.IdentityVerificationCode;
import org.asamk.signal.util.SendMessageResultUtils;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.UUID;
import static org.asamk.signal.dbus.DbusUtils.makeValidObjectPathElement;
private DBusPath thisDevice;
private final List<StructDevice> devices = new ArrayList<>();
private final List<StructGroup> groups = new ArrayList<>();
+ private final List<StructIdentity> identities = new ArrayList<>();
private DbusReceiveMessageHandler dbusMessageHandler;
private int subscriberCount;
updateDevices();
updateGroups();
updateConfiguration();
+ updateIdentities();
}
public void close() {
unExportDevices();
unExportGroups();
unExportConfiguration();
+ unExportIdentities();
connection.unExportObject(this.objectPath);
}
}
}
+ private void updateIdentities() {
+ List<org.asamk.signal.manager.api.Identity> identities;
+ identities = m.getIdentities();
+
+ unExportIdentities();
+
+ identities.forEach(i -> {
+ final var object = new DbusSignalIdentityImpl(i);
+ exportObject(object);
+ this.identities.add(new StructIdentity(new DBusPath(object.getObjectPath()),
+ emptyIfNull(i.recipient().getIdentifier()),
+ i.recipient().getLegacyIdentifier()));
+ });
+ }
+
+ private static String getIdentityObjectPath(String basePath, String id) {
+ return basePath + "/Identities/" + makeValidObjectPathElement(id);
+ }
+
+ private void unExportIdentities() {
+ this.identities.stream().map(StructIdentity::getObjectPath).map(DBusPath::getPath).forEach(connection::unExportObject);
+ this.identities.clear();
+ }
+
+ @Override
+ public DBusPath getIdentity(String number) throws Error.Failure {
+
+ final var found = identities.stream()
+ .filter(identity -> identity.getName().equals(number))
+ .findFirst();
+
+ if (found.isEmpty()) {
+ throw new Error.Failure("Identity for " + number + " unkown");
+ }
+ return found.get().getObjectPath();
+ }
+
+ @Override
+ public List<StructIdentity> listIdentities() {
+ updateIdentities();
+ return this.identities;
+ }
+
+ public class DbusSignalIdentityImpl extends DbusProperties implements Signal.Identity {
+
+ private final org.asamk.signal.manager.api.Identity identity;
+
+ public DbusSignalIdentityImpl(final org.asamk.signal.manager.api.Identity identity) {
+ this.identity=identity;
+ super.addPropertiesHandler(new DbusInterfacePropertiesHandler("org.asamk.Signal.Identity",
+ List.of(new DbusProperty<>("Number", () -> identity.recipient().number().orElse("")),
+ new DbusProperty<>("Uuid", () -> identity.recipient().uuid().map(UUID::toString).orElse("")),
+ new DbusProperty<>("Fingerprint", () -> identity.getFingerprint()),
+ new DbusProperty<>("SafetyNumber", identity::safetyNumber),
+ new DbusProperty<>("ScannableSafetyNumber", identity::scannableSafetyNumber),
+ new DbusProperty<>("TrustLevel", identity::trustLevel),
+ new DbusProperty<>("AddedDate", identity::dateAddedTimestamp)
+ )));
+ }
+
+ @Override
+ public String getObjectPath() {
+ return getIdentityObjectPath(objectPath, identity.recipient().getLegacyIdentifier());
+ }
+
+ @Override
+ public void trust() throws Error.Failure {
+ var recipient=RecipientIdentifier.Single.fromAddress(identity.recipient());
+ try {
+ m.trustIdentityAllKeys(recipient);
+ } catch (UnregisteredRecipientException e) {
+ throw new Error.Failure("The user " + e.getSender().getIdentifier() + " is not registered.");
+ }
+ };
+
+ @Override
+ public void trustVerified(String safetyNumber) throws Error.Failure {
+ var recipient = RecipientIdentifier.Single.fromAddress(identity.recipient());
+
+ if (safetyNumber == null) {
+ throw new Error.Failure(
+ "You need to specify a fingerprint/safety number");
+ }
+ final IdentityVerificationCode verificationCode;
+ try {
+ verificationCode = IdentityVerificationCode.parse(safetyNumber);
+ } catch (Exception e) {
+ throw new Error.Failure(
+ "Safety number has invalid format, either specify the old hex fingerprint or the new safety number");
+ }
+
+ try {
+ final var res = m.trustIdentityVerified(recipient, verificationCode);
+ if (!res) {
+ throw new Error.Failure(
+ "Failed to set the trust for this number, make sure the number and the fingerprint/safety number are correct.");
+ }
+ } catch (UnregisteredRecipientException e) {
+ throw new Error.Failure("The user " + e.getSender().getIdentifier() + " is not registered.");
+ }
+ }
+ }
+
public class DbusSignalDeviceImpl extends DbusProperties implements Signal.Device {
private final org.asamk.signal.manager.api.Device device;