Struct matrix_sdk::encryption::identities::Device

source ·
pub struct Device { /* private fields */ }
Available on crate feature e2e-encryption only.
Expand description

A device represents a E2EE capable client or device of an user.

A Device is backed by device keys that are uploaded to the server.

The device keys for our own device will be automatically uploaded by the SDK and the private parts of our device keys never leave this device.

Device keys consist of an Ed25519 keypair and a Curve25519 keypair. Only the public parts of those keypairs will be uploaded to the server.

                ┌──────────────────────────────────┐
                │              Device              │
                ├──────────────────────────────────┤
                │            Device Keys           │
                ├────────────────┬─────────────────┤
                │   Ed25519 Key  │  Curve25519 Key │
                └────────────────┴─────────────────┘

The Ed25519 key will be used to uniquely identify the Device while the Curve25519 key is used to establish 1-to-1 encrypted communication channels between two devices.

Implementations§

source§

impl Device

source

pub async fn request_verification(&self) -> Result<VerificationRequest>

Request an interactive verification with this Device.

Returns a VerificationRequest object that can be used to control the verification flow.

The default methods that are supported are m.sas.v1 and m.qr_code.show.v1, if this isn’t desirable the request_verification_with_methods() method can be used to override this. m.qr_code.show.v1 is only available if the qrcode feature is enabled, which it is by default.

§Examples
let device =
    client.encryption().get_device(alice, device_id!("DEVICEID")).await?;

if let Some(device) = device {
    let verification = device.request_verification().await?;
}
source

pub async fn request_verification_with_methods( &self, methods: Vec<VerificationMethod>, ) -> Result<VerificationRequest>

Request an interactive verification with this Device.

Returns a VerificationRequest object that can be used to control the verification flow.

§Arguments
  • methods - The verification methods that we want to support. Must be non-empty.
§Panics

This method will panic if methods is empty.

§Examples
let device =
    client.encryption().get_device(alice, device_id!("DEVICEID")).await?;

// We don't want to support showing a QR code, we only support SAS
// verification
let methods = vec![VerificationMethod::SasV1];

if let Some(device) = device {
    let verification =
        device.request_verification_with_methods(methods).await?;
}
source

pub async fn start_verification(&self) -> Result<SasVerification>

👎Deprecated since 0.4.0: directly starting a verification is deprecated in the spec. Users should instead use request_verification()

Start an interactive verification with this Device

Returns a SasVerification object that represents the interactive verification flow.

This method has been deprecated in the spec and the request_verification() method should be used instead.

§Examples
let device =
    client.encryption().get_device(alice, device_id!("DEVICEID")).await?;

if let Some(device) = device {
    let verification = device.start_verification().await?;
}
source

pub async fn verify(&self) -> Result<(), ManualVerifyError>

Manually verify this device.

This method will attempt to sign the device using our private cross signing key.

This method will always fail if the device belongs to someone else, we can only sign our own devices.

It can also fail if we don’t have the private part of our self-signing key.

The state of our private cross signing keys can be inspected using the Encryption::cross_signing_status() method.

§Problems of manual verification

Manual verification may be more convenient to use, i.e. both devices need to be online and available to interactively verify each other. Despite the convenience, interactive verifications should be generally preferred. Manually verifying a device won’t notify the other device, the one being verified, that they should also verify us. This means that device A will consider device B to be verified, but not the other way around.

§Examples
let device =
    client.encryption().get_device(alice, device_id!("DEVICEID")).await?;

if let Some(device) = device {
    device.verify().await?;
}
source

pub fn is_verified(&self) -> bool

Is the device considered to be verified.

A device is considered to be verified, either if it’s locally marked as such, or if it’s signed by the appropriate cross signing key. Our own device, is always implicitly verified.

§Local trust

Local trust can be established using the Device::set_local_trust() method or it will be established if we interactively verify the device using Device::request_verification().

Note: The concept of local trust is largely deprecated because it can’t be shared with other devices. Every device needs to verify all the other devices it communicates to. Because this becomes quickly unsustainable verification has migrated to cross signing verification.

§Cross signing verification

Cross signing verification uses signatures over devices and user identities to check if a device is considered to be verified. The signatures can be uploaded to the homeserver, this allows us to share the verification state with other devices. Devices only need to verify a user identity, if the user identity has verified and signed the device we can consider the device to be verified as well.

Devices are usually cross signing verified using interactive verification, which can be started using the Device::request_verification() method.

A Device can also be manually signed using the Device::verify() method, this works only for devices belonging to our own user.

Do note that the device that is being manually signed will not trust our own user identity like it would if we interactively verify the device. Such a device can mark our own user as verified using the UserIdentity::verify() method.

