Merge remote matrix-org/master
This commit is contained in:
commit
219b27b182
67 changed files with 541 additions and 507 deletions
|
@ -18,15 +18,17 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
"/3pid/getValidated3pid":
|
||||
get:
|
||||
summary: Check whether ownership of a 3pid was validated.
|
||||
description: A client can check whether ownership of a 3pid was validated
|
||||
description: |-
|
||||
Determines if a given 3pid has been validated by a user.
|
||||
operationId: getValidated3pid
|
||||
parameters:
|
||||
- in: query
|
||||
|
@ -61,7 +63,9 @@ paths:
|
|||
description: The address of the 3pid being looked up.
|
||||
validated_at:
|
||||
type: integer
|
||||
description: Timestamp indicating the time that the 3pid was validated.
|
||||
description: |-
|
||||
Timestamp, in milliseconds, indicating the time that the 3pid
|
||||
was validated.
|
||||
required: ['medium', 'address', 'validated_at']
|
||||
400:
|
||||
description: |-
|
||||
|
@ -78,7 +82,7 @@ paths:
|
|||
schema:
|
||||
$ref: "../client-server/definitions/errors/error.yaml"
|
||||
404:
|
||||
description: The Session ID or client secret were not found
|
||||
description: The Session ID or client secret were not found.
|
||||
examples:
|
||||
application/json: {
|
||||
"errcode": "M_NO_VALID_SESSION",
|
||||
|
@ -95,7 +99,7 @@ paths:
|
|||
Future calls to ``/lookup`` for any of the session\'s 3pids will return
|
||||
this association.
|
||||
|
||||
Note: for backwards compatibility with older versions of this
|
||||
Note: for backwards compatibility with previous drafts of this
|
||||
specification, the parameters may also be specified as
|
||||
``application/x-form-www-urlencoded`` data. However, this usage is
|
||||
deprecated.
|
||||
|
@ -132,7 +136,6 @@ paths:
|
|||
"not_before": 1428825849161,
|
||||
"not_after": 4582425849161,
|
||||
"ts": 1428825849161,
|
||||
|
||||
"signatures": {
|
||||
"matrix.org": {
|
||||
"ed25519:0": "ENiU2YORYUJgE6WBMitU0mppbQjidDLanAusj8XS2nVRHPu+0t42OKA/r6zV6i2MzUbNQ3c3MiLScJuSsOiVDQ"
|
||||
|
@ -162,7 +165,10 @@ paths:
|
|||
description: The unix timestamp at which the association was verified.
|
||||
signatures:
|
||||
type: object
|
||||
description: The signatures of the verifying identity services which show that the association should be trusted, if you trust the verifying identity services.
|
||||
description: |-
|
||||
The signatures of the verifying identity services which show that the
|
||||
association should be trusted, if you trust the verifying identity
|
||||
services.
|
||||
$ref: "../../schemas/server-signatures.yaml"
|
||||
required:
|
||||
- address
|
||||
|
|
|
@ -18,8 +18,9 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
|
@ -34,13 +35,13 @@ paths:
|
|||
that that user was able to read the email for that email address, and
|
||||
so we validate ownership of the email address.
|
||||
|
||||
Note that Home Servers offer APIs that proxy this API, adding
|
||||
Note that homeservers offer APIs that proxy this API, adding
|
||||
additional behaviour on top, for example,
|
||||
``/register/email/requestToken`` is designed specifically for use when
|
||||
registering an account and therefore will inform the user if the email
|
||||
address given is already registered on the server.
|
||||
|
||||
Note: for backwards compatibility with older versions of this
|
||||
Note: for backwards compatibility with previous drafts of this
|
||||
specification, the parameters may also be specified as
|
||||
``application/x-form-www-urlencoded`` data. However, this usage is
|
||||
deprecated.
|
||||
|
@ -58,7 +59,7 @@ paths:
|
|||
properties:
|
||||
client_secret:
|
||||
type: string
|
||||
description: A unique string used to identify the validation attempt
|
||||
description: A unique string used to identify the validation attempt.
|
||||
email:
|
||||
type: string
|
||||
description: The email address to validate.
|
||||
|
@ -119,7 +120,7 @@ paths:
|
|||
associate the email address with any Matrix user ID. Specifically,
|
||||
calls to ``/lookup`` will not show a binding.
|
||||
|
||||
Note: for backwards compatibility with older versions of this
|
||||
Note: for backwards compatibility with previous drafts of this
|
||||
specification, the parameters may also be specified as
|
||||
``application/x-form-www-urlencoded`` data. However, this usage is
|
||||
deprecated.
|
||||
|
|
|
@ -18,8 +18,9 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
|
@ -29,7 +30,7 @@ paths:
|
|||
description: |-
|
||||
Sign invitation details.
|
||||
|
||||
The identity server will look up ``token`` which was stored in a call
|
||||
The identity service will look up ``token`` which was stored in a call
|
||||
to ``store-invite``, and fetch the sender of the invite.
|
||||
operationId: blindlySignStuff
|
||||
parameters:
|
||||
|
@ -38,24 +39,24 @@ paths:
|
|||
schema:
|
||||
type: object
|
||||
example: {
|
||||
"mxid": "@foo:bar.com",
|
||||
"token": "sometoken",
|
||||
"private_key": "base64encodedkey"
|
||||
}
|
||||
"mxid": "@foo:bar.com",
|
||||
"token": "sometoken",
|
||||
"private_key": "base64encodedkey"
|
||||
}
|
||||
properties:
|
||||
mxid:
|
||||
type: string
|
||||
description: The Matrix user ID of the user accepting the invitation.
|
||||
token:
|
||||
type: string
|
||||
description: Token from the call to ``store-invite``
|
||||
description: The token from the call to ``store-invite``.
|
||||
private_key:
|
||||
type: string
|
||||
description: The private key, encoded as `Unpadded base64`_.
|
||||
required: ["mxid", "token", "private_key"]
|
||||
responses:
|
||||
200:
|
||||
description: The signedjson of the mxid, sender, and token.
|
||||
description: The signed JSON of the mxid, sender, and token.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -85,7 +86,7 @@ paths:
|
|||
"token": "abc123"
|
||||
}
|
||||
404:
|
||||
description: Token was not found.
|
||||
description: The token was not found.
|
||||
examples:
|
||||
application/json: {
|
||||
"errcode": "M_UNRECOGNIZED",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Copyright 2016 OpenMarket Ltd
|
||||
# Copyright 2017 Kamax.io
|
||||
# Copyright 2017 New Vector Ltd
|
||||
# Copyright 2018 New Vector Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -20,8 +21,9 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
|
@ -46,7 +48,7 @@ paths:
|
|||
responses:
|
||||
200:
|
||||
description:
|
||||
The association for that 3pid, or the empty object if no association is known.
|
||||
The association for that 3pid, or an empty object if no association is known.
|
||||
examples:
|
||||
application/json: {
|
||||
"address": "louise@bobs.burgers",
|
||||
|
@ -66,10 +68,10 @@ paths:
|
|||
properties:
|
||||
address:
|
||||
type: string
|
||||
description: The 3pid address of the user being looked up.
|
||||
description: The 3pid address of the user being looked up, matching the address requested.
|
||||
medium:
|
||||
type: string
|
||||
description: The literal string "email".
|
||||
description: A medium from the `3PID Types`_ Appendix, matching the medium requested.
|
||||
mxid:
|
||||
type: string
|
||||
description: The Matrix user ID associated with the 3pid.
|
||||
|
@ -126,7 +128,9 @@ paths:
|
|||
#- type: 3PID Address
|
||||
- type: string
|
||||
- type: string
|
||||
description: an array of arrays containing the `3PID Types`_ with the ``medium`` in first position and the ``address`` in second position.
|
||||
description: |-
|
||||
An array of arrays containing the `3PID Types`_ with the ``medium``
|
||||
in first position and the ``address`` in second position.
|
||||
required:
|
||||
- "threepids"
|
||||
responses:
|
||||
|
@ -157,6 +161,9 @@ paths:
|
|||
- type: string
|
||||
- type: string
|
||||
- type: string
|
||||
description: an array of array containing the `3PID Types`_ with the ``medium`` in first position, the ``address`` in second position and Matrix ID in third position.
|
||||
description: |-
|
||||
An array of array containing the `3PID Types`_ with the ``medium``
|
||||
in first position, the ``address`` in second position and Matrix user
|
||||
ID in third position.
|
||||
required:
|
||||
- "threepids"
|
||||
|
|
|
@ -18,8 +18,9 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
|
@ -34,13 +35,13 @@ paths:
|
|||
indicates that that user was able to read the SMS for that phone
|
||||
number, and so we validate ownership of the phone number.
|
||||
|
||||
Note that Home Servers offer APIs that proxy this API, adding
|
||||
Note that homeservers offer APIs that proxy this API, adding
|
||||
additional behaviour on top, for example,
|
||||
``/register/msisdn/requestToken`` is designed specifically for use when
|
||||
registering an account and therefore will inform the user if the phone
|
||||
number given is already registered on the server.
|
||||
|
||||
Note: for backwards compatibility with older versions of this
|
||||
Note: for backwards compatibility with previous drafts of this
|
||||
specification, the parameters may also be specified as
|
||||
``application/x-form-www-urlencoded`` data. However, this usage is
|
||||
deprecated.
|
||||
|
@ -106,6 +107,8 @@ paths:
|
|||
|
||||
- ``M_INVALID_ADDRESS``: The phone number provided was invalid.
|
||||
- ``M_SEND_ERROR``: The validation SMS could not be sent.
|
||||
- ``M_DESTINATION_REJECTED``: The identity service cannot deliver an
|
||||
SMS to the provided country or region.
|
||||
examples:
|
||||
application/json: {
|
||||
"errcode": "M_INVALID_ADDRESS",
|
||||
|
@ -125,7 +128,7 @@ paths:
|
|||
associate the phone number address with any Matrix user
|
||||
ID. Specifically, calls to ``/lookup`` will not show a binding.
|
||||
|
||||
Note: for backwards compatibility with older versions of this
|
||||
Note: for backwards compatibility with previous drafts of this
|
||||
specification, the parameters may also be specified as
|
||||
``application/x-form-www-urlencoded`` data. However, this usage is
|
||||
deprecated.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright 2018 Kamax Sàrl
|
||||
# Copyright 2018 New Vector Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -14,7 +15,7 @@
|
|||
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: "Matrix Client-Identity Versions API"
|
||||
title: "Matrix Identity Service Ping API"
|
||||
version: "1.0.0"
|
||||
host: localhost:8090
|
||||
schemes:
|
||||
|
@ -25,19 +26,19 @@ produces:
|
|||
paths:
|
||||
"/api/v1":
|
||||
get:
|
||||
summary: Checks that an Identity server is available at this API endpopint.
|
||||
summary: Checks that an Identity Service is available at this API endpoint.
|
||||
description: |-
|
||||
Checks that an Identity server is available at this API endpopint.
|
||||
Checks that an Identity Service is available at this API endpoint.
|
||||
|
||||
To discover that an Identity server is available at a specific URL,
|
||||
To discover that an Identity Service is available at a specific URL,
|
||||
this endpoint can be queried and will return an empty object.
|
||||
|
||||
This is primarly used for auto-discovery and health check purposes
|
||||
by entities acting as a client for the Identity server.
|
||||
by entities acting as a client for the Identity Service.
|
||||
operationId: ping
|
||||
responses:
|
||||
200:
|
||||
description: An Identity server is ready to serve requests.
|
||||
description: An Identity Service is ready to serve requests.
|
||||
examples:
|
||||
application/json: {}
|
||||
schema:
|
||||
|
|
|
@ -18,8 +18,9 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
|
@ -113,8 +114,8 @@ paths:
|
|||
The validity of the public key.
|
||||
examples:
|
||||
application/json: {
|
||||
"valid": true
|
||||
}
|
||||
"valid": true
|
||||
}
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
|
|
|
@ -18,16 +18,17 @@ info:
|
|||
host: localhost:8090
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/identity/api/v1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
paths:
|
||||
"/store-invite":
|
||||
post:
|
||||
summary: Store pending invitations to a user\'s 3pid.
|
||||
summary: Store pending invitations to a user's 3pid.
|
||||
description: |-
|
||||
Store pending invitations to a user\'s 3pid.
|
||||
Store pending invitations to a user's 3pid.
|
||||
|
||||
In addition to the request parameters specified below, an arbitrary
|
||||
number of other parameters may also be specified. These may be used in
|
||||
|
@ -47,6 +48,8 @@ paths:
|
|||
|
||||
Also, the generated ephemeral public key will be listed as valid on
|
||||
requests to ``/_matrix/identity/api/v1/pubkey/ephemeral/isvalid``.
|
||||
|
||||
Currently, invites may only be issued for 3pids of the ``email`` medium.
|
||||
operationId: storeInvite
|
||||
parameters:
|
||||
- in: body
|
||||
|
@ -84,7 +87,7 @@ paths:
|
|||
description: The generated token.
|
||||
public_keys:
|
||||
type: array
|
||||
description: A list of [server\'s long-term public key, generated ephemeral public key].
|
||||
description: A list of [server's long-term public key, generated ephemeral public key].
|
||||
items:
|
||||
type: string
|
||||
display_name:
|
||||
|
@ -111,7 +114,7 @@ paths:
|
|||
application/json: {
|
||||
"errcode": "M_THREEPID_IN_USE",
|
||||
"error": "Binding already known",
|
||||
"mxid": mxid
|
||||
"mxid": "@alice:example.com"
|
||||
}
|
||||
schema:
|
||||
$ref: "../client-server/definitions/errors/error.yaml"
|
||||
|
|
|
@ -23,7 +23,8 @@ allOf:
|
|||
hashes:
|
||||
type: object
|
||||
title: Event Hash
|
||||
description: Hashes of the PDU, following the algorithm specified in `Signing Events`_.
|
||||
description: |-
|
||||
Content hashes of the PDU, following the algorithm specified in `Signing Events`_.
|
||||
example: {
|
||||
"sha256": "thishashcoversallfieldsincasethisisredacted"
|
||||
}
|
||||
|
|
|
@ -55,8 +55,8 @@ properties:
|
|||
prev_events:
|
||||
type: array
|
||||
description: |-
|
||||
Event IDs and hashes of the most recent events in the room that the homeserver was aware
|
||||
of when it made this event.
|
||||
Event IDs and reference hashes for the most recent events in the room
|
||||
that the homeserver was aware of when it made this event.
|
||||
items:
|
||||
type: array
|
||||
maxItems: 2
|
||||
|
@ -86,7 +86,7 @@ properties:
|
|||
auth_events:
|
||||
type: array
|
||||
description: |-
|
||||
An event reference list containing the authorization events that would
|
||||
Event IDs and reference hashes for the authorization events that would
|
||||
allow this event to be in the room.
|
||||
items:
|
||||
type: array
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Update all event examples to be accurate representations of their associated events.
|
0
changelogs/identity_service.rst
Normal file
0
changelogs/identity_service.rst
Normal file
1
changelogs/identity_service/newsfragments/.gitignore
vendored
Normal file
1
changelogs/identity_service/newsfragments/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!.gitignore
|
30
changelogs/identity_service/pyproject.toml
Normal file
30
changelogs/identity_service/pyproject.toml
Normal file
|
@ -0,0 +1,30 @@
|
|||
[tool.towncrier]
|
||||
filename = "../identity_service.rst"
|
||||
directory = "newsfragments"
|
||||
issue_format = "`#{issue} <https://github.com/matrix-org/matrix-doc/issues/{issue}>`_"
|
||||
title_format = "{version}"
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "breaking"
|
||||
name = "Breaking Changes"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "deprecation"
|
||||
name = "Deprecations"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "new"
|
||||
name = "New Endpoints"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "feature"
|
||||
name = "Backwards Compatible Changes"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "clarification"
|
||||
name = "Spec Clarifications"
|
||||
showcontent = true
|
0
changelogs/server_server.rst
Normal file
0
changelogs/server_server.rst
Normal file
1
changelogs/server_server/newsfragments/.gitignore
vendored
Normal file
1
changelogs/server_server/newsfragments/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!.gitignore
|
30
changelogs/server_server/pyproject.toml
Normal file
30
changelogs/server_server/pyproject.toml
Normal file
|
@ -0,0 +1,30 @@
|
|||
[tool.towncrier]
|
||||
filename = "../server_server.rst"
|
||||
directory = "newsfragments"
|
||||
issue_format = "`#{issue} <https://github.com/matrix-org/matrix-doc/issues/{issue}>`_"
|
||||
title_format = "{version}"
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "breaking"
|
||||
name = "Breaking Changes"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "deprecation"
|
||||
name = "Deprecations"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "new"
|
||||
name = "New Endpoints"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "feature"
|
||||
name = "Backwards Compatible Changes"
|
||||
showcontent = true
|
||||
|
||||
[[tool.towncrier.type]]
|
||||
directory = "clarification"
|
||||
name = "Spec Clarifications"
|
||||
showcontent = true
|
|
@ -44,16 +44,51 @@ except ImportError as e:
|
|||
raise
|
||||
|
||||
|
||||
def load_file(path):
|
||||
print("Loading reference: %s" % path)
|
||||
if not path.startswith("file://"):
|
||||
raise Exception("Bad ref: %s" % (path,))
|
||||
path = path[len("file://"):]
|
||||
with open(path, "r") as f:
|
||||
if path.endswith(".json"):
|
||||
return json.load(f)
|
||||
else:
|
||||
# We have to assume it's YAML because some of the YAML examples
|
||||
# do not have file extensions.
|
||||
return yaml.load(f)
|
||||
|
||||
|
||||
def resolve_references(path, schema):
|
||||
if isinstance(schema, dict):
|
||||
# do $ref first
|
||||
if '$ref' in schema:
|
||||
value = schema['$ref']
|
||||
path = os.path.abspath(os.path.join(os.path.dirname(path), value))
|
||||
ref = load_file("file://" + path)
|
||||
result = resolve_references(path, ref)
|
||||
del schema['$ref']
|
||||
else:
|
||||
result = {}
|
||||
|
||||
for key, value in schema.items():
|
||||
result[key] = resolve_references(path, value)
|
||||
return result
|
||||
elif isinstance(schema, list):
|
||||
return [resolve_references(path, value) for value in schema]
|
||||
else:
|
||||
return schema
|
||||
|
||||
|
||||
def check_example_file(examplepath, schemapath):
|
||||
with open(examplepath) as f:
|
||||
example = yaml.load(f)
|
||||
example = resolve_references(examplepath, json.load(f))
|
||||
|
||||
with open(schemapath) as f:
|
||||
schema = yaml.load(f)
|
||||
|
||||
fileurl = "file://" + os.path.abspath(schemapath)
|
||||
schema["id"] = fileurl
|
||||
resolver = jsonschema.RefResolver(schemapath, schema, handlers={"file": load_yaml})
|
||||
resolver = jsonschema.RefResolver(schemapath, schema, handlers={"file": load_file})
|
||||
|
||||
print ("Checking schema for: %r %r" % (examplepath, schemapath))
|
||||
try:
|
||||
|
@ -71,6 +106,10 @@ def check_example_dir(exampledir, schemadir):
|
|||
if filename.startswith("."):
|
||||
# Skip over any vim .swp files.
|
||||
continue
|
||||
cwd = os.path.basename(os.path.dirname(os.path.join(root, filename)))
|
||||
if cwd == "core":
|
||||
# Skip checking the underlying definitions
|
||||
continue
|
||||
examplepath = os.path.join(root, filename)
|
||||
schemapath = examplepath.replace(exampledir, schemadir)
|
||||
if schemapath.find("#") >= 0:
|
||||
|
@ -85,14 +124,6 @@ def check_example_dir(exampledir, schemadir):
|
|||
raise ValueError("Error validating examples")
|
||||
|
||||
|
||||
def load_yaml(path):
|
||||
if not path.startswith("file:///"):
|
||||
raise Exception("Bad ref: %s" % (path,))
|
||||
path = path[len("file://"):]
|
||||
with open(path, "r") as f:
|
||||
return yaml.load(f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
check_example_dir("examples", "schema")
|
||||
|
|
6
event-schemas/examples/core/event.json
Normal file
6
event-schemas/examples/core/event.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"content": {
|
||||
"key": "value"
|
||||
},
|
||||
"type": "org.example.custom.event"
|
||||
}
|
4
event-schemas/examples/core/room_edu.json
Normal file
4
event-schemas/examples/core/room_edu.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$ref": "event.json",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com"
|
||||
}
|
10
event-schemas/examples/core/room_event.json
Normal file
10
event-schemas/examples/core/room_event.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"$ref": "event.json",
|
||||
"event_id": "$143273582443PhrSn:domain.com",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com",
|
||||
"sender": "@example:domain.com",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
4
event-schemas/examples/core/state_event.json
Normal file
4
event-schemas/examples/core/state_event.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$ref": "room_event.json",
|
||||
"state_key": "ArbitraryString"
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.call.answer",
|
||||
"content": {
|
||||
"version" : 0,
|
||||
"call_id": "12345",
|
||||
|
@ -8,10 +9,5 @@
|
|||
"type" : "answer",
|
||||
"sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]"
|
||||
}
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.call.answer",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.call.candidates",
|
||||
"content": {
|
||||
"version" : 0,
|
||||
"call_id": "12345",
|
||||
|
@ -10,10 +11,5 @@
|
|||
"candidate": "candidate:863018703 1 udp 2122260223 10.9.64.156 43670 typ host generation 0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.call.candidates",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.call.hangup",
|
||||
"content": {
|
||||
"version" : 0,
|
||||
"call_id": "12345"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.call.hangup",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.call.invite",
|
||||
"content": {
|
||||
"version" : 0,
|
||||
"call_id": "12345",
|
||||
|
@ -8,10 +9,5 @@
|
|||
"type" : "offer",
|
||||
"sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]"
|
||||
}
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.call.invite",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
{
|
||||
"$ref": "core/event.json",
|
||||
"type": "m.direct",
|
||||
"content": {
|
||||
"@bob:example.com": [
|
||||
"!abcdefgh:example.com",
|
||||
"!hgfedcba:example.com"
|
||||
]
|
||||
"!abcdefgh:example.com",
|
||||
"!hgfedcba:example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"$ref": "core/event.json",
|
||||
"type": "m.ignored_user_list",
|
||||
"content": {
|
||||
"ignored_users": {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"$ref": "core/event.json",
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.presence",
|
||||
"content": {
|
||||
"avatar_url": "mxc://localhost:wefuiwegh8742w",
|
||||
"last_active_ago": 2478593,
|
||||
"presence": "online",
|
||||
"currently_active": false
|
||||
},
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.presence"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"type": "m.receipt",
|
||||
"room_id": "!KpjVgQyZpzBwvMBsnT:matrix.org",
|
||||
"content": {
|
||||
"$1435641916114394fHBLK:matrix.org": {
|
||||
"m.read": {
|
||||
"@rikj:jki.re": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
"$ref": "core/room_edu.json",
|
||||
"type": "m.receipt",
|
||||
"content": {
|
||||
"$1435641916114394fHBLK:matrix.org": {
|
||||
"m.read": {
|
||||
"@rikj:jki.re": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"content": {
|
||||
"aliases": ["#somewhere:localhost", "#another:localhost"]
|
||||
},
|
||||
"state_key": "localhost",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"$ref": "core/state_event.json",
|
||||
"state_key": "domain.com",
|
||||
"type": "m.room.aliases",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
"content": {
|
||||
"aliases": ["#somewhere:domain.com", "#another:domain.com"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.avatar",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"info": {
|
||||
"h": 398,
|
||||
|
@ -7,12 +9,6 @@
|
|||
"mimetype": "image/jpeg",
|
||||
"size": 31037
|
||||
},
|
||||
"url": "mxc://localhost/JWEIFJgwEIhweiWJE"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.avatar",
|
||||
"state_key": "",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
"url": "mxc://domain.com/JWEIFJgwEIhweiWJE"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.canonical_alias",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"alias": "#somewhere:localhost"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.canonical_alias",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"content": {
|
||||
"creator": "@example:localhost"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.create",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"creator": "@example:domain.com",
|
||||
"room_version": "1",
|
||||
"m.federate": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
{
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.encrypted",
|
||||
"content": {
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"ciphertext": "AwgAEnACgAkLmt6qF84IK++J7UDH2Za1YVchHyprqTqsg...",
|
||||
"device_id": "RJYKSTBOIE",
|
||||
"sender_key": "IlRMeOPX2e0MurIyfWEucYBRVOEEUMrOHqn/8mLqMjA",
|
||||
"session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ"
|
||||
},
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"origin_server_ts": 1476648761524,
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.room.encrypted"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.encrypted",
|
||||
"sender": "@example:localhost",
|
||||
"content": {
|
||||
"algorithm": "m.olm.v1.curve25519-aes-sha2",
|
||||
"sender_key": "Szl29ksW/L8yZGWAX+8dY1XyFi+i5wm+DRhTGkbMiwU",
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
{
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.encryption",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"rotation_period_ms": 604800000,
|
||||
"rotation_period_msgs": 100
|
||||
},
|
||||
"event_id": "$WLGTSEFJJKJ:localhost",
|
||||
"origin_server_ts": 1476648761524,
|
||||
"sender": "@example:localhost",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"state_key": "",
|
||||
"type": "m.room.encryption"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242353,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.guest_access",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"guest_access": "can_join"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217938,
|
||||
"event_id": "$WLGTSEFSEG:localhost",
|
||||
"type": "m.room.guest_access",
|
||||
"room_id": "!Cuyf34gef24u:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.history_visibility",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"history_visibility": "shared"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.history_visibility",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.join_rules",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"join_rule": "public"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.join_rules",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"state_key": "@alice:domain.com",
|
||||
"type": "m.room.member",
|
||||
"content": {
|
||||
"membership": "join",
|
||||
"avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto",
|
||||
"avatar_url": "mxc://domain.com/SEsfnsuifSDFSSEF#auto",
|
||||
"displayname": "Alice Margatroid"
|
||||
},
|
||||
"state_key": "@alice:localhost",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.member",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "m.room.member",
|
||||
"content": {
|
||||
"membership": "invite",
|
||||
"avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto",
|
||||
"avatar_url": "mxc://domain.com/SEsfnsuifSDFSSEF#auto",
|
||||
"displayname": "Alice Margatroid"
|
||||
},
|
||||
"unsigned": {
|
||||
"age": 1234,
|
||||
"invite_room_state": [
|
||||
{
|
||||
"type": "m.room.name",
|
||||
|
@ -22,11 +23,5 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"state_key": "@alice:localhost",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.member",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "m.room.member",
|
||||
"content": {
|
||||
"membership": "invite",
|
||||
"avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto",
|
||||
"avatar_url": "mxc://domain.com/SEsfnsuifSDFSSEF#auto",
|
||||
"displayname": "Alice Margatroid",
|
||||
"third_party_invite": {
|
||||
"display_name": "alice",
|
||||
"signed": {
|
||||
"mxid": "@alice:localhost",
|
||||
"mxid": "@alice:domain.com",
|
||||
"signatures": {
|
||||
"magic.forest": {
|
||||
"ed25519:3": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
|
||||
|
@ -16,11 +16,5 @@
|
|||
"token": "abc123"
|
||||
}
|
||||
}
|
||||
},
|
||||
"state_key": "@alice:localhost",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.member",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
{
|
||||
"age": 146,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "Bee Gees - Stayin' Alive",
|
||||
"url": "mxc://localhost/ffed755USFFxlgbQYZGtryd",
|
||||
"url": "mxc://domain.com/ffed755USFFxlgbQYZGtryd",
|
||||
"info": {
|
||||
"duration": 2140786,
|
||||
"size": 1563685,
|
||||
"mimetype": "audio/mpeg"
|
||||
},
|
||||
"msgtype": "m.audio"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:localhost",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:localhost",
|
||||
"type": "m.room.message",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "thinks this is an example emote",
|
||||
"msgtype": "m.emote",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "thinks <b>this</b> is an example emote"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.message",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"age": 146,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "something-important.doc",
|
||||
"filename": "something-important.doc",
|
||||
|
@ -8,11 +9,6 @@
|
|||
"size": 46144
|
||||
},
|
||||
"msgtype": "m.file",
|
||||
"url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:localhost",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:localhost",
|
||||
"type": "m.room.message",
|
||||
"sender": "@example:localhost"
|
||||
"url": "mxc://domain.com/FHyPlCeYUSFFxlgbQYZmoEoe"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "filename.jpg",
|
||||
"info": {
|
||||
|
@ -8,12 +9,7 @@
|
|||
"mimetype": "image/jpeg",
|
||||
"size": 31037
|
||||
},
|
||||
"url": "mxc://localhost/JWEIFJgwEIhweiWJE",
|
||||
"url": "mxc://domain.com/JWEIFJgwEIhweiWJE",
|
||||
"msgtype": "m.image"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.message",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"age": 146,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "Big Ben, London, UK",
|
||||
"geo_uri": "geo:51.5008,0.1247",
|
||||
"info": {
|
||||
"thumbnail_url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe",
|
||||
"thumbnail_url": "mxc://domain.com/FHyPlCeYUSFFxlgbQYZmoEoe",
|
||||
"thumbnail_info": {
|
||||
"mimetype": "image/jpeg",
|
||||
"size": 46144,
|
||||
|
@ -13,10 +14,5 @@
|
|||
}
|
||||
},
|
||||
"msgtype": "m.location"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:localhost",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:localhost",
|
||||
"type": "m.room.message",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "This is an example notice",
|
||||
"msgtype": "m.notice",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "This is an <strong>example</strong> notice"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.message",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "This is an example text message",
|
||||
"msgtype": "m.text",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example text message</b>"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.message",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"age": 146,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"body": "Gangnam Style",
|
||||
"url": "mxc://localhost/a526eYUSFFxlgbQYZmo442",
|
||||
"url": "mxc://domain.com/a526eYUSFFxlgbQYZmo442",
|
||||
"info": {
|
||||
"thumbnail_url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe",
|
||||
"thumbnail_url": "mxc://domain.com/FHyPlCeYUSFFxlgbQYZmoEoe",
|
||||
"thumbnail_info": {
|
||||
"mimetype": "image/jpeg",
|
||||
"size": 46144,
|
||||
|
@ -18,10 +19,5 @@
|
|||
"mimetype": "video/mp4"
|
||||
},
|
||||
"msgtype": "m.video"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:localhost",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:localhost",
|
||||
"type": "m.room.message",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.message.feedback",
|
||||
"content": {
|
||||
"type": "delivered",
|
||||
"target_event_id": "$WEIGFHFW:localhost"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.message.feedback",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.name",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"name": "The room name"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.name",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"content": {
|
||||
"pinned": ["$someevent:localhost"]
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.pinned_events",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"pinned": ["$someevent:domain.com"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.power_levels",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"ban": 50,
|
||||
"events": {
|
||||
|
@ -18,11 +20,5 @@
|
|||
"notifications": {
|
||||
"room": 20
|
||||
}
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.power_levels",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
{
|
||||
"unsigned": {
|
||||
"age": 242352
|
||||
},
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.room.redaction",
|
||||
"redacts": "$fukweghifu23:localhost",
|
||||
"content": {
|
||||
"reason": "Spamming"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.redaction",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"redacts": "$fukweghifu23:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.third_party_invite",
|
||||
"state_key": "pc98",
|
||||
"content": {
|
||||
"display_name": "Alice Margatroid",
|
||||
"key_validity_url": "https://magic.forest/verifykey",
|
||||
|
@ -8,11 +10,5 @@
|
|||
"public_key": "def456",
|
||||
"key_validity_url": "https://magic.forest/verifykey"
|
||||
}]
|
||||
},
|
||||
"state_key": "pc98",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.third_party_invite",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/state_event.json",
|
||||
"type": "m.room.topic",
|
||||
"state_key": "",
|
||||
"content": {
|
||||
"topic": "A room topic"
|
||||
},
|
||||
"state_key": "",
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.room.topic",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
{
|
||||
"$ref": "core/event.json",
|
||||
"type": "m.room_key",
|
||||
"content": {
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"session_id": "X3lUlvLELLYxeTx4yOVu6UDpasGEVO0Jbu+QFnm0cKQ",
|
||||
"session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8LlfJL7qNBEY..."
|
||||
},
|
||||
"type": "m.room_key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"age": 242352,
|
||||
"$ref": "core/room_event.json",
|
||||
"type": "m.sticker",
|
||||
"content": {
|
||||
"body": "Landing",
|
||||
"info": {
|
||||
|
@ -16,10 +17,5 @@
|
|||
"size": 73602
|
||||
},
|
||||
"url": "mxc://matrix.org/sHhqkFCvSkFwtmvtETOtKnLP"
|
||||
},
|
||||
"origin_server_ts": 1431961217939,
|
||||
"event_id": "$WLGTSEFSEF:localhost",
|
||||
"type": "m.sticker",
|
||||
"room_id": "!Cuyf34gef24t:localhost",
|
||||
"sender": "@example:localhost"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"$ref": "core/event.json",
|
||||
"type": "m.tag",
|
||||
"content": {
|
||||
"tags": {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"type": "m.typing",
|
||||
"room_id": "!z0mnsuiwhifuhwwfw:matrix.org",
|
||||
"content": {
|
||||
"user_ids": ["@alice:matrix.org", "@bob:example.com"]
|
||||
}
|
||||
"$ref": "core/room_edu.json",
|
||||
"type": "m.typing",
|
||||
"content": {
|
||||
"user_ids": ["@alice:matrix.org", "@bob:example.com"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -525,6 +525,10 @@ if __name__ == '__main__':
|
|||
"--push_gateway_release", "-p", action="store", default="unstable",
|
||||
help="The push gateway release tag to generate, e.g. r1.2"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--identity_release", "-i", action="store", default="unstable",
|
||||
help="The identity service release tag to generate, e.g. r1.2"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--list_targets", action="store_true",
|
||||
help="Do not update the specification. Instead print a list of targets.",
|
||||
|
@ -543,13 +547,13 @@ if __name__ == '__main__':
|
|||
|
||||
substitutions = {
|
||||
"%CLIENT_RELEASE_LABEL%": args.client_release,
|
||||
# we hardcode a major version of r0. This ends up in the
|
||||
# example API URLs. When we have released a new major version,
|
||||
# we'll have to bump it.
|
||||
# we hardcode the major versions. This ends up in the example
|
||||
# API URLs. When we have released a new major version, we'll
|
||||
# have to bump them.
|
||||
"%CLIENT_MAJOR_VERSION%": "r0",
|
||||
"%SERVER_RELEASE_LABEL%": args.server_release,
|
||||
"%SERVER_MAJOR_VERSION%": extract_major(args.server_release),
|
||||
"%APPSERVICE_RELEASE_LABEL%": args.appservice_release,
|
||||
"%IDENTITY_RELEASE_LABEL%": args.identity_release,
|
||||
"%PUSH_GATEWAY_RELEASE_LABEL%": args.push_gateway_release,
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,14 @@ class MatrixSections(Sections):
|
|||
changelogs = self.units.get("changelogs")
|
||||
return changelogs["push_gateway"]
|
||||
|
||||
def render_identity_service_changelog(self):
|
||||
changelogs = self.units.get("changelogs")
|
||||
return changelogs["identity_service"]
|
||||
|
||||
def render_server_server_changelog(self):
|
||||
changelogs = self.units.get("changelogs")
|
||||
return changelogs["server_server"]
|
||||
|
||||
def render_application_service_changelog(self):
|
||||
changelogs = self.units.get("changelogs")
|
||||
return changelogs["application_service"]
|
||||
|
|
|
@ -754,6 +754,7 @@ class MatrixUnits(Units):
|
|||
def load_apis(self, substitutions):
|
||||
cs_ver = substitutions.get("%CLIENT_RELEASE_LABEL%", "unstable")
|
||||
fed_ver = substitutions.get("%SERVER_RELEASE_LABEL%", "unstable")
|
||||
is_ver = substitutions.get("%IDENTITY_RELEASE_LABEL%", "unstable")
|
||||
as_ver = substitutions.get("%APPSERVICE_RELEASE_LABEL%", "unstable")
|
||||
push_gw_ver = substitutions.get("%PUSH_GATEWAY_RELEASE_LABEL%", "unstable")
|
||||
|
||||
|
@ -772,7 +773,7 @@ class MatrixUnits(Units):
|
|||
as_ver,
|
||||
"Privileged server plugins",
|
||||
), TypeTableRow(
|
||||
"`Identity Service API <identity_service/unstable.html>`_",
|
||||
"`Identity Service API <identity_service/"+is_ver+".html>`_",
|
||||
"unstable",
|
||||
"Mapping of third party IDs to Matrix IDs",
|
||||
), TypeTableRow(
|
||||
|
@ -794,7 +795,7 @@ class MatrixUnits(Units):
|
|||
logger.info("Reading event example: %s" % filepath)
|
||||
try:
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
example = json.load(f)
|
||||
example = resolve_references(filepath, json.load(f))
|
||||
examples[filename] = examples.get(filename, [])
|
||||
examples[filename].append(example)
|
||||
if filename != event_name:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.. Copyright 2016 OpenMarket Ltd
|
||||
.. Copyright 2017 Kamax.io
|
||||
.. Copyright 2017 New Vector Ltd
|
||||
.. Copyright 2018 New Vector Ltd
|
||||
..
|
||||
.. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
.. you may not use this file except in compliance with the License.
|
||||
|
@ -28,13 +29,27 @@ practice has only been applied specifically to email addresses and phone numbers
|
|||
.. contents:: Table of Contents
|
||||
.. sectnum::
|
||||
|
||||
Specification version
|
||||
---------------------
|
||||
Changelog
|
||||
---------
|
||||
|
||||
.. topic:: Version: %IDENTITY_RELEASE_LABEL%
|
||||
{{identity_service_changelog}}
|
||||
|
||||
This version of the specification is generated from
|
||||
`matrix-doc <https://github.com/matrix-org/matrix-doc>`_ as of Git commit
|
||||
`{{git_version}} <https://github.com/matrix-org/matrix-doc/tree/{{git_rev}}>`_.
|
||||
|
||||
For the full historical changelog, see
|
||||
https://github.com/matrix-org/matrix-doc/blob/master/changelogs/identity_service.rst
|
||||
|
||||
|
||||
Other versions of this specification
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following other versions are also available, in reverse chronological order:
|
||||
|
||||
- `HEAD <https://matrix.org/docs/spec/identity_service/unstable.html>`_: Includes all changes since the latest versioned release.
|
||||
|
||||
General principles
|
||||
------------------
|
||||
|
||||
|
@ -56,7 +71,7 @@ is left as an exercise for the client.
|
|||
|
||||
3PID types are described in `3PID Types`_ Appendix.
|
||||
|
||||
API Standards
|
||||
API standards
|
||||
-------------
|
||||
|
||||
The mandatory baseline for identity service communication in Matrix is exchanging
|
||||
|
@ -136,6 +151,22 @@ should allow a 3pid to be mapped to a Matrix user identity, but not in the other
|
|||
direction (i.e. one should not be able to get all 3pids associated with a Matrix
|
||||
user ID, or get all 3pids associated with a 3pid).
|
||||
|
||||
Web browser clients
|
||||
-------------------
|
||||
|
||||
It is realistic to expect that some clients will be written to be run within a web
|
||||
browser or similar environment. In these cases, the identity service should respond to
|
||||
pre-flight requests and supply Cross-Origin Resource Sharing (CORS) headers on all
|
||||
requests.
|
||||
|
||||
When a client approaches the server with a pre-flight (OPTIONS) request, the server
|
||||
should respond with the CORS headers for that route. The recommended CORS headers
|
||||
to be returned by servers on all requests are::
|
||||
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
||||
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
|
||||
|
||||
Status check
|
||||
------------
|
||||
|
||||
|
@ -146,25 +177,24 @@ Key management
|
|||
|
||||
An identity service has some long-term public-private keypairs. These are named
|
||||
in a scheme ``algorithm:identifier``, e.g. ``ed25519:0``. When signing an
|
||||
association, the Matrix standard JSON signing format is used, as specified in
|
||||
the server-server API specification under the heading "Signing Events".
|
||||
association, the standard `Signing JSON`_ algorithm applies.
|
||||
|
||||
In the event of key compromise, the identity service may revoke any of its keys.
|
||||
An HTTP API is offered to get public keys, and check whether a particular key is
|
||||
valid.
|
||||
|
||||
The identity server may also keep track of some short-term public-private
|
||||
The identity service may also keep track of some short-term public-private
|
||||
keypairs, which may have different usage and lifetime characteristics than the
|
||||
service's long-term keys.
|
||||
|
||||
{{pubkey_is_http_api}}
|
||||
|
||||
Association Lookup
|
||||
Association lookup
|
||||
------------------
|
||||
|
||||
{{lookup_is_http_api}}
|
||||
|
||||
Establishing Associations
|
||||
Establishing associations
|
||||
-------------------------
|
||||
|
||||
The flow for creating an association is session-based.
|
||||
|
@ -183,6 +213,12 @@ session, within a 24 hour period since its most recent modification. Any
|
|||
attempts to perform these actions after the expiry will be rejected, and a new
|
||||
session should be created and used instead.
|
||||
|
||||
To start a session, the client makes a request to the appropriate ``/requestToken``
|
||||
endpoint. The user then receives a validation token which should be provided
|
||||
to the client. The client then provides the token to the appropriate ``/submitToken``
|
||||
endpoint, completing the session. At this point, the client should ``/bind`` the
|
||||
third party identifier or leave it for another entity to bind.
|
||||
|
||||
Email associations
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -198,53 +234,31 @@ General
|
|||
|
||||
{{associations_is_http_api}}
|
||||
|
||||
Invitation Storage
|
||||
Invitation storage
|
||||
------------------
|
||||
|
||||
An identity service can store pending invitations to a user's 3pid, which will
|
||||
be retrieved and can be either notified on or look up when the 3pid is
|
||||
associated with a Matrix user ID.
|
||||
|
||||
At a later point, if the owner of that particular 3pid binds it with a Matrix user ID, the identity server will attempt to make an HTTP POST to the Matrix user's homeserver which looks roughly as below::
|
||||
|
||||
POST https://bar.com:8448/_matrix/federation/v1/3pid/onbind
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"medium": "email",
|
||||
"address": "foo@bar.baz",
|
||||
"mxid": "@alice:example.tld",
|
||||
"invites": [
|
||||
{
|
||||
"medium": "email",
|
||||
"address": "foo@bar.baz",
|
||||
"mxid": "@alice:example.tld",
|
||||
"room_id": "!something:example.tld",
|
||||
"sender": "@bob:example.tld",
|
||||
"signed": {
|
||||
"mxid": "@alice:example.tld",
|
||||
"signatures": {
|
||||
"vector.im": {
|
||||
"ed25519:0": "somesignature"
|
||||
}
|
||||
},
|
||||
"token": "sometoken"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Where the signature is produced using a long-term private key.
|
||||
At a later point, if the owner of that particular 3pid binds it with a Matrix user
|
||||
ID, the identity service will attempt to make an HTTP POST to the Matrix user's
|
||||
homeserver via the `/3pid/onbind`_ endpoint. The request MUST be signed with a
|
||||
long-term private key for the identity service.
|
||||
|
||||
{{store_invite_is_http_api}}
|
||||
|
||||
Ephemeral invitation signing
|
||||
----------------------------
|
||||
|
||||
To aid clients who may not be able to perform crypto themselves, the identity service offers some crypto functionality to help in accepting invitations.
|
||||
This is less secure than the client doing it itself, but may be useful where this isn't possible.
|
||||
To aid clients who may not be able to perform crypto themselves, the identity
|
||||
service offers some crypto functionality to help in accepting invitations.
|
||||
This is less secure than the client doing it itself, but may be useful where
|
||||
this isn't possible.
|
||||
|
||||
{{invitation_signing_is_http_api}}
|
||||
|
||||
.. _`Unpadded Base64`: ../appendices.html#unpadded-base64
|
||||
.. _`3PID Types`: ../appendices.html#pid-types
|
||||
.. _`Signing JSON`: ../appendices.html#signing-json
|
||||
.. _`/3pid/onbind`: ../server_server/unstable.html#put-matrix-federation-v1-3pid-onbind
|
||||
|
|
|
@ -64,13 +64,27 @@ request.
|
|||
.. contents:: Table of Contents
|
||||
.. sectnum::
|
||||
|
||||
Specification version
|
||||
---------------------
|
||||
Changelog
|
||||
---------
|
||||
|
||||
.. topic:: Version: %SERVER_RELEASE_LABEL%
|
||||
{{server_server_changelog}}
|
||||
|
||||
This version of the specification is generated from
|
||||
`matrix-doc <https://github.com/matrix-org/matrix-doc>`_ as of Git commit
|
||||
`{{git_version}} <https://github.com/matrix-org/matrix-doc/tree/{{git_rev}}>`_.
|
||||
|
||||
For the full historical changelog, see
|
||||
https://github.com/matrix-org/matrix-doc/blob/master/changelogs/server_server.rst
|
||||
|
||||
|
||||
Other versions of this specification
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following other versions are also available, in reverse chronological order:
|
||||
|
||||
- `HEAD <https://matrix.org/docs/spec/server_server/unstable.html>`_: Includes all changes since the latest versioned release.
|
||||
|
||||
Server discovery
|
||||
----------------
|
||||
|
||||
|
@ -112,7 +126,7 @@ Server implementation
|
|||
|
||||
{{version_ss_http_api}}
|
||||
|
||||
Retrieving Server Keys
|
||||
Retrieving server keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. NOTE::
|
||||
|
@ -978,152 +992,127 @@ Signing Events
|
|||
Signing events is complicated by the fact that servers can choose to redact
|
||||
non-essential parts of an event.
|
||||
|
||||
Before signing the event, the ``unsigned`` and ``signature`` members are
|
||||
removed, it is encoded as `Canonical JSON`_, and then hashed using SHA-256. The
|
||||
resulting hash is then stored in the event JSON in a ``hash`` object under a
|
||||
``sha256`` key.
|
||||
Adding hashes and signatures to outgoing events
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Before signing the event, the *content hash* of the event is calculated as
|
||||
described below. The hash is encoded using `Unpadded Base64`_ and stored in the
|
||||
event object, in a ``hashes`` object, under a ``sha256`` key.
|
||||
|
||||
The event object is then *redacted*, following the `redaction
|
||||
algorithm`_. Finally it is signed as described in `Signing JSON`_, using the
|
||||
server's signing key (see also `Retrieving server keys`_).
|
||||
|
||||
The signature is then copied back to the original event object.
|
||||
|
||||
See `Persistent Data Unit schema`_ for an example of a signed event.
|
||||
|
||||
|
||||
Validating hashes and signatures on received events
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
When a server receives an event over federation from another server, the
|
||||
receiving server should check the hashes and signatures on that event.
|
||||
|
||||
First the signature is checked. The event is redacted following the `redaction
|
||||
algorithm`_, and the resultant object is checked for a signature from the
|
||||
originating server, following the algorithm described in `Checking for a signature`_.
|
||||
Note that this step should succeed whether we have been sent the full event or
|
||||
a redacted copy.
|
||||
|
||||
If the signature is found to be valid, the expected content hash is calculated
|
||||
as described below. The content hash in the ``hashes`` property of the received
|
||||
event is base64-decoded, and the two are compared for equality.
|
||||
|
||||
If the hash check fails, then it is assumed that this is because we have only
|
||||
been given a redacted version of the event. To enforce this, the receiving
|
||||
server should use the redacted copy it calculated rather than the full copy it
|
||||
received.
|
||||
|
||||
Calculating the content hash for an event
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The *content hash* of an event covers the complete event including the
|
||||
*unredacted* contents. It is calculated as follows.
|
||||
|
||||
First, any existing ``unsigned``, ``signature``, and ``hashes`` members are
|
||||
removed. The resulting object is then encoded as `Canonical JSON`_, and the
|
||||
JSON is hashed using SHA-256.
|
||||
|
||||
|
||||
Example code
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
|
||||
def hash_event(event_json_object):
|
||||
|
||||
# Keys under "unsigned" can be modified by other servers.
|
||||
# They are useful for conveying information like the age of an
|
||||
# event that will change in transit.
|
||||
# Since they can be modifed we need to exclude them from the hash.
|
||||
unsigned = event_json_object.pop("unsigned", None)
|
||||
|
||||
# Signatures will depend on the current value of the "hashes" key.
|
||||
# We cannot add new hashes without invalidating existing signatures.
|
||||
signatures = event_json_object.pop("signatures", None)
|
||||
|
||||
# The "hashes" key might contain multiple algorithms if we decide to
|
||||
# migrate away from SHA-2. We don't want to include an existing hash
|
||||
# output in our hash so we exclude the "hashes" dict from the hash.
|
||||
hashes = event_json_object.pop("hashes", {})
|
||||
|
||||
# Encode the JSON using a canonical encoding so that we get the same
|
||||
# bytes on every server for the same JSON object.
|
||||
event_json_bytes = encode_canonical_json(event_json_bytes)
|
||||
|
||||
# Add the base64 encoded bytes of the hash to the "hashes" dict.
|
||||
hashes["sha256"] = encode_base64(sha256(event_json_bytes).digest())
|
||||
|
||||
# Add the "hashes" dict back the event JSON under a "hashes" key.
|
||||
event_json_object["hashes"] = hashes
|
||||
if unsigned is not None:
|
||||
event_json_object["unsigned"] = unsigned
|
||||
return event_json_object
|
||||
|
||||
The event is then stripped of all non-essential keys both at the top level and
|
||||
within the ``content`` object. Any top-level keys not in the following list
|
||||
MUST be removed:
|
||||
|
||||
.. code::
|
||||
|
||||
auth_events
|
||||
depth
|
||||
event_id
|
||||
hashes
|
||||
membership
|
||||
origin
|
||||
origin_server_ts
|
||||
prev_events
|
||||
prev_state
|
||||
room_id
|
||||
sender
|
||||
signatures
|
||||
state_key
|
||||
type
|
||||
|
||||
A new ``content`` object is constructed for the resulting event that contains
|
||||
only the essential keys of the original ``content`` object. If the original
|
||||
event lacked a ``content`` object at all, a new empty JSON object is created
|
||||
for it.
|
||||
|
||||
The keys that are considered essential for the ``content`` object depend on the
|
||||
the ``type`` of the event. These are:
|
||||
|
||||
.. code::
|
||||
|
||||
type is "m.room.aliases":
|
||||
aliases
|
||||
|
||||
type is "m.room.create":
|
||||
creator
|
||||
|
||||
type is "m.room.history_visibility":
|
||||
history_visibility
|
||||
|
||||
type is "m.room.join_rules":
|
||||
join_rule
|
||||
|
||||
type is "m.room.member":
|
||||
membership
|
||||
|
||||
type is "m.room.power_levels":
|
||||
ban
|
||||
events
|
||||
events_default
|
||||
kick
|
||||
redact
|
||||
state_default
|
||||
users
|
||||
users_default
|
||||
|
||||
The resulting stripped object with the new ``content`` object and the original
|
||||
``hashes`` key is then signed using the JSON signing algorithm outlined below:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def sign_event(event_json_object, name, key):
|
||||
|
||||
# Make sure the event has a "hashes" key.
|
||||
if "hashes" not in event_json_object:
|
||||
event_json_object = hash_event(event_json_object)
|
||||
def hash_and_sign_event(event_object, signing_key, signing_name):
|
||||
# First we need to hash the event object.
|
||||
content_hash = compute_content_hash(event_object)
|
||||
event_object["hashes"] = {"sha256": encode_unpadded_base64(content_hash)}
|
||||
|
||||
# Strip all the keys that would be removed if the event was redacted.
|
||||
# The hashes are not stripped and cover all the keys in the event.
|
||||
# This means that we can tell if any of the non-essential keys are
|
||||
# modified or removed.
|
||||
stripped_json_object = strip_non_essential_keys(event_json_object)
|
||||
stripped_object = strip_non_essential_keys(event_object)
|
||||
|
||||
# Sign the stripped JSON object. The signature only covers the
|
||||
# essential keys and the hashes. This means that we can check the
|
||||
# signature even if the event is redacted.
|
||||
signed_json_object = sign_json(stripped_json_object)
|
||||
signed_object = sign_json(stripped_object, signing_key, signing_name)
|
||||
|
||||
# Copy the signatures from the stripped event to the original event.
|
||||
event_json_object["signatures"] = signed_json_oject["signatures"]
|
||||
return event_json_object
|
||||
event_object["signatures"] = signed_object["signatures"]
|
||||
|
||||
Servers can then transmit the entire event or the event with the non-essential
|
||||
keys removed. If the entire event is present, receiving servers can then check
|
||||
the event by computing the SHA-256 of the event, excluding the ``hash`` object.
|
||||
If the keys have been redacted, then the ``hash`` object is included when
|
||||
calculating the SHA-256 hash instead.
|
||||
def compute_content_hash(event_object):
|
||||
# take a copy of the event before we remove any keys.
|
||||
event_object = dict(event_object)
|
||||
|
||||
New hash functions can be introduced by adding additional keys to the ``hash``
|
||||
object. Since the ``hash`` object cannot be redacted a server shouldn't allow
|
||||
too many hashes to be listed, otherwise a server might embed illict data within
|
||||
the ``hash`` object. For similar reasons a server shouldn't allow hash values
|
||||
that are too long.
|
||||
# Keys under "unsigned" can be modified by other servers.
|
||||
# They are useful for conveying information like the age of an
|
||||
# event that will change in transit.
|
||||
# Since they can be modifed we need to exclude them from the hash.
|
||||
event_object.pop("unsigned", None)
|
||||
|
||||
# Signatures will depend on the current value of the "hashes" key.
|
||||
# We cannot add new hashes without invalidating existing signatures.
|
||||
event_object.pop("signatures", None)
|
||||
|
||||
# The "hashes" key might contain multiple algorithms if we decide to
|
||||
# migrate away from SHA-2. We don't want to include an existing hash
|
||||
# output in our hash so we exclude the "hashes" dict from the hash.
|
||||
event_object.pop("hashes", None)
|
||||
|
||||
# Encode the JSON using a canonical encoding so that we get the same
|
||||
# bytes on every server for the same JSON object.
|
||||
event_json_bytes = encode_canonical_json(event_object)
|
||||
|
||||
return hashlib.sha256(event_json_bytes)
|
||||
|
||||
.. TODO
|
||||
[[TODO(markjh): We might want to specify a maximum number of keys for the
|
||||
``hash`` and we might want to specify the maximum output size of a hash]]
|
||||
[[TODO(markjh) We might want to allow the server to omit the output of well
|
||||
known hash functions like SHA-256 when none of the keys have been redacted]]
|
||||
|
||||
[[TODO(markjh): Since the ``hash`` object cannot be redacted a server
|
||||
shouldn't allow too many hashes to be listed, otherwise a server might embed
|
||||
illict data within the ``hash`` object.
|
||||
|
||||
We might want to specify a maximum number of keys for the
|
||||
``hash`` and we might want to specify the maximum output size of a hash]]
|
||||
|
||||
[[TODO(markjh) We might want to allow the server to omit the output of well
|
||||
known hash functions like SHA-256 when none of the keys have been redacted]]
|
||||
|
||||
|
||||
.. |/query/directory| replace:: ``/query/directory``
|
||||
.. _/query/directory: #get-matrix-federation-v1-query-directory
|
||||
|
||||
.. _`Invitation storage`: ../identity_service/unstable.html#invitation-storage
|
||||
.. _`Identity Service API`: ../identity_service/unstable.html
|
||||
.. _`Invitation storage`: ../identity_service/%IDENTITY_RELEASE_LABEL%.html#invitation-storage
|
||||
.. _`Identity Service API`: ../identity_service/%IDENTITY_RELEASE_LABEL%.html
|
||||
.. _`Client-Server API`: ../client_server/%CLIENT_RELEASE_LABEL%.html
|
||||
.. _`Inviting to a room`: #inviting-to-a-room
|
||||
.. _`Canonical JSON`: ../appendices.html#canonical-json
|
||||
.. _`Unpadded Base64`: ../appendices.html#unpadded-base64
|
||||
.. _`Server ACLs`: ../client_server/unstable.html#module-server-acls
|
||||
.. _`redaction algorithm`: ../client_server/unstable.html#redactions
|
||||
.. _`Signing JSON`: ../appendices.html#signing-json
|
||||
.. _`Checking for a signature`: ../appendices.html#checking-for-a-signature
|
||||
.. _`Device Management module`: ../client-server/%CLIENT_RELEASE_LABEL%.html#device-management
|
||||
.. _`End-to-End Encryption module`: ../client-server/%CLIENT_RELEASE_LABEL%.html#end-to-end-encryption
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue