Matthew Hodgson 3 weeks ago committed by GitHub
commit 321c57cd98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,483 @@
# MSC3489 - m.beacon: Sharing streams of location data with history
## Problem
A common communication feature is sharing live location data with other users.
Use cases include helping users find each other and asset tracking. Matrix
doesn't currently provide a way of doing this.
Therefore, we'd like to provide a way for users to efficiently advertise the
time-limited real-time location of themselves or arbitrary assets to other
users in a room - while by default preserving the history of the location
data in the room by storing it as relational timeline events.
The rationale for persisting location data is to support the use cases of:
* Publishing things like Strava-style exercise data
* Bridging to things like ADS-B sources for sharing plane flight path data.
* Logistics use cases where you want to track where your fleet of
vehicles/ships has been, or the packages within them
* Supporting scenarios where you're trying to rendezvous with someone/something
which will be aided by seeing their historical whereabouts (e.g.
search-and-rescue operations; enhanced Find-my-iPhone style use cases).
For purely ephemeral location sharing, see
[MSC3672](https://github.com/matrix-org/matrix-spec-proposals/pull/3672).
## Proposal
This MSC adds the ability to publish real-time location beacons to Matrix by
building on
[MSC3488](https://github.com/matrix-org/matrix-spec-proposals/pull/3488),
which allows sharing of single static locations via the `m.location` event
type.
We introduce two types of event to describe beacons:
* **`m.beacon_info`**: a single state event containing metadata about this
beacon (e.g. how long it will remain live).
* **`m.beacon`**: multiple message events containing the actual locations at
various times. All of the `m.beacon` events refer to the original
`m.beacon_info`.
### `m.beacon_info` - "I am going to share live location"
An example `m.beacon_info` event is:
```json5
{
"type": "m.beacon_info",
"state_key": "@matthew:matrix.org",
"content": {
"description": "The Matthew Tracker",
"live": true,
"m.ts": 1436829458432,
"timeout": 86400000,
"m.asset": { "type": "m.self" }
}
}
```
`description` is the same as an `m.location` description
([MSC3488](https://github.com/matrix-org/matrix-spec-proposals/pull/3488)).
`live` should be true when a user starts sharing location.
`m.ts` is the time when location sharing started, in milliseconds since the
epoch.
`timeout` is the length of time in milliseconds that the location will be live.
So the location will stop being shared at `m.ts` + `timeout` milliseconds since
the epoch.
`m.asset` identifies the type of asset being tracked as per
[MSC3488](https://github.com/matrix-org/matrix-spec-proposals/pull/3488).
#### `state_key` of `m.beacon_info`
The `state_key` of the `m.beacon_info` identifies the beacon. It must start
with the mxid of the sender, and if it contains more characters, the first
character after the mxid must be underscore, to match
[MSC3757](https://github.com/matrix-org/matrix-spec-proposals/pull/3757) and
[MSC3779](https://github.com/matrix-org/matrix-spec-proposals/pull/3779).
If `state_key` exactly equals the sender's mxid, then the current Matrix spec
prevents anyone else from overwriting the state from this event. Until
`state_key`
[MSC3757](https://github.com/matrix-org/matrix-spec-proposals/pull/3757) (or
some equivalent mechanism) lands, `state_key` will not be allowed to contain
further characters. After it lands, adding underscore and further characters
will allow one user to create multiple beacons.
Obviously, if the `state_key` always equals the sender's mxid, each user can
only share a single beacon in each room at any time. We recommend that clients
work in this mode until
[MSC3757](https://github.com/matrix-org/matrix-spec-proposals/pull/3757) is
available.
To allow multiple beacons per user (e.g. one per device), we use a `state_key`
of mxid plus underscore, and an identifier. For example:
```json5
{
"type": "m.beacon_info",
"state_key": "@matthew:matrix.org_46583241", // inspired by MSC3757
"content": {
"description": "Matthew's other phone",
"live": true,
"m.ts": 1436829458432,
"timeout": 86400000,
"m.asset": { "type": "m.self" }
}
}
```
This style of `state_key` will not work (is not allowed) until
[MSC3757](https://github.com/matrix-org/matrix-spec-proposals/pull/3757) is
available.
### `m.beacon` - "I am here"
The actual location data is sent in `m.beacon` events, which have a reference
relationship to the original `m.beacon_info` event.
`m.beacon` events should be sent at a variable rate which is meaningful for
the use case for the asset being tracked. This rate should not be more
frequent than sending an event every 2 seconds. If the asset is not moving,
the location should still be refreshed on a regular basis to convey that
information - e.g. every 30 seconds.
An example `m.beacon` event is:
```json5
{
"type": "m.beacon",
"sender": "@matthew:matrix.org",
"content": {
"m.relates_to": {
"rel_type": "m.reference",
"event_id": "$beacon_info_event_id"
},
"m.location": {
"uri": "geo:51.5008,0.1247;u=35",
"description": "Arbitrary beacon information"
},
"m.ts": 1636829458432,
}
}
```
`m.relates_to` is a reference relationship
([MSC3267](https://github.com/matrix-org/matrix-spec-proposals/pull/3267)).
The `event_id` is the ID of the `m.beacon_info` event emitted when the user
started this live share.
`m.location` is identical to the `m.location` section of the `m.location` event
type in [MSC3488](https://github.com/matrix-org/matrix-spec-proposals/pull/3488). As such,
it must contain a `uri` field with an RFC5870 `geo:` URI. It can contain an
optional `description` field to provide user-facing updates e.g. the current
address of this location.
`m.ts` is the time in milliseconds since the epoch when the location was
measured.
### Stopping sharing
To stop sharing, the client should emit an additional `m.beacon_info`
event that is identical to the first, except with `live: false`.
The client that initiated a share should stop sharing if:
* the timeout on a live share has expired, or
* the user requested to stop sharing, or
* the user revoked permissions on their device to share location.
For example:
```json5
{
"type": "m.beacon_info",
"state_key": "@matthew:matrix.org_46583241",
"content": {
"description": "Matthew's other phone",
"live": false, // Stop sharing
"m.ts": 1436829458432,
"timeout": 86400000,
"m.asset": { "type": "m.self" }
}
}
```
### Deciding which shared locations are live
A location share is "live" if the sender is currently sharing their location.
Client apps will often want to determine two related but different pieces of
information about the shares in a room:
1. Which location shares are live
2. How to display a single location share event (e.g. in a timeline)
#### Which locations shares are live
To determine who is currently sharing their location in a room, clients should
examine the room state for events of type `m.beacon_info`.
For each `m.beacon_info` event in the room state, it is live if:
* `live` is `true`, and
* `m.ts + timeout < now_ts` where `now_ts` is the current time in milliseconds
since the epoch.
Otherwise it is not live.
#### How to display a single location share event
For clients with timelines, we expect that a map or similar will appear in the
timeline whenever a `m.beacon_info` event with `live: true` is sent, and
related `m.beacon` events will cause that map to update. Stopping sharing
(sending a `m.beacon_info` event with `live: false`) might not create any new
visible item in the timeline.
For a map on a timeline associated with an initial `m.beacon_info`, to
determine whether that map is "live", clients should:
* look in the room state for an `m.beacon_info` event with the same
`state_key`, and
* follow the rules in the previous section ("Which location shares are live").
### Redacting shared locations
Because location information is private, it is vital that people are able to
delete information that they no longer want to reveal, or that was
inadvertently posted to the wrong room.
We expect that clients will provide a single UI element that redacts all events
for a live sharing session. This includes the original `m.beacon_info` event,
all `m.beacon` events related to it, and any additional `m.beacon_info` event
sent to stop sharing.
Redaction should be done in the normal way, using the `redact` API as specified
in section
[7.9 Redactions](https://spec.matrix.org/v1.2/client-server-api/#redactions) of
the Client-Server API. (See also
[MSC2244: Mass redactions](https://github.com/matrix-org/matrix-spec-proposals/pull/2244).)
## Permission to share location
Since the `m.beacon_info` event is a state event, users who wish to share their
live location will need permission to send state events. By default, users with
power level 50 are able to send state events.
To allow all users to send `m.beacon_info` events, the room's power levels
should be set to something like this:
```json5
{
"state_key": "",
"type": "m.room.power_levels",
"content": {
"events": {
"m.beacon_info": 0,
...
},
...
},
...
}
```
This can be done during room creation, or later by sending a new
`m.room.power_levels` state event.
[MSC3779](https://github.com/matrix-org/matrix-spec-proposals/pull/3779) is intended to
make it easier to send this kind of state event, and the `state_key`s in this
proposal are deliberately designed to take advantage of MSC3779 if it is
standardised. If MSC3779 is available, users with permission to send message
events will automatically have permission to share their live location, because
the `state_key` matches the pattern required to be an "owned" state event.
## Alternatives
### Storing location in room state
Initially this MSC considered storing location data in a separate state event
but that had multiple downsides:
* No encryption without
[MSC3414](https://github.com/matrix-org/matrix-spec-proposals/pull/3414).
* Difficult access to historical data, timeline pagination required.
* State resolution thrashing on every location update. By storing a state event
for every location datapoint, we put significant load on servers' state
management implementations. Current implementations may not handle this
well.
Storing the location data as references as opposed to in a state event has
multiple advantages:
* Location data is easily encrypted (no dependency on
[MSC3414](https://github.com/matrix-org/matrix-spec-proposals/pull/3414)).
* Doesn't thrash state resolution by storing new location points every time
they change.
* Paginated history easily accessible through the `relations` endpoint. If
history is not wanted, then one can use data retention policies (e.g.
exploding messages) to ensure it does not accumulate unnecessarily.
* Allows other users to request data from a beacon.
### Sending location data using ephemeral data units (EDUs)
This proposal covers use cases where location data needs to be preserved
in the room timeline. In cases where this is not required, better privacy
may be obtained by sending the `m.beacon` events as EDUs.
See [MSC3672](https://github.com/matrix-org/matrix-spec-proposals/pull/3672)
for this approach. Note that it depends on user-defined EDUs
([MSC2477](https://github.com/matrix-org/matrix-spec-proposals/pull/2477/))
and encrypted EDUs
([MSC3673](https://github.com/matrix-org/matrix-spec-proposals/pull/3673)).
### To-device messages
We could behave like
[MSC3401](https://github.com/matrix-org/matrix-spec-proposals/pull/3401) and
send location data via to-device messages to interested devices.
* Pros:
* Doesn't thrash state resolution by storing new location points every time
they change
* Gets you easy E2EE automatically
* Cons:
* designs out historical geo-data use cases
* means you are reinventing the pubsub fan-out routing you get for free with
Matrix events
* means you have to reinvent decentralised ACLs to check that the
subscribing users are valid
* means new joiners to a room won't even be able to see the most recent
location for someone
* MSC1763 data retention lets us control the historical data anyway.
Alternatively, we could negotiate a WebRTC data channel using MSC3401 and
stream low-latency geospatial data over the participating devices in the room.
This doesn't give us historical data, however, and requiring a WebRTC stack
is prohibitively complicated for simple clients (e.g. basic IOT devices
reporting spatial telemetry).
### One state event per user
(As suggested by @deepbluev7)
To reduce the problem of state bloat (too many state events with different keys) and avoid the need for permission changes on state events, we could post a single state event per user, which contained a list of all the currently-shared location events, and the location events could be normal timeline events, which are updated using message edits (with `m.replace`).
Advantages:
* Backwards compatible with static location sharing ([MSC3488](https://github.com/matrix-org/matrix-spec-proposals/pull/3488)) - clients that did not understand live location sharing but did understand static would see the location changing over time due to the edits.
* Only one state event per user - less state bloat.
* No need for changes to the rules about who can modify state events (but still requires the ability for unprivileged users to create a state event with `state_key` equal to their mxid).
Disadvantages
* Potential race where multiple clients update the same state event at the same time, and one overwrites the other.
* Location events need to be fetched from the timeline before they can be used.
* Potential confusion - a live location is semantically different from a static location that has been edited.
### No state events
We could send location data as normal E2EE messages, with no state events
involved. However, clients would have to back-paginate in an unbounded fashion
to confidently say what the various beacons are doing rather than simply
fishing it out of room state.
### Including velocity
We could include velocity data as well as displacement data here (especially as
the W3C geolocation API provides it); this has been left for a future MSC in
the interests of avoiding scope creep.
## Security considerations
Location data is high risk for real-world abuse, especially if stored
unencrypted or persisted. The same security considerations apply as for
`m.location` data in general.
Normally, locations should only be shared in encrypted rooms, meaning that they
are transferred and stored end-to-end encrypted automatically.
Clients will probably want to warn users when they request to share location in
an unencrypted room.
See "Redacting shared locations" above for information about deleting shared
location data.
## Unstable prefix
Until this MSC lands, the following unstable prefixes should be used:
* `m.beacon_info` -> `org.matrix.msc3672.beacon_info`
* `m.beacon` -> `org.matrix.msc3672.beacon`
(Note: these prefixes are shared with MSC3672. If this MSC lands first, MSC3672
can be updated to use stable prefixes.)
Until MSC3488 lands, the following unstable prefixes should be used:
* `m.location` -> `org.matrix.msc3488.location`
* `m.ts` -> `org.matrix.msc3488.ts`
* `m.asset` -> `org.matrix.msc3488.asset`
Examples of the events with unstable prefixes:
```json5
{
"content": {
"description": "Kylie's live location",
"live": true,
"org.matrix.msc3488.asset": { "type": "m.self" },
"org.matrix.msc3488.ts": 651066205621,
"timeout": 3600000
},
"room_id": "!dypRwVXIkJkTAACHPd:element.io",
"sender": "@kylie:example.com",
"state_key": "@kylie:example.com",
"type": "org.matrix.msc3672.beacon_info",
"event_id": "$TlS7h0NHzBdZIccsSspF5CMpQE8YMT0stRern0nXscI"
}
```
```json5
{
"content": {
"m.relates_to": {
"event_id": "$TlS7h0NHzBdZIccsSspF5CMpQE8YMT0stRern0nXscI",
"rel_type": "m.reference"
},
"org.matrix.msc3488.location": {
"uri": "geo:8.95752746197222,12.494122581370175;u=10"
},
"org.matrix.msc3488.ts": 651066206460
},
"room_id": "!dypRwVXIkJkTAACHPd:element.io",
"sender": "@kylie:example.com",
"type": "org.matrix.msc3672.beacon",
"event_id": "$75FtAIdg9wRTdACcgq4yetaInKlKQKhExYAwMc-qW3Q"
}
```
## Related MSCs
### Dependencies
* [MSC3267](https://github.com/matrix-org/matrix-spec-proposals/pull/3267):
*Reference relations*. This MSC uses `rel_type: m.reference` from MSC3267,
which in turn builds on
[MSC2674](https://github.com/matrix-org/matrix-spec-proposals/pull/2674):
Event Relationships (which has landed).
* [MSC3488](https://github.com/matrix-org/matrix-spec-proposals/pull/3488):
*Extending events with location data*. This MSC re-uses the `m.location`
object from MSC3488.
### MSCs that will enhance this one
* [MSC3779](https://github.com/matrix-org/matrix-spec-proposals/pull/3779):
*"Owned" State Events*. If MSC3779 lands, normal users will be able to share
their live location without special room permissions.
* [MSC3757](https://github.com/matrix-org/matrix-spec-proposals/pull/3757):
*Restricting who can overwrite a state event*. If MSC3757 lands, it will be
possible for users to share multiple live locations with variable `state_keys`
without fear that other users can overwrite their `m.beacon_info`.
### Related
* [MSC3672](https://github.com/matrix-org/matrix-spec-proposals/pull/3672):
*Sharing ephemeral streams of location data*. Equivalent of this MSC, but
using ephemeral events, for greater privacy but reduced historical
functionality.
## Implementations
Element (Web, Android and iOS) implementations based on this MSC are underway
in April 2022, and feedback from those implementations has been incorporated
into updates of this document.
Loading…
Cancel
Save