Decrypts a previously-received m.room.encrypted event for scope --
the same value passed to encryptEvent, since decryption needs it for
the same reason: the native call this delegates to requires an explicit
scope to look up the right group session, and reading one out of the
unauthenticated, not-yet-decrypted event JSON would mean trusting
attacker-influenced input for a security-relevant lookup.
A deliberate break from the M1a-frozen decryptEvent(rawEvent): that
shape cannot express a required scope without smuggling it into the
unknown (e.g. { scope, event }), which compiles but hides a required
argument where the type system cannot see it and bypasses the branded
CryptoScopeId that exists precisely so a caller cannot pass a bare
string -- trading a compile error for a runtime one in a cryptographic
API. getDeviceIdentityKeys is the counter-case: its parameters stayed
because keeping them cost nothing. Here, keeping the frozen shape would
have cost the caller the type system.
rawEvent is the m.room.encrypted event as received, verbatim --
JSON-stringified as-is before crossing to native.
This library decrypts events. It does not authenticate their
senders -- spec section 7.1. The returned envelope's sender and
algorithm are read from the fields the homeserver delivered, not
independently verified, and are unauthenticated transport metadata.
That was scoped to "until cross-signing lands, which is M4" twice, and
cross-signing has now landed without changing it: these two fields are
never re-derived, whatever this library knows about the sender. What
cross-signing adds is the separate value below, not a promotion of these
two. Verifying the sending device does not change it either: see
EventEnvelope.sender and
EventEnvelope.algorithm for what that means and why. A product
that reads the sender of a successfully decrypted event as the
cryptographic sender has assumed something this milestone does not
provide, and that assumption is the shape impersonation takes.
What the returned envelope now adds is the size of that assumption.senderVerification carries what this library knew about the sender at
the moment it decrypted -- see SenderVerification. It does not
turn sender into an authenticated value. It can read 'verified'
through this surface from this release, which it could not before: the
last missing step was the bridged call that lets a product create this
account's own cross-signing identity, and that call is
createCrossSigningIdentity. This named
bootstrapCrossSigning, which did the creating until the two were
split and now only publishes. Reaching the value is still a chain rather
than a setting, and the chain is the seven steps
SenderVerification sets out; what changed is that every one of
them can now be driven from TypeScript. What the value can already do
without any of that is tell three different things
apart: an ordinary unsigned device, a device its owner cross-signed whose
owner you have not verified ('unverified_identity', which this release
does produce, from any peer whose client has cross-signing set up), and
an event whose claimed sender is not the owner of the session that
encrypted it. The last of those is an impersonation signal a product
should react to. It is a snapshot taken at decryption time, not a live
value; see the field.
senderTrustRequirement is the decision this call will not make for
you, and it is new to this surface: what a sender's device must satisfy
before the plaintext is handed over. The default 'any' is what every
caller before the parameter existed got. The two tightened tiers make
'sender_not_trusted' reachable for the first time -- its own kind
rather than a fold into 'unknown_device', because the two want opposite
things done about them: 'sender_not_trusted' is a policy gap the user
fixes by verifying the device (or the product, by relaxing the
requirement), while 'unknown_device' means the event's provenance is
broken and nothing fixes it. Read SenderTrustRequirement before
choosing: local trust is absent from every tier, so a product whose
users verify devices without cross-signing identities should stay on the
default and gate on the returned envelope's senderVerification
instead.
Decrypts a previously-received
m.room.encryptedevent forscope-- the same value passed toencryptEvent, since decryption needs it for the same reason: the native call this delegates to requires an explicit scope to look up the right group session, and reading one out of the unauthenticated, not-yet-decrypted event JSON would mean trusting attacker-influenced input for a security-relevant lookup.A deliberate break from the M1a-frozen
decryptEvent(rawEvent): that shape cannot express a required scope without smuggling it into theunknown(e.g.{ scope, event }), which compiles but hides a required argument where the type system cannot see it and bypasses the brandedCryptoScopeIdthat exists precisely so a caller cannot pass a bare string -- trading a compile error for a runtime one in a cryptographic API.getDeviceIdentityKeysis the counter-case: its parameters stayed because keeping them cost nothing. Here, keeping the frozen shape would have cost the caller the type system.rawEventis them.room.encryptedevent as received, verbatim -- JSON-stringified as-is before crossing to native.This library decrypts events. It does not authenticate their senders -- spec section 7.1. The returned envelope's
senderandalgorithmare read from the fields the homeserver delivered, not independently verified, and are unauthenticated transport metadata. That was scoped to "until cross-signing lands, which is M4" twice, and cross-signing has now landed without changing it: these two fields are never re-derived, whatever this library knows about the sender. What cross-signing adds is the separate value below, not a promotion of these two. Verifying the sending device does not change it either: see EventEnvelope.sender and EventEnvelope.algorithm for what that means and why. A product that reads the sender of a successfully decrypted event as the cryptographic sender has assumed something this milestone does not provide, and that assumption is the shape impersonation takes.What the returned envelope now adds is the size of that assumption.
senderVerificationcarries what this library knew about the sender at the moment it decrypted -- see SenderVerification. It does not turnsenderinto an authenticated value. It can read'verified'through this surface from this release, which it could not before: the last missing step was the bridged call that lets a product create this account's own cross-signing identity, and that call is createCrossSigningIdentity. This named bootstrapCrossSigning, which did the creating until the two were split and now only publishes. Reaching the value is still a chain rather than a setting, and the chain is the seven steps SenderVerification sets out; what changed is that every one of them can now be driven from TypeScript. What the value can already do without any of that is tell three different things apart: an ordinary unsigned device, a device its owner cross-signed whose owner you have not verified ('unverified_identity', which this release does produce, from any peer whose client has cross-signing set up), and an event whose claimed sender is not the owner of the session that encrypted it. The last of those is an impersonation signal a product should react to. It is a snapshot taken at decryption time, not a live value; see the field.senderTrustRequirementis the decision this call will not make for you, and it is new to this surface: what a sender's device must satisfy before the plaintext is handed over. The default'any'is what every caller before the parameter existed got. The two tightened tiers make'sender_not_trusted'reachable for the first time -- its own kind rather than a fold into'unknown_device', because the two want opposite things done about them:'sender_not_trusted'is a policy gap the user fixes by verifying the device (or the product, by relaxing the requirement), while'unknown_device'means the event's provenance is broken and nothing fixes it. Read SenderTrustRequirement before choosing: local trust is absent from every tier, so a product whose users verify devices without cross-signing identities should stay on the default and gate on the returned envelope'ssenderVerificationinstead.