§Verification of devices belonging to our own user.

If the device belongs to our own user, the device will be considered to be verified if:

  • The device has been signed by our self-signing key
  • Our own user identity is considered to be verified

In other words we need to find a valid signature chain from our user identity to the device:

         ┌─────────────────────────────────────┐    ┌─────────────┐
         │           Own User Identity         │    │   Device    │
         ├──────────────────┬──────────────────┤───►├─────────────┤
         │    Master Key    │ Self-signing Key │    │ Device Keys │
         └──────────────────┴──────────────────┘    └─────────────┘
§Verification of devices belonging to other users.

If the device belongs to some other user it will be considered to be verified if:

  • The device has been signed by the user’s self-signing key
  • The user’s master-signing key has been signed by our own user-signing key, i.e. our own identity trusts the other users identity.
  • Our own user identity is considered to be verified
            ┌─────────────────────────────────────┐
            │           Own User Identity         │
            ├──────────────────┬──────────────────┤─────┐
            │    Master Key    │ User-signing Key │     │
            └──────────────────┴──────────────────┘     │
    ┌───────────────────────────────────────────────────┘
    │
    │       ┌─────────────────────────────────────┐    ┌─────────────┐
    │       │             User Identity           │    │   Device    │
    └──────►├──────────────────┬──────────────────┤───►│─────────────│
            │    Master Key    │ Self-signing Key │    │ Device Keys │
            └──────────────────┴──────────────────┘    └─────────────┘
§Examples

Let’s check if a device is verified:

let device =
    client.encryption().get_device(alice, device_id!("DEVICEID")).await?;

if let Some(device) = device {
    if device.is_verified() {
        println!(
            "Device {} of user {} is verified",
            device.device_id(),
            device.user_id(),
        );
    } else {
        println!(
            "Device {} of user {} is not verified",
            device.device_id(),
            device.user_id(),
        );
    }
}
source

pub fn is_verified_with_cross_signing(&self) -> bool

Is the device considered to be verified with cross-signing.

A device is considered to be verified if it’s signed by the appropriate cross-signing key.

§Cross-signing verification

Cross-signing verification uses signatures over devices and user identities to check if a device is considered to be verified. The signatures can be uploaded to the homeserver, this allows us to share the verification state with other devices. Devices only need to verify a user identity, if the user identity has verified and signed the device we can consider the device to be verified as well.

Devices are usually cross-signing verified using interactive verification, which can be started using the Device::request_verification() method.

A Device can also be manually signed using the Device::verify() method, this works only for devices belonging to our own user.

Do note that the device that is being manually signed will not trust our own user identity like it would if we interactively verify the device. Such a device can mark our own user as verified using the UserIdentity::verify() method.

§Verification of devices belonging to our own user.

If the device belongs to our own user, the device will be considered to be verified if:

  • The device has been signed by our self-signing key
  • Our own user identity is considered to be verified

In other words we need to find a valid signature chain from our user identity to the device:

         ┌─────────────────────────────────────┐    ┌─────────────┐
         │           Own User Identity         │    │   Device    │
         ├──────────────────┬──────────────────┤───►├─────────────┤
         │    Master Key    │ Self-signing Key │    │ Device Keys │
         └──────────────────┴──────────────────┘    └─────────────┘
§Verification of devices belonging to other users.

If the device belongs to some other user it will be considered to be verified if:

  • The device has been signed by the user’s self-signing key
  • The user’s master-signing key has been signed by our own user-signing key, i.e. our own identity trusts the other users identity.
  • Our own user identity is considered to be verified
            ┌─────────────────────────────────────┐
            │           Own User Identity         │
            ├──────────────────┬──────────────────┤─────┐
            │    Master Key    │ User-signing Key │     │
            └──────────────────┴──────────────────┘     │
    ┌───────────────────────────────────────────────────┘
    │
    │       ┌─────────────────────────────────────┐    ┌─────────────┐
    │       │             User Identity           │    │   Device    │
    └──────►├──────────────────┬──────────────────┤───►│─────────────│
            │    Master Key    │ Self-signing Key │    │ Device Keys │
            └──────────────────┴──────────────────┘    └─────────────┘
§Examples

Let’s check if a device is verified:

let device =
    client.encryption().get_device(alice, device_id!("DEVICEID")).await?;

if let Some(device) = device {
    if device.is_verified_with_cross_signing() {
        println!(
            "Device {} of user {} is verified with cross-signing",
            device.device_id(),
            device.user_id()
        );
    } else {
        println!(
            "Device {} of user {} is not verified with cross-signing",
            device.device_id(),
            device.user_id()
        );
    }
}
source

pub async fn set_local_trust( &self, trust_state: LocalTrust, ) -> Result<(), CryptoStoreError>

