mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 02:20:39 +00:00
Dbus identities (#1259)
* Dbus Identities and Trust * Update src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java * PR feedback updates * Documentation and consistent case sensitivity * doc for listIdentities and getIdentity
This commit is contained in:
parent
c62a1e829f
commit
a96c4938b1
3 changed files with 210 additions and 0 deletions
|
@ -416,6 +416,24 @@ Only works if sent from a secondary device.
|
||||||
|
|
||||||
Exceptions: Failure
|
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
|
=== 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:
|
The following methods listen to the group's object path, which can be obtained from the listGroups() method and is constructed as follows:
|
||||||
|
@ -531,6 +549,42 @@ removeDevice() -> <>::
|
||||||
|
|
||||||
Exceptions: Failure
|
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
|
=== Signal.Configuration interface
|
||||||
|
|
||||||
The configuration's object path, which exists only for primary devices, is constructed as follows:
|
The configuration's object path, which exists only for primary devices, is constructed as follows:
|
||||||
|
|
|
@ -138,6 +138,10 @@ public interface Signal extends DBusInterface {
|
||||||
|
|
||||||
DBusPath getDevice(long deviceId);
|
DBusPath getDevice(long deviceId);
|
||||||
|
|
||||||
|
public DBusPath getIdentity(String number);
|
||||||
|
|
||||||
|
public List<StructIdentity> listIdentities();
|
||||||
|
|
||||||
List<StructDevice> listDevices() throws Error.Failure;
|
List<StructDevice> listDevices() throws Error.Failure;
|
||||||
|
|
||||||
DBusPath getThisDevice();
|
DBusPath getThisDevice();
|
||||||
|
@ -551,6 +555,50 @@ public interface Signal extends DBusInterface {
|
||||||
void enableLink(boolean requiresApproval) throws Error.Failure;
|
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 {
|
interface Error {
|
||||||
|
|
||||||
class AttachmentInvalid extends DBusExecutionException {
|
class AttachmentInvalid extends DBusExecutionException {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
||||||
import org.asamk.signal.manager.api.UpdateGroup;
|
import org.asamk.signal.manager.api.UpdateGroup;
|
||||||
import org.asamk.signal.manager.api.UpdateProfile;
|
import org.asamk.signal.manager.api.UpdateProfile;
|
||||||
import org.asamk.signal.manager.api.UserStatus;
|
import org.asamk.signal.manager.api.UserStatus;
|
||||||
|
import org.asamk.signal.manager.api.IdentityVerificationCode;
|
||||||
import org.asamk.signal.util.SendMessageResultUtils;
|
import org.asamk.signal.util.SendMessageResultUtils;
|
||||||
import org.freedesktop.dbus.DBusPath;
|
import org.freedesktop.dbus.DBusPath;
|
||||||
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
||||||
|
@ -55,6 +56,7 @@ import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.asamk.signal.dbus.DbusUtils.makeValidObjectPathElement;
|
import static org.asamk.signal.dbus.DbusUtils.makeValidObjectPathElement;
|
||||||
|
|
||||||
|
@ -68,6 +70,7 @@ public class DbusSignalImpl implements Signal {
|
||||||
private DBusPath thisDevice;
|
private DBusPath thisDevice;
|
||||||
private final List<StructDevice> devices = new ArrayList<>();
|
private final List<StructDevice> devices = new ArrayList<>();
|
||||||
private final List<StructGroup> groups = new ArrayList<>();
|
private final List<StructGroup> groups = new ArrayList<>();
|
||||||
|
private final List<StructIdentity> identities = new ArrayList<>();
|
||||||
private DbusReceiveMessageHandler dbusMessageHandler;
|
private DbusReceiveMessageHandler dbusMessageHandler;
|
||||||
private int subscriberCount;
|
private int subscriberCount;
|
||||||
|
|
||||||
|
@ -100,6 +103,7 @@ public class DbusSignalImpl implements Signal {
|
||||||
updateDevices();
|
updateDevices();
|
||||||
updateGroups();
|
updateGroups();
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
|
updateIdentities();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -114,6 +118,7 @@ public class DbusSignalImpl implements Signal {
|
||||||
unExportDevices();
|
unExportDevices();
|
||||||
unExportGroups();
|
unExportGroups();
|
||||||
unExportConfiguration();
|
unExportConfiguration();
|
||||||
|
unExportIdentities();
|
||||||
connection.unExportObject(this.objectPath);
|
connection.unExportObject(this.objectPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,6 +1034,109 @@ public class DbusSignalImpl implements Signal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
public class DbusSignalDeviceImpl extends DbusProperties implements Signal.Device {
|
||||||
|
|
||||||
private final org.asamk.signal.manager.api.Device device;
|
private final org.asamk.signal.manager.api.Device device;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue