WunProtocol is the protocol used by WunApp clients to communicate with a WunApp server. Note that WunApp clients includes both the iOS application, and 3rd party applications that interact with the WunApp server.


General Overview


Communication is done via HTTP and HTTPS using JSON. Login and Sign Up use the "heavyweight" HTTPS for security. After Login a shared token and key are used for interactions over HTTP. The protocol protects credentials (shared secrets, email addresses), but not the primary content (message data, locations, etc). This design decision reflects the importance of credentials security, and also the importance of low latency and data usage.


SignUp and Login


Both SignUp and Login are done via SSL (HTTPS). This protects email addresses, and shared secrets. HTTPS is quite a "heavy" protocol; it is very secure (server proves identity; encryption on the wire etc), but too
expensive for the majority of transactions (latency, data usage, etc).


Login


To Login the client makes the following request (over SSL):
POST /api/login
The body of the POST should be a JSON dict as follows:


{
'type': 'credentials',
'email': '<email>',
'secret': '<secret>'
}


The email here is the email address of the user logging in. The secret is a shared secret established during signup. The WunApp iOS client creates this shared secret by MD5 hashing the cleartext password. This approach is recommended for 3rd party clients too. DO NOT send a clear text password as the shared secret!
Successful login has a status code of 200, and returns a JSON response:


{
'type': 'login',
'user': '<userid>',
'org': '<orgid>',
'token': '<token>',
'key': '<key>'
}


All of the returned values are strings. 'token' and 'key' are opaque objects. 'token' is a shared session state between the client and server. The server cryptographically hashes the token to produce the key. All subsequent (logged in) requests must supply this token, and be signed with this key.
'user' is a UUID referring to the currently logged in user.
'org' is a UUID referring to the user's organisation.


Sign Up


The WunApp server supports programmatic sign-up (with email address verification). To Sign-Up the client makes the following request (over SSL):


POST /api/signup
The body of the POST should be a JSON dict as follows:


{
'type': 'signup',
'email': '<email>',
'secret': '<secret>'
}


The supplied email address will be sent an email with a link to complete the signup. If the secret is supplied (it is optional) it will be sent "in the clear" (not encrypted) via an email after the signup is completed. It should
be used as a temporary password only.


RESTful Session Methods


After successful login the client has a 'token' and 'key' which it can use to make requests. Most of these requests follow the principles of REpresentational State Transfer (REST). They make use of the HTTP verb to
indicate the action being taken on a given resource (specified by the URL). Currently the resources are as follows:


• /api/organisation/<org>
• /api/user/<user>
• /api/conversation/<conv>
• /api/history/<history>


All requests to these URLs must include a 'token' parameter, a 'time' parameter (which is close to now), and a 'sig' parameter which is the HMAC-MD5 signature of the request path, parameters, and request body.
This request authentication mechanism is similar to that employed by Amazon's AWS, and was selected to provide a balance between client complexity, security, and request latency (cost).


/api/organisation/<org>
Supported verbs: GET, PUT, POST, DELETE
GET /api/organisation/<org>
Retrieve a JSON object with information about the organisation.


{
'type': 'organisation',
'name': '<name>',
'users': ['<userid1>', ...],
'billing': '<userid>
}


PUT /api/organisation/<org>
Send a JSON object with updates to the organisation. Currently only the
organisation name, and billing user can be changed. Attempting to set an
invalid billing user (e.g. none) will return a status code of 400 (invalid
parameters).


{
'type': 'organisation',
'name': '<newname>',
'billing': '<newbilling>'
}


Note that keys that are not supplied in the JSON object will not be set, e.g. supplying just 'name' will only update the organisation name, and not effect the organisation's billing user. Additional keys will be added in the future for reading and writing. The client should not assume that the listed keys here are exhaustive.


POST /api/organisation/<org>
Perform an "action" on the given organisation. Currently the only supported
action is inviting a new user to the organisation as follows:


{
'type': 'invite',
'name': '<user name>',
'email': '<email address>',
'message': '<invitation message>'
}


This will send an email to the specified user inviting them to the organisation, and providing a link to complete the signup process. After that link is followed they will have a new user associated with the
organisation. Default permissions of a user created this way are 0 (no organisation write, no write other user), ie they are a standard user.


DELETE /api/organisation/<org>
Remove the organisation altogether from the WunApp server (also removes
all users, and history). At present this requires a "special" permission
(orgdelete) which is not given by default through the signup process. It is
used for unit testing, and is optional to support for a 3rd party vendor.


/api/user/<user>
Supported verbs: GET, PUT, DELETE


GET /api/user/<user>
Retrieve a JSON object with information about the user.


{
'type': 'user',
'email': '<email>',
'name': '<name>',
'org': '<org>,
'loc': {
'latitude': <latitude>,
'longitude': <longitude>
},
'perms': 0
}


PUT /api/user/<user>
Send a JSON object with updates to this user. The name, location, and permissions can be changed (at present). To make changes to a user other than the logged in one the logged in user will need permotherwrite. It is an auth error to attempt to change (or GET) a user on a different organisation.


{
'type': 'user',
'name': '<new name>'
}


DELETE /api/user/<user>
Remove the given user altogether incuding all history. The user may not be
the organisation's billing user (which in turn means that it may not be the
organisation's only user).
/api/conversation/<conv>


Supported verbs: GET, PUT, POST, DELETE
GET /api/conversation/<conv>
Retrieve a JSON object with all information about the conversation


{
'type': 'conversation',
'org': '<organisation>',
'users': ['<userid1>', ...],
'body': [
{'id': '<mid1>', 'author': '<userid>', 'time': <time>, 'message':
'<message>'},
{'id': '<mid2>', 'author': '<userid>', 'time': <time>, 'message':
'<message>'},
...
]
}


The conversation is tied to the organisation by 'org'. The 'users' field provides all of the users who can currently see the conversation. When a user "deletes" a conversation they are removed from this field. When a user is added to a conversation an entry is added to the body that shows their addition with no message body. It looks like the following:


{'id': '<mid3>', 'author': '<userid>', 'time': <time>, 'user': '<newuserid>'}
PUT /api/conversation/<conv>
Create a new conversation.
{
'type': 'conversation',
'org': '<organisation>',
'users': ['<userid1>', ...],
'body': [
...
]
}


This creates a new conversation that links in the specified users with the supplied initial body. In the future this method may allow a conversation to be rewritten by a user with appropriate permissions.
POST /api/conversation/<conv>
Add a message to the conversation. The logged in user must be linked in
to the conversation.


{
'type': 'message',
'id': '<mid>',
'time': <time>,
'message': '<message>'
}


DELETE /api/conversation/<conv>
Remove the logged in user from the specified conversation.
/api/history/<history>
Supported verbs: GET, PUT
Get and store blocks of history.
Query URLs
A couple of URLs can be used for querying the underlying data store for matching records. These URLs require the same authentication as the RESTful URLs. They return a JSON summary of the matching resources.
GET /api/history?from=<time>&to=<time>
GET /api/conversation?user=<userid>