Set the local trust state of the device to the given state.

This won’t affect any cross signing verification state, this only sets a flag marking to have the given trust state.

§Arguments
  • trust_state - The new trust state that should be set for the device.
source

pub fn is_cross_signed_by_owner(&self) -> bool

Is the device cross-signed by its own user.

Methods from Deref<Target = DeviceData>§

source

pub fn user_id(&self) -> &UserId

The user id of the device owner.

source

pub fn device_id(&self) -> &DeviceId

The unique ID of the device.

source

pub fn display_name(&self) -> Option<&str>

Get the human readable name of the device.

source

pub fn get_key(&self, algorithm: DeviceKeyAlgorithm) -> Option<&DeviceKey>

Get the key of the given key algorithm belonging to this device.

source

pub fn curve25519_key(&self) -> Option<Curve25519PublicKey>

Get the Curve25519 key of the given device.

source

pub fn ed25519_key(&self) -> Option<Ed25519PublicKey>

Get the Ed25519 key of the given device.

source

pub fn keys( &self, ) -> &BTreeMap<OwnedKeyId<DeviceKeyAlgorithm, DeviceId>, DeviceKey>

Get a map containing all the device keys.

source

pub fn signatures(&self) -> &Signatures

Get a map containing all the device signatures.

source

pub fn local_trust_state(&self) -> LocalTrust

Get the trust state of the device.

source

pub fn is_locally_trusted(&self) -> bool

Is the device locally marked as trusted.

source

pub fn is_blacklisted(&self) -> bool

Is the device locally marked as blacklisted.

Blacklisted devices won’t receive any group sessions.

source

pub fn was_withheld_code_sent(&self) -> bool

Returns true if the m.no_olm withheld code was already sent to this device.

source

pub fn algorithms(&self) -> &[EventEncryptionAlgorithm]

Get the list of algorithms this device supports.

source

pub fn supports_olm(&self) -> bool

Does this device support any of our known Olm encryption algorithms.

source

pub fn olm_session_config(&self) -> SessionConfig

Get the optimal SessionConfig for this device.

source

pub fn is_deleted(&self) -> bool

Is the device deleted.

source

pub fn as_device_keys(&self) -> &DeviceKeys

Return the device keys

source

pub fn first_time_seen_ts(&self) -> MilliSecondsSinceUnixEpoch

Get the local timestamp of when this device was first persisted, in milliseconds since epoch (client local time).

Trait Implementations§

source§

impl Clone for Device

source§

fn clone(&self) -> Device

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Device

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Deref for Device

§

type Target = DeviceData

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.

Auto Trait Implementations§

§

impl Freeze for Device

§

impl !RefUnwindSafe for Device

§

impl Send for Device

§

impl Sync for Device

§

impl Unpin for Device

§

impl !UnwindSafe for Device

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
§

impl<T> CompatExt for T

§

fn compat(self) -> Compat<T>

Applies the [Compat] adapter by value. Read more
§

fn compat_ref(&self) -> Compat<&T>

Applies the [Compat] adapter by shared reference. Read more
§

fn compat_mut(&mut self) -> Compat<&mut T>

Applies the [Compat] adapter by mutable reference. Read more
source§

impl<T> DynClone for T
where T: Clone,

source§

fn __clone_box(&self, _: Private) -> *mut ()

source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> FromRef<T> for T
where T: Clone,

source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
source§

impl<T> FutureExt for T

source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
source§

impl<T, UT> HandleAlloc<UT> for T
where T: Send + Sync,

source§

fn new_handle(value: Arc<T>) -> Handle

Create a new handle for an Arc value Read more
source§

fn clone_handle(handle: Handle) -> Handle

Clone a handle Read more
source§

fn consume_handle(handle: Handle) -> Arc<T>

Consume a handle, getting back the initial Arc<>
source§

fn get_arc(handle: Handle) -> Arc<Self>

Get a clone of the Arc<> using a “borrowed” handle. Read more
source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

source§

const WITNESS: W = W::MAKE

A constant of the type witness
source§

impl<T> Identity for T
where T: ?Sized,

§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
source§

impl<T> Any for T
where T: Any,

source§

impl<T> AsyncTraitDeps for T

source§

impl<T> CloneAny for T
where T: Any + Clone,

source§

impl<T> CloneAnySend for T
where T: Any + Send + Clone,

source§

impl<T> CloneAnySendSync for T
where T: Any + Send + Sync + Clone,

source§

impl<T> CloneAnySync for T
where T: Any + Sync + Clone,

source§

impl<T> SendOutsideWasm for T
where T: Send,

source§

impl<T> SyncOutsideWasm for T
where T: Sync,