summary refs log tree commit diff
path: root/docs/model
diff options
context:
space:
mode:
authormatrix.org <matrix@matrix.org>2014-08-12 15:10:52 +0100
committermatrix.org <matrix@matrix.org>2014-08-12 15:10:52 +0100
commit4f475c7697722e946e39e42f38f3dd03a95d8765 (patch)
tree076d96d3809fb836c7245fd9f7960e7b75888a77 /docs/model
downloadsynapse-4f475c7697722e946e39e42f38f3dd03a95d8765.tar.xz
Reference Matrix Home Server
Diffstat (limited to 'docs/model')
-rw-r--r--docs/model/presence249
-rw-r--r--docs/model/profiles232
-rw-r--r--docs/model/room-join-workflow113
-rw-r--r--docs/model/rooms274
-rw-r--r--docs/model/third-party-id108
5 files changed, 976 insertions, 0 deletions
diff --git a/docs/model/presence b/docs/model/presence
new file mode 100644
index 0000000000..7e54505364
--- /dev/null
+++ b/docs/model/presence
@@ -0,0 +1,249 @@
+========
+Presence
+========
+
+A description of presence information and visibility between users.
+
+Overview
+========
+
+Each user has the concept of Presence information. This encodes a sense of the
+"availability" of that user, suitable for display on other user's clients.
+
+
+Presence Information
+====================
+
+The basic piece of presence information is an enumeration of a small set of
+state; such as "free to chat", "online", "busy", or "offline". The default state
+unless the user changes it is "online". Lower states suggest some amount of
+decreased availability from normal, which might have some client-side effect
+like muting notification sounds and suggests to other users not to bother them
+unless it is urgent. Equally, the "free to chat" state exists to let the user
+announce their general willingness to receive messages moreso than default.
+
+Home servers should also allow a user to set their state as "hidden" - a state
+which behaves as offline, but allows the user to see the client state anyway and
+generally interact with client features such as reading message history or
+accessing contacts in the address book.
+
+This basic state field applies to the user as a whole, regardless of how many
+client devices they have connected. The home server should synchronise this
+status choice among multiple devices to ensure the user gets a consistent
+experience.
+
+Idle Time
+---------
+
+As well as the basic state field, the presence information can also show a sense
+of an "idle timer". This should be maintained individually by the user's
+clients, and the homeserver can take the highest reported time as that to
+report. Likely this should be presented in fairly coarse granularity; possibly
+being limited to letting the home server automatically switch from a "free to
+chat" or "online" mode into "idle".
+
+When a user is offline, the Home Server can still report when the user was last
+seen online, again perhaps in a somewhat coarse manner.
+
+Device Type
+-----------
+
+Client devices that may limit the user experience somewhat (such as "mobile"
+devices with limited ability to type on a real keyboard or read large amounts of
+text) should report this to the home server, as this is also useful information
+to report as "presence" if the user cannot be expected to provide a good typed
+response to messages.
+
+
+Presence List
+=============
+
+Each user's home server stores a "presence list" for that user. This stores a
+list of other user IDs the user has chosen to add to it (remembering any ACL
+Pointer if appropriate).
+
+To be added to a contact list, the user being added must grant permission. Once
+granted, both user's HS(es) store this information, as it allows the user who
+has added the contact some more abilities; see below. Since such subscriptions
+are likely to be bidirectional, HSes may wish to automatically accept requests
+when a reverse subscription already exists.
+
+As a convenience, presence lists should support the ability to collect users
+into groups, which could allow things like inviting the entire group to a new
+("ad-hoc") chat room, or easy interaction with the profile information ACL
+implementation of the HS.
+
+
+Presence and Permissions
+========================
+
+For a viewing user to be allowed to see the presence information of a target
+user, either
+
+ * The target user has allowed the viewing user to add them to their presence
+   list, or
+
+ * The two users share at least one room in common
+
+In the latter case, this allows for clients to display some minimal sense of
+presence information in a user list for a room.
+
+Home servers can also use the user's choice of presence state as a signal for
+how to handle new private one-to-one chat message requests. For example, it
+might decide:
+
+  "free to chat": accept anything
+  "online": accept from anyone in my addres book list
+  "busy": accept from anyone in this "important people" group in my address
+    book list
+
+
+API Efficiency
+==============
+
+A simple implementation of presence messaging has the ability to cause a large
+amount of Internet traffic relating to presence updates. In order to minimise
+the impact of such a feature, the following observations can be made:
+
+ * There is no point in a Home Server polling status for peers in a user's
+   presence list if the user has no clients connected that care about it.
+
+ * It is highly likely that most presence subscriptions will be symmetric - a
+   given user watching another is likely to in turn be watched by that user.
+
+ * It is likely that most subscription pairings will be between users who share
+   at least one Room in common, and so their Home Servers are actively
+   exchanging message PDUs or transactions relating to that Room.
+
+ * Presence update messages do not need realtime guarantees. It is acceptable to
+   delay delivery of updates for some small amount of time (10 seconds to a
+   minute).
+
+The general model of presence information is that of a HS registering its
+interest in receiving presence status updates from other HSes, which then
+promise to send them when required. Rather than actively polling for the
+currentt state all the time, HSes can rely on their relative stability to only
+push updates when required.
+
+A Home Server should not rely on the longterm validity of this presence
+information, however, as this would not cover such cases as a user's server
+crashing and thus failing to inform their peers that users it used to host are
+no longer available online. Therefore, each promise of future updates should
+carry with a timeout value (whether explicit in the message, or implicit as some
+defined default in the protocol), after which the receiving HS should consider
+the information potentially stale and request it again.
+
+However, because of the likelyhood that two home servers are exchanging messages
+relating to chat traffic in a room common to both of them, the ongoing receipt
+of these messages can be taken by each server as an implicit notification that
+the sending server is still up and running, and therefore that no status changes
+have happened; because if they had the server would have sent them. A second,
+larger timeout should be applied to this implicit inference however, to protect
+against implementation bugs or other reasons that the presence state cache may
+become invalid; eventually the HS should re-enquire the current state of users
+and update them with its own.
+
+The following workflows can therefore be used to handle presence updates:
+
+ 1 When a user first appears online their HS sends a message to each other HS
+   containing at least one user to be watched; each message carrying both a
+   notification of the sender's new online status, and a request to obtain and
+   watch the target users' presence information. This message implicitly
+   promises the sending HS will now push updates to the target HSes.
+
+ 2 The target HSes then respond a single message each, containing the current
+   status of the requested user(s). These messages too implicitly promise the
+   target HSes will themselves push updates to the sending HS.
+
+   As these messages arrive at the sending user's HS they can be pushed to the
+   user's client(s), possibly batched again to ensure not too many small
+   messages which add extra protocol overheads.
+
+At this point, all the user's clients now have the current presence status
+information for this moment in time, and have promised to send each other
+updates in future.
+
+ 3 The HS maintains two watchdog timers per peer HS it is exchanging presence
+   information with. The first timer should have a relatively small expiry
+   (perhaps 1 minute), and the second timer should have a much longer time
+   (perhaps 1 hour).
+
+ 4 Any time any kind of message is received from a peer HS, the short-term
+   presence timer associated with it is reset.
+
+ 5 Whenever either of these timers expires, an HS should push a status reminder
+   to the target HS whose timer has now expired, and request again from that
+   server the status of the subscribed users.
+
+ 6 On receipt of one of these presence status reminders, an HS can reset both
+   of its presence watchdog timers.
+
+To avoid bursts of traffic, implementations should attempt to stagger the expiry
+of the longer-term watchdog timers for different peer HSes.
+
+When individual users actively change their status (either by explicit requests
+from clients, or inferred changes due to idle timers or client timeouts), the HS
+should batch up any status changes for some reasonable amount of time (10
+seconds to a minute). This allows for reduced protocol overheads in the case of
+multiple messages needing to be sent to the same peer HS; as is the likely
+scenario in many cases, such as a given human user having multiple user
+accounts.
+
+
+API Requirements
+================
+
+The data model presented here puts the following requirements on the APIs:
+
+Client-Server
+-------------
+
+Requests that a client can make to its Home Server
+
+ * get/set current presence state
+   Basic enumeration + ability to set a custom piece of text
+
+ * report per-device idle time
+   After some (configurable?) idle time the device should send a single message
+   to set the idle duration. The HS can then infer a "start of idle" instant and
+   use that to keep the device idleness up to date. At some later point the
+   device can cancel this idleness.
+
+ * report per-device type
+   Inform the server that this device is a "mobile" device, or perhaps some
+   other to-be-defined category of reduced capability that could be presented to
+   other users.
+
+ * start/stop presence polling for my presence list
+   It is likely that these messages could be implicitly inferred by other
+   messages, though having explicit control is always useful.
+
+ * get my presence list
+   [implicit poll start?]
+   It is possible that the HS doesn't yet have current presence information when
+   the client requests this. There should be a "don't know" type too.
+
+ * add/remove a user to my presence list
+
+Server-Server
+-------------
+
+Requests that Home Servers make to others
+
+ * request permission to add a user to presence list
+
+ * allow/deny a request to add to a presence list
+
+ * perform a combined presence state push and subscription request
+   For each sending user ID, the message contains their new status.
+   For each receiving user ID, the message should contain an indication on
+   whether the sending server is also interested in receiving status from that
+   user; either as an immediate update response now, or as a promise to send
+   future updates.
+
+Server to Client
+----------------
+
+[[TODO(paul): There also needs to be some way for a user's HS to push status
+updates of the presence list to clients, but the general server-client event
+model currently lacks a space to do that.]]
diff --git a/docs/model/profiles b/docs/model/profiles
new file mode 100644
index 0000000000..f7d6bd5679
--- /dev/null
+++ b/docs/model/profiles
@@ -0,0 +1,232 @@
+========
+Profiles
+========
+
+A description of Synapse user profile metadata support.
+
+
+Overview
+========
+
+Internally within Synapse users are referred to by an opaque ID, which consists
+of some opaque localpart combined with the domain name of their home server.
+Obviously this does not yield a very nice user experience; users would like to
+see readable names for other users that are in some way meaningful to them.
+Additionally, users like to be able to publish "profile" details to inform other
+users of other information about them.
+
+It is also conceivable that since we are attempting to provide a
+worldwide-applicable messaging system, that users may wish to present different
+subsets of information in their profile to different other people, from a
+privacy and permissions perspective.
+
+A Profile consists of a display name, an (optional?) avatar picture, and a set
+of other metadata fields that the user may wish to publish (email address, phone
+numbers, website URLs, etc...). We put no requirements on the display name other
+than it being a valid Unicode string. Since it is likely that users will end up
+having multiple accounts (perhaps by necessity of being hosted in multiple
+places, perhaps by choice of wanting multiple distinct identifies), it would be
+useful that a metadata field type exists that can refer to another Synapse User
+ID, so that clients and HSes can make use of this information.
+
+Metadata Fields
+---------------
+
+[[TODO(paul): Likely this list is incomplete; more fields can be defined as we
+think of them. At the very least, any sort of supported ID for the 3rd Party ID
+servers should be accounted for here.]]
+
+ * Synapse Directory Server username(s)
+
+ * Email address
+
+ * Phone number - classify "home"/"work"/"mobile"/custom?
+ 
+ * Twitter/Facebook/Google+/... social networks
+
+ * Location - keep this deliberately vague to allow people to choose how
+     granular it is
+ 
+ * "Bio" information - date of birth, etc...
+
+ * Synapse User ID of another account
+
+ * Web URL
+
+ * Freeform description text
+
+
+Visibility Permissions
+======================
+
+A home server implementation could offer the ability to set permissions on
+limited visibility of those fields. When another user requests access to the
+target user's profile, their own identity should form part of that request. The
+HS implementation can then decide which fields to make available to the
+requestor.
+
+A particular detail of implementation could allow the user to create one or more
+ACLs; where each list is granted permission to see a given set of non-public
+fields (compare to Google+ Circles) and contains a set of other people allowed
+to use it. By giving these ACLs strong identities within the HS, they can be
+referenced in communications with it, granting other users who encounter these
+the "ACL Token" to use the details in that ACL.
+
+If we further allow an ACL Token to be present on Room join requests or stored
+by 3PID servers, then users of these ACLs gain the extra convenience of not
+having to manually curate people in the access list; anyone in the room or with
+knowledge of the 3rd Party ID is automatically granted access. Every HS and
+client implementation would have to be aware of the existence of these ACL
+Token, and include them in requests if present, but not every HS implementation
+needs to actually provide the full permissions model. This can be used as a
+distinguishing feature among competing implementations. However, servers MUST
+NOT serve profile information from a cache if there is a chance that its limited
+understanding could lead to information leakage.
+
+
+Client Concerns of Multiple Accounts
+====================================
+
+Because a given person may want to have multiple Synapse User accounts, client
+implementations should allow the use of multiple accounts simultaneously
+(especially in the field of mobile phone clients, which generally don't support
+running distinct instances of the same application). Where features like address
+books, presence lists or rooms are presented, the client UI should remember to
+make distinct with user account is in use for each.
+
+
+Directory Servers
+=================
+
+Directory Servers can provide a forward mapping from human-readable names to
+User IDs. These can provide a service similar to giving domain-namespaced names
+for Rooms; in this case they can provide a way for a user to reference their
+User ID in some external form (e.g. that can be printed on a business card).
+
+The format for Synapse user name will consist of a localpart specific to the
+directory server, and the domain name of that directory server:
+
+  @localname:some.domain.name
+
+The localname is separated from the domain name using a colon, so as to ensure
+the localname can still contain periods, as users may want this for similarity
+to email addresses or the like, which typically can contain them. The format is
+also visually quite distinct from email addresses, phone numbers, etc... so
+hopefully reasonably "self-describing" when written on e.g. a business card
+without surrounding context.
+
+[[TODO(paul): we might have to think about this one - too close to email?
+  Twitter? Also it suggests a format scheme for room names of
+  #localname:domain.name, which I quite like]]
+
+Directory server administrators should be able to make some kind of policy
+decision on how these are allocated. Servers within some "closed" domain (such
+as company-specific ones) may wish to verify the validity of a mapping using
+their own internal mechanisms; "public" naming servers can operate on a FCFS
+basis. There are overlapping concerns here with the idea of the 3rd party
+identity servers as well, though in this specific case we are creating a new
+namespace to allocate names into.
+
+It would also be nice from a user experience perspective if the profile that a
+given name links to can also declare that name as part of its metadata.
+Furthermore as a security and consistency perspective it would be nice if each
+end (the directory server and the user's home server) check the validity of the
+mapping in some way. This needs investigation from a security perspective to
+ensure against spoofing.
+
+One such model may be that the user starts by declaring their intent to use a
+given user name link to their home server, which then contacts the directory
+service. At some point later (maybe immediately for "public open FCFS servers",
+maybe after some kind of human intervention for verification) the DS decides to
+honour this link, and includes it in its served output. It should also tell the
+HS of this fact, so that the HS can present this as fact when requested for the
+profile information. For efficiency, it may further wish to provide the HS with
+a cryptographically-signed certificate as proof, so the HS serving the profile
+can provide that too when asked, avoiding requesting HSes from constantly having
+to contact the DS to verify this mapping. (Note: This is similar to the security
+model often applied in DNS to verify PTR <-> A bidirectional mappings).
+
+
+Identity Servers
+================
+
+The identity servers should support the concept of pointing a 3PID being able to
+store an ACL Token as well as the main User ID. It is however, beyond scope to
+do any kind of verification that any third-party IDs that the profile is
+claiming match up to the 3PID mappings.
+
+
+User Interface and Expectations Concerns
+========================================
+
+Given the weak "security" of some parts of this model as compared to what users
+might expect, some care should be taken on how it is presented to users,
+specifically in the naming or other wording of user interface components.
+
+Most notably mere knowledge of an ACL Pointer is enough to read the information
+stored in it. It is possible that Home or Identity Servers could leak this
+information, allowing others to see it. This is a security-vs-convenience
+balancing choice on behalf of the user who would choose, or not, to make use of
+such a feature to publish their information.
+
+Additionally, unless some form of strong end-to-end user-based encryption is
+used, a user of ACLs for information privacy has to trust other home servers not
+to lie about the identify of the user requesting access to the Profile.
+
+
+API Requirements
+================
+
+The data model presented here puts the following requirements on the APIs:
+
+Client-Server
+-------------
+
+Requests that a client can make to its Home Server
+
+ * get/set my Display Name
+   This should return/take a simple "text/plain" field
+
+ * get/set my Avatar URL
+   The avatar image data itself is not stored by this API; we'll just store a
+   URL to let the clients fetch it. Optionally HSes could integrate this with
+   their generic content attacmhent storage service, allowing a user to set
+   upload their profile Avatar and update the URL to point to it.
+
+ * get/add/remove my metadata fields
+   Also we need to actually define types of metadata
+
+ * get another user's Display Name / Avatar / metadata fields
+
+[[TODO(paul): At some later stage we should consider the API for:
+
+ * get/set ACL permissions on my metadata fields
+
+ * manage my ACL tokens
+]]
+
+Server-Server
+-------------
+
+Requests that Home Servers make to others
+
+ * get a user's Display Name / Avatar
+
+ * get a user's full profile - name/avatar + MD fields
+   This request must allow for specifying the User ID of the requesting user,
+   for permissions purposes. It also needs to take into account any ACL Tokens
+   the requestor has.
+
+ * push a change of Display Name to observers (overlaps with the presence API)
+
+Room Event PDU Types
+--------------------
+
+Events that are pushed from Home Servers to other Home Servers or clients.
+
+ * user Display Name change
+ 
+ * user Avatar change
+   [[TODO(paul): should the avatar image itself be stored in all the room
+   histories? maybe this event should just be a hint to clients that they should
+   re-fetch the avatar image]]
diff --git a/docs/model/room-join-workflow b/docs/model/room-join-workflow
new file mode 100644
index 0000000000..c321a64fab
--- /dev/null
+++ b/docs/model/room-join-workflow
@@ -0,0 +1,113 @@
+==================
+Room Join Workflow
+==================
+
+An outline of the workflows required when a user joins a room.
+
+Discovery
+=========
+
+To join a room, a user has to discover the room by some mechanism in order to
+obtain the (opaque) Room ID and a candidate list of likely home servers that
+contain it.
+
+Sending an Invitation
+---------------------
+
+The most direct way a user discovers the existence of a room is from a
+invitation from some other user who is a member of that room.
+
+The inviter's HS sets the membership status of the invitee to "invited" in the
+"m.members" state key by sending a state update PDU. The HS then broadcasts this
+PDU among the existing members in the usual way. An invitation message is also
+sent to the invited user, containing the Room ID and the PDU ID of this
+invitation state change and potentially a list of some other home servers to use
+to accept the invite. The user's client can then choose to display it in some
+way to alert the user.
+
+[[TODO(paul): At present, no API has been designed or described to actually send
+that invite to the invited user. Likely it will be some facet of the larger
+user-user API required for presence, profile management, etc...]]
+
+Directory Service
+-----------------
+
+Alternatively, the user may discover the channel via a directory service; either
+by performing a name lookup, or some kind of browse or search acitivty. However
+this is performed, the end result is that the user's home server requests the
+Room ID and candidate list from the directory service.
+
+[[TODO(paul): At present, no API has been designed or described for this
+directory service]]
+
+
+Joining
+=======
+
+Once the ID and home servers are obtained, the user can then actually join the
+room.
+
+Accepting an Invite
+-------------------
+
+If a user has received and accepted an invitation to join a room, the invitee's
+home server can now send an invite acceptance message to a chosen candidate
+server from the list given in the invitation, citing also the PDU ID of the
+invitation as "proof" of their invite. (This is required as due to late message
+propagation it could be the case that the acceptance is received before the
+invite by some servers). If this message is allowed by the candidate server, it
+generates a new PDU that updates the invitee's membership status to "joined",
+referring back to the acceptance PDU, and broadcasts that as a state change in
+the usual way. The newly-invited user is now a full member of the room, and
+state propagation proceeds as usual.
+
+Joining a Public Room
+---------------------
+
+If a user has discovered the existence of a room they wish to join but does not
+have an active invitation, they can request to join it directly by sending a
+join message to a candidate server on the list provided by the directory
+service. As this list may be out of date, the HS should be prepared to retry
+other candidates if the chosen one is no longer aware of the room, because it
+has no users as members in it.
+
+Once a candidate server that is aware of the room has been found, it can
+broadcast an update PDU to add the member into the "m.members" key setting their
+state directly to "joined" (i.e. bypassing the two-phase invite semantics),
+remembering to include the new user's HS in that list.
+
+Knocking on a Semi-Public Room
+------------------------------
+
+If a user requests to join a room but the join mode of the room is "knock", the
+join is not immediately allowed. Instead, if the user wishes to proceed, they
+can instead post a "knock" message, which informs other members of the room that
+the would-be joiner wishes to become a member and sets their membership value to
+"knocked". If any of them wish to accept this, they can then send an invitation
+in the usual way described above. Knowing that the user has already knocked and
+expressed an interest in joining, the invited user's home server should
+immediately accept that invitation on the user's behalf, and go on to join the
+room in the usual way.
+
+[[NOTE(Erik): Though this may confuse users who expect 'X has joined' to
+actually be a user initiated action, i.e. they may expect that 'X' is actually
+looking at synapse right now?]]
+
+[[NOTE(paul): Yes, a fair point maybe we should suggest HSes don't do that, and
+just offer an invite to the user as normal]]
+
+Private and Non-Existent Rooms
+------------------------------
+
+If a user requests to join a room but the room is either unknown by the home
+server receiving the request, or is known by the join mode is "invite" and the
+user has not been invited, the server must respond that the room does not exist.
+This is to prevent leaking information about the existence and identity of
+private rooms.
+
+
+Outstanding Questions
+=====================
+
+ * Do invitations or knocks time out and expire at some point? If so when? Time
+   is hard in distributed systems.
diff --git a/docs/model/rooms b/docs/model/rooms
new file mode 100644
index 0000000000..0007e48e30
--- /dev/null
+++ b/docs/model/rooms
@@ -0,0 +1,274 @@
+===========
+Rooms Model
+===========
+
+A description of the general data model used to implement Rooms, and the
+user-level visible effects and implications.
+
+
+Overview
+========
+
+"Rooms" in Synapse are shared messaging channels over which all the participant
+users can exchange messages. Rooms have an opaque persistent identify, a
+globally-replicated set of state (consisting principly of a membership set of
+users, and other management and miscellaneous metadata), and a message history.
+
+
+Room Identity and Naming
+========================
+
+Rooms can be arbitrarily created by any user on any home server; at which point
+the home server will sign the message that creates the channel, and the
+fingerprint of this signature becomes the strong persistent identify of the
+room. This now identifies the room to any home server in the network regardless
+of its original origin. This allows the identify of the room to outlive any
+particular server. Subject to appropriate permissions [to be discussed later],
+any current member of a room can invite others to join it, can post messages
+that become part of its history, and can change the persistent state of the room
+(including its current set of permissions).
+
+Home servers can provide a directory service, allowing a lookup from a
+convenient human-readable form of room label to a room ID. This mapping is
+scoped to the particular home server domain and so simply represents that server
+administrator's opinion of what room should take that label; it does not have to
+be globally replicated and does not form part of the stored state of that room.
+
+This room name takes the form
+
+  #localname:some.domain.name
+
+for similarity and consistency with user names on directories.
+
+To join a room (and therefore to be allowed to inspect past history, post new
+messages to it, and read its state), a user must become aware of the room's
+fingerprint ID. There are two mechanisms to allow this:
+
+ * An invite message from someone else in the room
+
+ * A referral from a room directory service
+
+As room IDs are opaque and ephemeral, they can serve as a mechanism to create
+"ad-hoc" rooms deliberately unnamed, for small group-chats or even private
+one-to-one message exchange.
+
+
+Stored State and Permissions
+============================
+
+Every room has a globally-replicated set of stored state. This state is a set of
+key/value or key/subkey/value pairs. The value of every (sub)key is a
+JSON-representable object. The main key of a piece of stored state establishes
+its meaning; some keys store sub-keys to allow a sub-structure within them [more
+detail below]. Some keys have special meaning to Synapse, as they relate to
+management details of the room itself, storing such details as user membership,
+and permissions of users to alter the state of the room itself. Other keys may
+store information to present to users, which the system does not directly rely
+on. The key space itself is namespaced, allowing 3rd party extensions, subject
+to suitable permission.
+
+Permission management is based on the concept of "power-levels". Every user
+within a room has an integer assigned, being their "power-level" within that
+room. Along with its actual data value, each key (or subkey) also stores the
+minimum power-level a user must have in order to write to that key, the
+power-level of the last user who actually did write to it, and the PDU ID of
+that state change.
+
+To be accepted as valid, a change must NOT:
+
+ * Be made by a user having a power-level lower than required to write to the
+   state key
+
+ * Alter the required power-level for that state key to a value higher than the
+   user has
+
+ * Increase that user's own power-level
+
+ * Grant any other user a power-level higher than the level of the user making
+   the change
+
+[[TODO(paul): consider if relaxations should be allowed; e.g. is the current
+outright-winner allowed to raise their own level, to allow for "inflation"?]]
+
+
+Room State Keys
+===============
+
+[[TODO(paul): if this list gets too big it might become necessary to move it
+into its own doc]]
+
+The following keys have special semantics or meaning to Synapse itself:
+
+m.member (has subkeys)
+  Stores a sub-key for every Synapse User ID which is currently a member of
+  this room. Its value gives the membership type ("knocked", "invited",
+  "joined").
+
+m.power_levels
+  Stores a mapping from Synapse User IDs to their power-level in the room. If
+  they are not present in this mapping, the default applies.
+
+  The reason to store this as a single value rather than a value with subkeys
+  is that updates to it are atomic; allowing a number of colliding-edit
+  problems to be avoided.
+
+m.default_level
+  Gives the default power-level for members of the room that do not have one
+  specified in their membership key.
+
+m.invite_level
+  If set, gives the minimum power-level required for members to invite others
+  to join, or to accept knock requests from non-members requesting access. If
+  absent, then invites are not allowed. An invitation involves setting their
+  membership type to "invited", in addition to sending the invite message.
+
+m.join_rules
+  Encodes the rules on how non-members can join the room. Has the following
+  possibilities:
+    "public" - a non-member can join the room directly
+    "knock" - a non-member cannot join the room, but can post a single "knock"
+        message requesting access, which existing members may approve or deny
+    "invite" - non-members cannot join the room without an invite from an
+        existing member
+    "private" - nobody who is not in the 'may_join' list or already a member
+        may join by any mechanism
+
+  In any of the first three modes, existing members with sufficient permission
+  can send invites to non-members if allowed by the "m.invite_level" key. A
+  "private" room is not allowed to have the "m.invite_level" set.
+
+  A client may use the value of this key to hint at the user interface
+  expectations to provide; in particular, a private chat with one other use
+  might warrant specific handling in the client.
+
+m.may_join
+  A list of User IDs that are always allowed to join the room, regardless of any
+  of the prevailing join rules and invite levels. These apply even to private
+  rooms. These are stored in a single list with normal update-powerlevel
+  permissions applied; users cannot arbitrarily remove themselves from the list.
+
+m.add_state_level
+  The power-level required for a user to be able to add new state keys.
+
+m.public_history
+  If set and true, anyone can request the history of the room, without needing
+  to be a member of the room.
+
+m.archive_servers
+  For "public" rooms with public history, gives a list of home servers that
+  should be included in message distribution to the room, even if no users on
+  that server are present. These ensure that a public room can still persist
+  even if no users are currently members of it. This list should be consulted by
+  the dirctory servers as the candidate list they respond with.
+
+The following keys are provided by Synapse for user benefit, but their value is
+not otherwise used by Synapse.
+
+m.name
+  Stores a short human-readable name for the room, such that clients can display
+  to a user to assist in identifying which room is which.
+  
+  This name specifically is not the strong ID used by the message transport
+  system to refer to the room, because it may be changed from time to time.
+
+m.topic
+  Stores the current human-readable topic
+
+
+Room Creation Templates
+=======================
+
+A client (or maybe home server?) could offer a few templates for the creation of
+new rooms. For example, for a simple private one-to-one chat the channel could
+assign the creator a power-level of 1, requiring a level of 1 to invite, and
+needing an invite before members can join. An invite is then sent to the other
+party, and if accepted and the other user joins, the creator's power-level can
+now be reduced to 0. This now leaves a room with two participants in it being
+unable to add more.
+
+
+Rooms that Continue History
+===========================
+
+An option that could be considered for room creation, is that when a new room is
+created the creator could specify a PDU ID into an existing room, as the history
+continuation point. This would be stored as an extra piece of meta-data on the
+initial PDU of the room's creation. (It does not appear in the normal previous
+PDU linkage).
+
+This would allow users in rooms to "fork" a room, if it is considered that the
+conversations in the room no longer fit its original purpose, and wish to
+diverge. Existing permissions on the original room would continue to apply of
+course, for viewing that history. If both rooms are considered "public" we might
+also want to define a message to post into the original room to represent this
+fork point, and give a reference to the new room.
+
+
+User Direct Message Rooms
+=========================
+
+There is no need to build a mechanism for directly sending messages between
+users, because a room can handle this ability. To allow direct user-to-user chat
+messaging we simply need to be able to create rooms with specific set of
+permissions to allow this direct messaging.
+
+Between any given pair of user IDs that wish to exchange private messages, there
+will exist a single shared Room, created lazily by either side. These rooms will
+need a certain amount of special handling in both home servers and display on
+clients, but as much as possible should be treated by the lower layers of code
+the same as other rooms.
+
+Specially, a client would likely offer a special menu choice associated with
+another user (in room member lists, presence list, etc..) as "direct chat". That
+would perform all the necessary steps to create the private chat room. Receiving
+clients should display these in a special way too as the room name is not
+important; instead it should distinguish them on the Display Name of the other
+party.
+
+Home Servers will need a client-API option to request setting up a new user-user
+chat room, which will then need special handling within the server. It will
+create a new room with the following 
+
+  m.member: the proposing user
+  m.join_rules: "private"
+  m.may_join: both users
+  m.power_levels: empty
+  m.default_level: 0
+  m.add_state_level: 0
+  m.public_history: False
+
+Having created the room, it can send an invite message to the other user in the
+normal way - the room permissions state that no users can be set to the invited
+state, but because they're in the may_join list then they'd be allowed to join
+anyway.
+
+In this arrangement there is now a room with both users may join but neither has
+the power to invite any others. Both users now have the confidence that (at
+least within the messaging system itself) their messages remain private and
+cannot later be provably leaked to a third party. They can freely set the topic
+or name if they choose and add or edit any other state of the room. The update
+powerlevel of each of these fixed properties should be 1, to lock out the users
+from being able to alter them.
+
+
+Anti-Glare
+==========
+
+There exists the possibility of a race condition if two users who have no chat
+history with each other simultaneously create a room and invite the other to it.
+This is called a "glare" situation. There are two possible ideas for how to
+resolve this:
+
+ * Each Home Server should persist the mapping of (user ID pair) to room ID, so
+   that duplicate requests can be suppressed. On receipt of a room creation
+   request that the HS thinks there already exists a room for, the invitation to
+   join can be rejected if:
+      a) the HS believes the sending user is already a member of the room (and
+         maybe their HS has forgotten this fact), or
+      b) the proposed room has a lexicographically-higher ID than the existing
+         room (to resolve true race condition conflicts)
+      
+ * The room ID for a private 1:1 chat has a special form, determined by
+   concatenting the User IDs of both members in a deterministic order, such that
+   it doesn't matter which side creates it first; the HSes can just ignore
+   (or merge?) received PDUs that create the room twice.
diff --git a/docs/model/third-party-id b/docs/model/third-party-id
new file mode 100644
index 0000000000..1f8138ddf7
--- /dev/null
+++ b/docs/model/third-party-id
@@ -0,0 +1,108 @@
+======================
+Third Party Identities
+======================
+
+A description of how email addresses, mobile phone numbers and other third
+party identifiers can be used to authenticate and discover users in Matrix.
+
+
+Overview
+========
+
+New users need to authenticate their account. An email or SMS text message can 
+be a convenient form of authentication. Users already have email addresses 
+and phone numbers for contacts in their address book. They want to communicate
+with those contacts in Matrix without manually exchanging a Matrix User ID with 
+them.
+
+Third Party IDs
+---------------
+
+[[TODO(markjh): Describe the format of a 3PID]]
+
+
+Third Party ID Associations
+---------------------------
+
+An Associaton is a binding between a Matrix User ID and a Third Party ID (3PID).
+Each 3PID can be associated with one Matrix User ID at a time.
+
+[[TODO(markjh): JSON format of the association.]]
+
+Verification 
+------------
+
+An Assocation must be verified by a trusted Verification Server. Email 
+addresses and phone numbers can be verified by sending a token to the address 
+which a client can supply to the verifier to confirm ownership.
+
+An email Verification Server may be capable of verifying all email 3PIDs or may
+be restricted to verifying addresses for a particular domain. A phone number
+Verification Server may be capable of verifying all phone numbers or may be
+restricted to verifying numbers for a given country or phone prefix.
+
+Verification Servers fulfil a similar role to Certificate Authorities in PKI so
+a similar level of vetting should be required before clients trust their
+signatures.
+
+A Verification Server may wish to check for existing Associations for a 3PID 
+before creating a new Association.
+
+Discovery
+---------
+
+Users can discover Associations using a trusted Identity Server. Each 
+Association will be signed by the Identity Server. An Identity Server may store
+the entire space of Associations or may delegate to other Identity Servers when
+looking up Associations.
+
+Each Association returned from an Identity Server must be signed by a 
+Verification Server. Clients should check these signatures.
+
+Identity Servers fulfil a similar role to DNS servers.
+
+Privacy
+-------
+
+A User may publish the association between their phone number and Matrix User ID
+on the Identity Server without publishing the number in their Profile hosted on
+their Home Server.
+
+Identity Servers should refrain from publishing reverse mappings and should 
+take steps, such as rate limiting, to prevent attackers enumerating the space of
+mappings.
+
+Federation
+==========
+
+Delegation
+----------
+
+Verification Servers could delegate signing to another server by issuing 
+certificate to that server allowing it to verify and sign a subset of 3PID on 
+its behalf. It would be necessary to provide a language for describing which
+subset of 3PIDs that server had authority to validate. Alternatively it could 
+delegate the verification step to another server but sign the resulting
+association itself.
+
+The 3PID space will have a heirachical structure like DNS so Identity Servers
+can delegate lookups to other servers. An Identity Server should be prepared 
+to host or delegate any valid association within the subset of the 3PIDs it is 
+resonsible for.
+
+Multiple Root Verification Servers
+----------------------------------
+
+There can be multiple root Verification Servers and an Association could be
+signed by multiple servers if different clients trust different subsets of
+the verification servers.
+
+Multiple Root Identity Servers
+------------------------------
+
+There can be be multiple root Identity Servers. Clients will add each
+Association to all root Identity Servers.
+
+[[TODO(markjh): Describe how clients find the list of root Identity Servers]]
+
+