Add docs
This commit is contained in:
parent
24547ab996
commit
68ce1aeaff
15 changed files with 2517 additions and 26 deletions
2
Rules
2
Rules
|
@ -64,6 +64,8 @@ compile '*' do
|
|||
layout 'none'
|
||||
when %r{^/blog/.+}
|
||||
layout 'post'
|
||||
when %r{^/docs/}
|
||||
layout 'doc'
|
||||
else
|
||||
layout 'default'
|
||||
end
|
||||
|
|
|
@ -80,3 +80,7 @@ footer {
|
|||
padding-bottom: 10px;
|
||||
border-top: 1px grey solid;
|
||||
}
|
||||
|
||||
.doc-nav {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: App Authentication
|
||||
---
|
||||
|
||||
# App Authentication
|
||||
## App Authentication
|
||||
|
||||
Tent uses [OAuth 2](http://tools.ietf.org/html/draft-ietf-oauth-v2-31) for app
|
||||
authentication. Because of the distributed nature of Tent, it is necessary for
|
||||
|
@ -13,7 +13,7 @@ with [MAC Access
|
|||
Authentication](http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01).
|
||||
|
||||
|
||||
## App Registration
|
||||
### App Registration
|
||||
|
||||
Before authenticating a user, the application must be registered with the
|
||||
specified Tent entity. The first step is to perform discovery on the provided
|
||||
|
@ -62,13 +62,15 @@ Location: https://tent.titanous.com/apps/6737b
|
|||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "6737b",
|
||||
"secret": "3d2adf9a68bf64f4eaff70a7c7700a8",
|
||||
"mac_algorithm": "hmac-sha-256"
|
||||
}
|
||||
```
|
||||
|
||||
### Request Parameters
|
||||
#### Request Parameters
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ----------- |
|
||||
|
@ -79,7 +81,7 @@ Location: https://tent.titanous.com/apps/6737b
|
|||
| `redirect_uris` | Optional | Array | A list of **exact** (including parameters) urls that will be used as OAuth `redirect_uri` |
|
||||
| `scopes` | Optional | Object | A list of scope key to description value mappings of all scopes that the app might use. The descriptions should describe why the specific scope is necessary for the app to function. |
|
||||
|
||||
### Response Parameters
|
||||
#### Response Parameters
|
||||
|
||||
| Name | Description |
|
||||
| --------------- | ----------- |
|
||||
|
@ -87,12 +89,12 @@ Location: https://tent.titanous.com/apps/6737b
|
|||
| `secret` | The secret used as the MAC key when modifying the registration and receiving notifications. |
|
||||
| `mac_algorithm` | The MAC algorithm to be used. |
|
||||
|
||||
## App Registration Modification
|
||||
### App Registration Modification
|
||||
|
||||
The request must be authenticated with a MAC generated using the secret from the
|
||||
initial registration.
|
||||
|
||||
### PATCH /apps/:id
|
||||
#### PATCH /apps/:id
|
||||
|
||||
```text
|
||||
PATCH /apps/aff70a7
|
||||
|
@ -120,9 +122,9 @@ Authorization: MAC id="aff70a7",
|
|||
```
|
||||
|
||||
|
||||
## Authentication Flow
|
||||
### Authentication Flow
|
||||
|
||||
### Auth Request
|
||||
#### Auth Request
|
||||
|
||||
The app requests the user's Tent identifier, and performs discovery on it to
|
||||
find the Tent API root. The app then builds an auth request and redirects the
|
||||
|
@ -134,10 +136,10 @@ user-agent to it:
|
|||
&scope=read_posts,read_profile
|
||||
&state=87351cc2f6737bfc8ba
|
||||
&tent_profile_info_types=https://tent.io/types/info/music
|
||||
&tent_post_types=https://tent.io/types/posts/status#0.2.0,https://tent.io/types/posts/photo#0.2.0
|
||||
&tent_post_types=https://tent.io/types/posts/status##0.2.0,https://tent.io/types/posts/photo##0.2.0
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
##### Parameters
|
||||
|
||||
| Name | Required | Description |
|
||||
| --------------------------- | --------- | ----------- |
|
||||
|
@ -145,11 +147,11 @@ user-agent to it:
|
|||
| `redirect_uri` | Required | The URI to redirect to after authentication is complete. It must **exactly** match a URI (including parameters) provided during app registration in `redirect_uris`. |
|
||||
| `state` | Optional | This parameter will be added to the `redirect_uri` and should always be set to a random string that is stored in the session, and then verified to prevent cross-site request forgery attacks. |
|
||||
| `scope` | Optional | A comma-separated list of scopes that the app is requesting access to. |
|
||||
| `tent_profile_info_types` | Optional | A comma-separated list of `profile_info_type_url#version` profile info type specifiers that the app is requesting access to. Set to `all` to request full access to the profile. |
|
||||
| `tent_post_types` | Optional | A comma-separated list of `post_type_url#version` type/version specifiers that the app is requesting access to. Set to `all` to request access to all posts. |
|
||||
| `tent_profile_info_types` | Optional | A comma-separated list of `profile_info_type_url##version` profile info type specifiers that the app is requesting access to. Set to `all` to request full access to the profile. |
|
||||
| `tent_post_types` | Optional | A comma-separated list of `post_type_url##version` type/version specifiers that the app is requesting access to. Set to `all` to request access to all posts. |
|
||||
|
||||
|
||||
#### Scopes
|
||||
##### Scopes
|
||||
|
||||
| Scope | Description |
|
||||
| ------------------ | ---------------------------------------------------------------------- |
|
||||
|
@ -163,7 +165,7 @@ user-agent to it:
|
|||
| `write_posts` | Read and publish posts with types listed in the `post_types` parameter |
|
||||
|
||||
|
||||
### Redirect
|
||||
#### Redirect
|
||||
|
||||
After the user has authorized the application, the Tent server will redirect the
|
||||
User-Agent back to the specified `redirect_uri` with a `code` that can be used
|
||||
|
@ -177,12 +179,12 @@ the initial request to prevent request forgery.
|
|||
Location: http://fooapp.com/tent/callback?code=27ec1c54980f1af74&state=87351cc2f6737bfc8ba
|
||||
```
|
||||
|
||||
### Access Token
|
||||
#### Access Token
|
||||
|
||||
The `code` must be traded for permanent authentication details that can be used
|
||||
to access the Tent server on behalf of the user.
|
||||
|
||||
#### POST /apps/:id/access\_token
|
||||
##### POST /apps/:id/access\_token
|
||||
|
||||
The request must be signed with a MAC using the secret obtained during app
|
||||
registration. Currently only the `mac` `token_type` is supported.
|
||||
|
@ -221,7 +223,7 @@ Content-Type: application/json
|
|||
}
|
||||
```
|
||||
|
||||
#### Response Parameters
|
||||
##### Response Parameters
|
||||
|
||||
| Name | Description |
|
||||
| --------------- | ------------------------------------------------ |
|
||||
|
@ -231,7 +233,7 @@ Content-Type: application/json
|
|||
| `token_type` | Specifies the token type. Currently always `mac` |
|
||||
|
||||
|
||||
## Request Authentication
|
||||
### Request Authentication
|
||||
|
||||
Tent uses [HTTP MAC Access
|
||||
Authentication](http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01) to
|
||||
|
|
251
content/docs/app-notifications.md
Normal file
251
content/docs/app-notifications.md
Normal file
|
@ -0,0 +1,251 @@
|
|||
---
|
||||
title: App Notifications
|
||||
---
|
||||
|
||||
## App Notifications
|
||||
|
||||
If the app does not respond with 2XX, then the server should try again later.
|
||||
|
||||
For the purpose of examples, the server entity is thora.me and the app hostname is thoraapp.io
|
||||
|
||||
### New Content Notification
|
||||
|
||||
Server tells app about new content.
|
||||
|
||||
For example, smithson.me (an entity thora.me is following) posts a new status update. thora.me will notify all authorized apps requesting to be notified about status posts (just thoraapp.io for this example):
|
||||
|
||||
```
|
||||
POST /notifications
|
||||
Host: thoraapp.io
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "fadb14",
|
||||
"entity": "smithson.me",
|
||||
"time": 1345317776,
|
||||
"scope": "public",
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "Think different!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### Content Deleted Notification
|
||||
|
||||
Server tells app about a deleted post.
|
||||
|
||||
For example, thora.me receives a deleted post notification from smithson.me. thora.me already pushed the post to thoraapp.io so it pushes the deleted notification there as well.
|
||||
|
||||
```text
|
||||
POST /notifications
|
||||
Host: thoraapp.io
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "d2c519",
|
||||
"entity": "smithson.me",
|
||||
"time": 1345317776,
|
||||
"scope": "public",
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/delete",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"id": "fadb14",
|
||||
"entity": "smithson.me"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### New Following Notification
|
||||
|
||||
Server tells app about new entity it is following.
|
||||
|
||||
For example, thora.me follows johnsmith.me. thora.me will notify all authorized apps requesting to be notified about new followings (just thoraapp.io in this example):
|
||||
|
||||
```
|
||||
POST /notifications
|
||||
Host: thoraapp.io
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "54f85a",
|
||||
"entity": "thora.me",
|
||||
"scope": "direct",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/following",
|
||||
"version": "1.1.0",
|
||||
"view": "meta"
|
||||
},
|
||||
"groups": ["friends"],
|
||||
"entity": "johnsmith.me"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### Deleted Following Notification
|
||||
|
||||
Server tells app about an entity it is no longer following.
|
||||
|
||||
For example, thora.me is following elza-mraz.me. thora.me stops following elza-mraz.me and notifies all authorized apps requesting to be notified about followings (just thoraapp.io in this example):
|
||||
|
||||
```
|
||||
DELETE /notifications
|
||||
Host: thoraapp.io
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "5f5ea4",
|
||||
"entity": "thora.me",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/following",
|
||||
"version": "1.1.0",
|
||||
"view": "meta"
|
||||
},
|
||||
"id": "54f85a",
|
||||
"action": "remove",
|
||||
"entity": "elza-mraz.me"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### New Follower Notification
|
||||
|
||||
Server tells app about new entity that is following it.
|
||||
|
||||
For example, koss.me follows thora.me. thora.me sends a notification to all authorized apps requesting to be notified about followers (just thoraapp.io in this example):
|
||||
|
||||
```
|
||||
POST /notifications
|
||||
Host: thoraapp.io
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "ba8a7f4",
|
||||
"entity": "thora.me",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/follower",
|
||||
"version": "1.1.0",
|
||||
"view": "meta"
|
||||
},
|
||||
"action": "add",
|
||||
"entity": "koss.me",
|
||||
"groups": ["random-people"],
|
||||
"name": "Tim Koss"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### Deleted Follower Notification
|
||||
|
||||
Server tells app about an entity that is no longer following it, or it blocked.
|
||||
|
||||
For example, koss.me informs thora.me it no longer follows thora.me. thora.me sends a notification to all authorized apps requesting to be notified about followers (just thoraapp.io in this example):
|
||||
|
||||
```
|
||||
DELETE /notifications
|
||||
Host: thoraapp.io
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
```json
|
||||
{
|
||||
"id": "477fc5",
|
||||
"entity": "thora.me",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/follower",
|
||||
"version": "1.1.0",
|
||||
"view": "meta"
|
||||
},
|
||||
"action": "remove",
|
||||
"id": "ba8a7f4",
|
||||
"entity": "koss.me"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
488
content/docs/app-server.md
Normal file
488
content/docs/app-server.md
Normal file
|
@ -0,0 +1,488 @@
|
|||
---
|
||||
title: Server API for Apps
|
||||
---
|
||||
|
||||
## Server API for Apps
|
||||
|
||||
### Get profile
|
||||
|
||||
Tent servers are required to have a profile JSON file describing their setup. The JSON is formatted as an array of info-types.
|
||||
|
||||
Your app, or a third party app your using, will request the profile JSON from your server initially and will be notified when it changes. This will allow it to display your name and other personal information (within the scope of its permissions), and use canonical servers if your primary one goes down.
|
||||
|
||||
```
|
||||
GET /profile
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
``` json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "smith.me",
|
||||
"servers": [
|
||||
"https://tent.smith.me",
|
||||
"https://eqt5g4fuenphqinx.onion",
|
||||
"https://smi.th/api"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io/types/info/music",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
"bands": [ "foo", "bar" ]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Update profile.json
|
||||
|
||||
If given permission, an app can update your profile JSON. An app can have permission to update all or just specific sections of the file.
|
||||
|
||||
```
|
||||
PATCH /profile
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "smith.me",
|
||||
"servers": [
|
||||
"https://tent.smith.me",
|
||||
"https://eqt5g4fuenphqinx.onion",
|
||||
"https://smi.th/api"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io/types/info/music",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
"bands": [ "foo", "bar", "baz" ]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "smith.me",
|
||||
"servers": [
|
||||
"https://tent.smith.me",
|
||||
"https://eqt5g4fuenphqinx.onion",
|
||||
"https://smi.th/api"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io/types/info/music",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
"bands": [ "foo", "bar", "baz" ]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Get following entities
|
||||
|
||||
App gets list of entities your server is following.
|
||||
|
||||
```
|
||||
GET /following
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "ddc0563f12de",
|
||||
"entity": "johnsmith.me",
|
||||
"groups": ["friends"],
|
||||
"licenses": [
|
||||
{
|
||||
"url": "http://license.org/free-speach",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"post_types": [
|
||||
{
|
||||
"url": "https://tent.io/post-types/photo",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Follow
|
||||
|
||||
App tells server to follow an entitie.
|
||||
|
||||
```
|
||||
POST /following
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"entity": "elza-mraz.me",
|
||||
"groups": ["friends", "business"]
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
### Update Following
|
||||
|
||||
App changes what groups are applied to an entity your server is following.
|
||||
|
||||
#### PATCH /following/:id
|
||||
|
||||
```
|
||||
PATCH /following/bda7f416fbba
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"entity": "elza-mraz.me",
|
||||
"groups": ["business"]
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"id": "bda7f416fbba",
|
||||
"entity": "elza-mraz.me",
|
||||
"groups": ["business"]
|
||||
}
|
||||
```
|
||||
|
||||
### Unfollow
|
||||
|
||||
App tells server not to follow an entity.
|
||||
|
||||
#### DELETE /following/:id
|
||||
|
||||
```
|
||||
DELETE /following/bda7f416fbba
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### Followers
|
||||
|
||||
App asks for list of entities that are following the server.
|
||||
|
||||
```
|
||||
GET /followers
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "ddd67278456b",
|
||||
"entity": "koss.me",
|
||||
"groups": [],
|
||||
"full_name": "Tim Koss",
|
||||
"display_name": "koss"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Update Follower
|
||||
|
||||
App tells server to update information about a follower entity.
|
||||
|
||||
#### PATCH /followers/:id
|
||||
|
||||
```
|
||||
PATCH /followers/ddd67278456b
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"entity": "koss.me",
|
||||
"groups": ["random-people"],
|
||||
"full_name": "Tim Koss",
|
||||
"display_name": "koss"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"id": "ddd67278456b",
|
||||
"entity": "koss.me",
|
||||
"groups": ["random-people"],
|
||||
"full_name": "Tim Koss",
|
||||
"display_name": "koss"
|
||||
}
|
||||
```
|
||||
|
||||
### Follower
|
||||
|
||||
App asks for info about specific follower
|
||||
|
||||
```
|
||||
GET /followers/ddd67278456b
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"id": "ddd67278456b",
|
||||
"entity": "koss.me",
|
||||
"groups": ["random-people"],
|
||||
"full_name": "Tim Koss",
|
||||
"display_name": "koss"
|
||||
}
|
||||
```
|
||||
|
||||
### Block Follower
|
||||
|
||||
App tells server not to send notifications to entity.
|
||||
|
||||
```
|
||||
DELETE /followers/ddd67278456b
|
||||
```
|
||||
|
||||
```
|
||||
204 No Content
|
||||
```
|
||||
|
||||
### Publish
|
||||
|
||||
App publishes content to server.
|
||||
|
||||
For example, you have an app that manages status updates. You type a status update (post) in the app, your app sends that post to the server with this API.
|
||||
|
||||
See [conversation example](https://github.com/tent/tent-docs/blob/master/examples/conversation.md), and [conversation thread example](https://github.com/tent/tent-docs/blob/master/examples/conversation-thread.md) for full examples of publishing content through an app.
|
||||
|
||||
```
|
||||
POST /posts
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"time": 1345317062,
|
||||
"recipients": [
|
||||
"friends",
|
||||
"elza-mraz.me"
|
||||
],
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://licences.org/free-speach",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "Necessitatibus saepe exercitationem. Quidem rem aspernatur atque numquam in. Voluptas qui et.",
|
||||
"excerpt": "Necessitatibus saepe exercitationem..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
### Fetch Single Post
|
||||
|
||||
App fetches a specific post from server.
|
||||
|
||||
For example, a post your app has previously fetched or otherwise obtained is referencing another post.
|
||||
```json
|
||||
{
|
||||
"id": "8fec7937f7c1",
|
||||
"time": 1342217776,
|
||||
"entity": "sheldon.io",
|
||||
"scope": "public",
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://licences.org/free-speach",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/repost",
|
||||
"version": "1.0.0",
|
||||
},
|
||||
"id": "3fe1abef41cb",
|
||||
"entity": "smithson.me"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You want to see it, so your app requests it from your server.
|
||||
|
||||
#### GET /posts/:id[?params]
|
||||
|
||||
```
|
||||
GET /posts/3fe1abef41cb?entity=smithson%2Eme&fetch=force
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
#### Request Params
|
||||
|
||||
| Param | Required | Possible values | Description |
|
||||
| -------- | -------- | --------------- | ----------- |
|
||||
| `fetch` | Optional | `true`, `force` | When `true`, query listed entity' server when not in own database. When `force`, query listed entity' server instead of own database. |
|
||||
| `entity` | When the id was generated by another entity | Escaped Hostname of the entity responsible for the id (e.g. `entity=smithson%2Eme`) | Informs the server where to look (e.g. smithson.me) |
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
{
|
||||
"id": "3fe1abef41cb",
|
||||
"time": 1345317776,
|
||||
"entity": "smithson.me",
|
||||
"scope": "public",
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://licences.org/free-speach",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/repost",
|
||||
"version": "1.0.0",
|
||||
"view": "full"
|
||||
},
|
||||
"entity": "elza-mraz.me"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fetch Multiple Posts
|
||||
|
||||
App fetches posts from server matching specified criteria.
|
||||
|
||||
For example, your app has a stream view showing status updates from you and your followings. Your app paginates in an infinite-scroll pane, fetching 50 more updates when you reach the bottom. If the id of the last post loaded in your stream is `80b445839dd1` and your server Tent API root is `https://tent.johnsmith.io`, fetching the next page might look like this:
|
||||
```
|
||||
GET https://tent.johnsmith.io/posts?since_id=80b445839dd1&limit=50
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
#### GET /posts[?params]
|
||||
|
||||
```
|
||||
GET /posts?fetch=false
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
#### Request Params
|
||||
|
||||
Param | Required | Possible values | Description |
|
||||
------------ | -------- | --------------- | ----------- |
|
||||
`fetch` | No | `true`, `force` | When `true`, query listed entities’ servers in addition to own database. When `force`, query listed entities' servers instead of own database. |
|
||||
`entity` | No | Comma separated list of escaped Hostnames (e.g. `entity=smithson%2Eme,sheldon%2Eio` would only return content from smithson.me and sheldon.io) | Informs the server where to look. |
|
||||
`post_types` | No | Comma separated list of escaped post-type urls (e.g. `?post_types=https%3A%2F%2Ftent%2Eio%2Fpost-types%2Fpost##excerpt,https%3A%2F%2Ftent%2Eio%2Fpost-types%2Fphoto##thumb`) | Informs the server what post-types to return (e.g. https://tent.io/post-types/post##excerpt and https://tent.io/post-types/photo##thumb) |
|
||||
`since_id` | No | ID recognized by server, or listed entity’s server (if only one entity is listed) | Only return content created after given ID |
|
||||
`before_id` | No | ID recognized by server, or listed entity’s server (if only one entity is listed) | Only return content created before given ID |
|
||||
`since_time` | No | UTC epoch timestamp (e.g. 1345575602) | Only return content created after given time |
|
||||
`before_time`| No | UTC epoch timestamp (e.g. 1345575602) | Only return content created before given time |
|
||||
`limit` | No | Any positive integer (e.g. 500) | Max number of posts server should return |
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "3fe1abef41cb",
|
||||
"time": 1345317776,
|
||||
"entity": "smithson.me",
|
||||
"scope": "public",
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://licences.org/free-speach",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/repost",
|
||||
"version": "1.0.0",
|
||||
"view": "full"
|
||||
},
|
||||
"entity": "elza-mraz.me"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
176
content/docs/example-conversation-thread.md
Normal file
176
content/docs/example-conversation-thread.md
Normal file
|
@ -0,0 +1,176 @@
|
|||
---
|
||||
title: Example Conversation Thread
|
||||
---
|
||||
|
||||
## Example Conversation Thread
|
||||
|
||||
Brant decides the weather is great for going to the beach, he publicly asks a few friends if they want to go:
|
||||
|
||||
```
|
||||
POST https://tent.brant.io/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic 6BAtLBGtCK8417S2kEzZUZs/GU87l2beDKKLNo+BGZ8evqv35WiKVlRum4z0dOK0WNPfU9tZzkCK8Q+0RdOwFw==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345475873,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{ "entity": "allison.me" },
|
||||
{ "entity": "kelsi.io" }
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "^Allison ^Kelsi looks like a great day to go beaching"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
His server pushes his post to them and his followers...
|
||||
|
||||
Kelsi responds:
|
||||
|
||||
```
|
||||
POST https://kelsi.io/tent/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic Ak98PTWmfK6B55VrOx8W1QZGoR8ptSRpEMqXqW9mtCgn9vgzZTL0pU2eD9O8qo/GQwaDo3kmGtWN39coOHSrow==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345476455,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{ "entity": "brant.io" },
|
||||
{ "entity": "allison.me" },
|
||||
{
|
||||
"id": "24894d54305a",
|
||||
"entity": "brant.io"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "^Brant ^Allison I'm not doing anything later if you want to go around 3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
Her server pushes her response to them and her followers...
|
||||
|
||||
Susie is following Kelsi and responds to her post:
|
||||
|
||||
```
|
||||
POST https://tent.susie.com/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic hsKqPQ3wktYmByYgnOH21MTRq1DDAXkOyDGlfKGZ8RhiB7mBePA+68o+b1jyYG2nXlzUqUPIGz8yeKmJckB1XQ==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345476455,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{ "entity": "kelsi.io" },
|
||||
{
|
||||
"id": "24894d54305a",
|
||||
"entity": "brant.io"
|
||||
},
|
||||
{
|
||||
"id": "a9448b1b33ec",
|
||||
"entity": "kelsi.io"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "^Kelsi I'll be down there around 2:30"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
Susie’s server pushes her post to her followers (which includes Kelsi), and Brant...
|
||||
|
||||
Brant responds:
|
||||
|
||||
```
|
||||
POST https://tent.brant.io/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic 6BAtLBGtCK8417S2kEzZUZs/GU87l2beDKKLNo+BGZ8evqv35WiKVlRum4z0dOK0WNPfU9tZzkCK8Q+0RdOwFw==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345476455,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{ "entity": "kelsi.io" },
|
||||
{ "entity": "susie.com" },
|
||||
{
|
||||
"id": "24894d54305a",
|
||||
"entity": "brant.io"
|
||||
},
|
||||
{
|
||||
"id": "a9448b1b33ec",
|
||||
"entity": "kelsi.io"
|
||||
},
|
||||
{
|
||||
"id": "87cc8698f03f",
|
||||
"entity": "susie.com"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "^Kelsi ^Susie Should I meet the two of you there around 3?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
Susi, and Brant’s followers (which includes Kelsi) get pushed the post...
|
462
content/docs/example-conversation.md
Normal file
462
content/docs/example-conversation.md
Normal file
|
@ -0,0 +1,462 @@
|
|||
---
|
||||
title: Example Tent Conversation
|
||||
---
|
||||
|
||||
## Example Tent Conversation
|
||||
|
||||
Jerrold posts an opinionated status to his 'friends' group of followers:
|
||||
|
||||
His client posts to his server:
|
||||
|
||||
```text
|
||||
POST https://tent.jerrold.me/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic siueXXjTBoVvjpJAH8Mi2CB58pxGoGes06F2Yhhv4sh13LEdasECwCBOt+GhE3PiBniMZoiBoOeNUiI+mIUN0w==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345317062,
|
||||
"recipients": [
|
||||
"friends"
|
||||
],
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "I love kittens!"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
201 Created
|
||||
```
|
||||
|
||||
Jerrold has Kavon and Shirley in his friends group of followers.
|
||||
|
||||
His server lets the recipients know about the post:
|
||||
|
||||
```text
|
||||
POST https://tent.kavon.me/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic pFxCQ0EIDgJDAkWi1kXr1nHBR2BhrSqY5IGgjgXgwriuuiFI8R+u2jKuw8+DmiJMcUt+08HI55xDeT7KBgnhLQ==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me",
|
||||
"time": 1345317062,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "limited",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "I love kittens!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK
|
||||
```
|
||||
|
||||
```text
|
||||
POST https://shirley.me/tent/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic 8g/A17DuOlwKODrhxr6wKUnm2kmoA7wMHnMtdsj7pTLGcNaoq8wavPgxzd7ihtif2ywPrwJowHaHy8wTexeRCg==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me",
|
||||
"time": 1345317062,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "limited",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"text": "I love kittens!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK
|
||||
```
|
||||
|
||||
Their servers instantly propigate the post to designated clients:
|
||||
|
||||
```text
|
||||
POST https://status-updates.kavon.me/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic wMgriYX2cr2kgVFRrrlndRuz4K20pAcm5GZzQ8akYYqSxRHS3mkujksjHkszZhp3IP+EXcA7vYDAt3k/8QIYeQ==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me",
|
||||
"time": 1345317062,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "limited",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "I love kittens!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK ## response can be any 200 series http code
|
||||
```
|
||||
|
||||
Shirley has her client in maintenence mode; jerrold.me will attempt to deliver the notification later using an exponential backoff algorithm.
|
||||
|
||||
```text
|
||||
POST https://shirley.me/status-updates/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic 3H5i9F6HlFCgdFywnuUN1ATleGgaO1Y+fYTWBBPQ35NzyG9YzLeLRS2xdlibiGl15UQ91w/e61+5F9PM0KGqvQ==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me",
|
||||
"time": 1345317062,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "limited",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "I love kittens!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```text
|
||||
503 Service Unavailable
|
||||
```
|
||||
|
||||
Kavon responds to the post:
|
||||
|
||||
```text
|
||||
POST https://tent.kavon.me/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic LfSERqFpMAyaYhWCMsQrZuY+SYwrjAarVqrtYWDkE209igHeo3TbRjWu2hY8r9IeUkXZlyUqicNvkV8zIrUL9Q==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345409893,
|
||||
"recipients": [
|
||||
"jerrold.me"
|
||||
],
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "0.6.0"
|
||||
},
|
||||
"exif": { ... },
|
||||
"binary": "...",
|
||||
"filetype": "jpeg",
|
||||
"caption": "Cute Kitten"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
201 Created
|
||||
```
|
||||
|
||||
His server sends it along to Jerrold’s server:
|
||||
|
||||
```text
|
||||
POST https://tent.jerrold.me/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic Em3TI5yRwASeeVlUIEBW5T8rBSKdtwZR9CPZ/8hOphLRwWjOzns1bctZSVFm9MrEdR/jZ61EEPInOl4cvFr8bg==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "d8c9d3453e33",
|
||||
"time": 1345409893,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me"
|
||||
}
|
||||
],
|
||||
"scope": "direct",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "0.6.0"
|
||||
},
|
||||
"exif": { ... },
|
||||
"binary": "...",
|
||||
"filetype": "jpeg",
|
||||
"caption": "Cute Kitten"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
```
|
||||
|
||||
Jerrold’s server instantly propagates it to his client:
|
||||
|
||||
```
|
||||
POST https://status.jerrold.me/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic SySu6uvpKu+Wc7jpZGStQMTQU6HVLC0TGaH2gyHwmRGNHUOhFiRK0WAN4+6YzXC2qWkiH7DxurpoqCtWFsrH7A==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "d8c9d3453e33",
|
||||
"time": 1345409893,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me"
|
||||
}
|
||||
],
|
||||
"scope": "direct",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "0.6.0"
|
||||
},
|
||||
"exif": { ... },
|
||||
"binary": "...",
|
||||
"filetype": "jpeg",
|
||||
"caption": "Cute Kitten"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
```
|
||||
|
||||
Jerrold sees Kavon’s reply and reposts it to his friends:
|
||||
|
||||
```
|
||||
POST https://tent.jerrold.me/posts
|
||||
Content-Type: application/json
|
||||
Authorization: Basic siueXXjTBoVvjpJAH8Mi2CB58pxGoGes06F2Yhhv4sh13LEdasECwCBOt+GhE3PiBniMZoiBoOeNUiI+mIUN0w==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"time": 1345410615,
|
||||
"recipients": [
|
||||
"friends"
|
||||
],
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me"
|
||||
}
|
||||
],
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/repost",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"entity": "kavon.me",
|
||||
"id": "d8c9d3453e33"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
201 Created
|
||||
```
|
||||
|
||||
Shirley’s client is back up and receives the two posts:
|
||||
|
||||
```
|
||||
POST https://shirley.me/status-updates/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic 3H5i9F6HlFCgdFywnuUN1ATleGgaO1Y+fYTWBBPQ35NzyG9YzLeLRS2xdlibiGl15UQ91w/e61+5F9PM0KGqvQ==
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me",
|
||||
"time": 1345317062,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "limited",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "I love kittens!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
```
|
||||
|
||||
```
|
||||
POST https://shirley.me/status-updates/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Basic 3H5i9F6HlFCgdFywnuUN1ATleGgaO1Y+fYTWBBPQ35NzyG9YzLeLRS2xdlibiGl15UQ91w/e61+5F9PM0KGqvQ==
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "d0f2eeb833e8",
|
||||
"time": 1345410615,
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "jerrold.me"
|
||||
}
|
||||
],
|
||||
"scope": "limited",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/repost",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"entity": "kavon.me",
|
||||
"id": "d8c9d3453e33"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
200 OK
|
||||
```
|
||||
|
||||
Her client requests Kavon’s post:
|
||||
|
||||
```
|
||||
GET https://shirley.me/tent/posts/d8c9d3453e33
|
||||
Content-Type: application/json
|
||||
Authorization: Basic QIGjvhI003diqWIoZlcegn/zSGMpSUheElNZv/uBUEgXE6n2kCNrnu16kLRgZ5keZI37IXStGJUdDH7lZ5mCLQ==
|
||||
```
|
||||
|
||||
It is not on her server, so it attempts to fetch it:
|
||||
|
||||
```
|
||||
GET https://tent.kavon.me/posts/d8c9d3453e33
|
||||
Content-Type: application/json
|
||||
Authorization: Basic uzYm8HtmWBAjqBdLA+kmTT4yZc5930ydU/dSQxFDtzFXu0xEfektBCDy/c167JFBOClqmShh0wF3omuqD9Mhvg==
|
||||
```
|
||||
|
||||
She is not authorized to see it, so Kavon’s server responds with:
|
||||
|
||||
```
|
||||
403 Forbidden
|
||||
```
|
||||
|
||||
Her server responds to her client:
|
||||
|
||||
```
|
||||
403 Forbidden
|
||||
```
|
91
content/docs/index.md
Normal file
91
content/docs/index.md
Normal file
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
title: Protocol Introduction
|
||||
---
|
||||
|
||||
## The Tent Protocol
|
||||
|
||||
Tent is a protocol for distributed social networking. It allows you to control
|
||||
your data, who has access to it, and what can be done with it.
|
||||
|
||||
|
||||
### API Overview
|
||||
|
||||
The API is
|
||||
[RESTful](http://en.wikipedia.org/wiki/Representational_state_transfer#RESTful_web_services),
|
||||
using [JSON](http://en.wikipedia.org/wiki/JSON) over
|
||||
[HTTPS](http://en.wikipedia.org/wiki/HTTPS) (**Important**: HTTPS is used
|
||||
everywhere, unencrypted HTTP requests are used.)
|
||||
|
||||
Requests are authenticated with [HMAC](http://en.wikipedia.org/wiki/Hash-based_message_authentication_code)
|
||||
signatures, and apps use [OAuth 2](http://en.wikipedia.org/wiki/OAuth) to access
|
||||
content on behalf of users.
|
||||
|
||||
Client libraries for Ruby, Python, Java, Objective-C, JavaScript, and C++ are coming
|
||||
soon so you can focus on writing your app.
|
||||
|
||||
|
||||
### Users
|
||||
|
||||
Tent users are called entities and are defined by a URI.
|
||||
|
||||
**Example:** John Smith's entity might be `johnsmith.me`, implying a [HEAD
|
||||
request](http://en.wikipedia.org/wiki/HEAD_%28HTTP%29#Request_methods) to
|
||||
`https://johnsmith.me/` would respond with a `Tent-Server` header pointing to
|
||||
a Tent API root (e.g. `Tent-Server: https://tent.johnsmith.me`)
|
||||
|
||||
|
||||
### Profiles
|
||||
|
||||
Every Tent entity has a profile JSON file describing it. The profile contains an
|
||||
array of JSON objects each described by an info-type. The most basic profile has
|
||||
a single object containing the supported Tent version, the entity name (e.g.
|
||||
johnsmith.me), an array of supported licences, and an array of servers
|
||||
containing canonical API roots.
|
||||
|
||||
You may have multiple versions of the same info type in your profile (e.g. you
|
||||
might need to support multiple versions of Tent.)
|
||||
|
||||
|
||||
### Servers
|
||||
|
||||
Tent servers are the protocol core. A server handles these responsibilities:
|
||||
|
||||
- Persisting data
|
||||
- Notifying other servers about new data
|
||||
- Ensuring content is only pushed to recipients accepting associated licences
|
||||
- Managing a list of servers (entities) it is following
|
||||
- Managing a list of servers (entities) that are following it
|
||||
- Authorizing apps to access data
|
||||
- Notifying apps about new or modified data they have access to
|
||||
|
||||
|
||||
### Apps
|
||||
|
||||
Tent apps are typically where content is created and consumed.
|
||||
|
||||
For example:
|
||||
|
||||
1. ian-hanson.me (Ian) posts a status update (post) from a micro blogging app authenticated with his server.
|
||||
2. The app publishes the post to his server.
|
||||
3. His server sends a notification to every server following him or mentioned in the post with permission to see the post.
|
||||
4. If anna-collins.me (Anna) is following Ian, her server will receive a notification from Ian’s server containing the post.
|
||||
5. If Anna has an app setup for consuming status updates, her server will send it a notification with Ian’s post.
|
||||
6. Anna can now read Ian’s post from the status app.
|
||||
7. If Anna decides to reply, her response will follow a path inverse to Ian’s post.
|
||||
|
||||
|
||||
### Posts
|
||||
|
||||
Tent posts can be used to describe anything. The term used to describe a piece
|
||||
of content is __post__. Posts each have a post-type which describes its data.
|
||||
|
||||
For example, a post containing a photo would be described by a photo post-type.
|
||||
The post-type outlines what content keys to expect, in this case it might have
|
||||
`exif`, `binary`, and `filetype`.
|
||||
|
||||
|
||||
### Notifications
|
||||
|
||||
Tent notifications are used when a server needs to let another server or app
|
||||
know about new content updates. Notifications are JSON webhooks with an array of
|
||||
Tent posts.
|
90
content/docs/info-types.md
Normal file
90
content/docs/info-types.md
Normal file
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
title: Profile Info Types
|
||||
---
|
||||
|
||||
## Profile Info Types
|
||||
|
||||
Profile info type schemas.
|
||||
|
||||
### Building your own type
|
||||
|
||||
Your type schema needs to have `url`, `name`, `description`, `version`, and `content` keys. `content` holds all your custom data keys.
|
||||
|
||||
#### Example
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/info/relationship-status",
|
||||
"name": "Relationship Status",
|
||||
"description": "Publish your relationship status",
|
||||
"version": "1.0.0",
|
||||
"content": {
|
||||
"status": "single",
|
||||
"interested_in": ["women"],
|
||||
"looking_for": ["friendship", "networking", "random play"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `status` | Required | String | Possible values: "single", "in a relationship", "it's complicated" |
|
||||
| `interested_in` | Required | Array | Possible values: "men", "women" |
|
||||
| `looking_for` | Required | Array | Possible values: "random play", "friendship", "relationship", "whatever I can get", "networking" |
|
||||
|
||||
### Tent
|
||||
|
||||
Every profile JSON file must have this
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/info/tent",
|
||||
"name": "Tent",
|
||||
"description": "Core of self.json, must be included to be Tent compatible",
|
||||
"version": "1.0.0",
|
||||
"content": {
|
||||
"licences": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "johnsmith.me",
|
||||
"servers": [
|
||||
"john.smith.com",
|
||||
"https://eqt5g4fuenphqinx.onion",
|
||||
"smi.th/tent-api"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `licenses` | Required | Array | List of accepted licences (url and version) |
|
||||
| `entity` | Required | String | Url with `Tent-Server` header pointing to your tent-api root (https:// prefix is implied) |
|
||||
| `servers` | Required | Array | List of canonical tent-api roots |
|
||||
|
||||
### Profile
|
||||
|
||||
Basic personal information.
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/info/profile",
|
||||
"name": "Profile",
|
||||
"description": "Basic personal information",
|
||||
"version": "1.0.0",
|
||||
"content": {
|
||||
"display_name": "jdoe",
|
||||
"full_name": "Dr. John Blake Doe",
|
||||
"avatar_url": "https://avatar.io/jdoe.png"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `display_name` | Required | String | Name to be used from within posts |
|
||||
| `name` | Optional | String | Your full name |
|
||||
| `avatar_url` | Optional | String | URL of your public display photo |
|
||||
|
305
content/docs/post-types.md
Normal file
305
content/docs/post-types.md
Normal file
|
@ -0,0 +1,305 @@
|
|||
---
|
||||
title: Post Types
|
||||
---
|
||||
|
||||
## Post Types
|
||||
|
||||
Schema for posting content of different types.
|
||||
|
||||
### Building your own type
|
||||
|
||||
Your type schema needs to have `url`, `version`, `name`, `description`, `views`, and `content`.
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `url` | Required | String | The schema url (e.g. https://tent.io/types/posts/video) |
|
||||
| `version` | Required | String | See [Semantic Versioning](http://semver.org/) (e.g. "0.1.0") |
|
||||
| `name` | Required | String | Name of the type (e.g. Video) |
|
||||
| `description` | Required | String | A short description of the type (e.g. "Any video format") |
|
||||
| `views` | Required | Object | JSON object defining views for the type. `ignore` and `full` are implied and don't need specifying, `meta` is required and should only include meta content keys. `full` includes all content keys, `ignore` is used to ask never to be sent this type of content. |
|
||||
| `content` | Required | Object | JSON object defining possible content key/value pairs. |
|
||||
|
||||
For example, if you wanted to create a type for post cards the JSON schema might look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/post-card",
|
||||
"version": "0.1.0",
|
||||
"name": "Post Card",
|
||||
"description": "Virtual post cards",
|
||||
"views": {
|
||||
"meta": ["geo", "photo.exif", "photo.filetype"],
|
||||
"photo": ["photo", "geo"],
|
||||
"message": ["text", "geo"],
|
||||
},
|
||||
"content": {
|
||||
"text": "Grettings from Toronto",
|
||||
"photo": {
|
||||
"exif": {},
|
||||
"binary": "...",
|
||||
"filetype": "jpeg",
|
||||
},
|
||||
"geo": {
|
||||
"lat": 43.753504,
|
||||
"lng": -79.408326
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Text
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/text",
|
||||
"version": "1.0.0",
|
||||
"name": "General Text Post",
|
||||
"description": "Text-only blog post",
|
||||
"views": {
|
||||
"excerpt": ["excerpt"]
|
||||
},
|
||||
"content": {
|
||||
"excerpt": "Snippet of full text...",
|
||||
"text": "Full post text",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Content
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `excerpt` | Required | String | Short excerpt of `text` |
|
||||
| `text` | Required | String | Full text of post |
|
||||
|
||||
### HTML
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/html",
|
||||
"version": "1.0.0",
|
||||
"name": "HTML post",
|
||||
"description": "HTML blog post",
|
||||
"views": {
|
||||
"excerpt": ["excerpt"]
|
||||
},
|
||||
"content": {
|
||||
"excerpt": "Text only snippet of full HTML...",
|
||||
"html": "Full post HTML",
|
||||
"text": "Text only representation of HTML"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Content
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `excerpt` | Required | String | Short text-only excerpt of `html` |
|
||||
| `html` | Required | String | Full HTML of post. Disallowed tags are `link`, `script`, and `style` |
|
||||
| `text` | Optional | String | Text-only representation of HTML |
|
||||
|
||||
### Status
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.0.0",
|
||||
"name": "Short status update",
|
||||
"description": "160 character or less text post",
|
||||
"views": {
|
||||
},
|
||||
"content": {
|
||||
"text": "Omnis provident omnis. Et fuga error modi asperiores esse quis mollitia. In dignissimos odio molestiae qui. Nihil et consequuntur sed aperiam qui libero ##cupidit",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Content
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `text` | Required | String | plain text up to a limit of 160 character |
|
||||
|
||||
### Delete
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/delete",
|
||||
"version": "0.1.0",
|
||||
"name": "Delete",
|
||||
"description": "Delete existing post",
|
||||
"views": {},
|
||||
"content": {
|
||||
"id": "entity-post-uid",
|
||||
"entity": "entity.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Following
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/following",
|
||||
"version": "0.1.0",
|
||||
"name": "Following",
|
||||
"description": "Describes an entity you are following",
|
||||
"views": {},
|
||||
"content": {
|
||||
"action" "add",
|
||||
"entity": "johnsmith.com"
|
||||
"id": "your-uid-of-follower",
|
||||
"groups" ["random-people"],
|
||||
"name": "John Smith"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| ----------------- | ---------- | -------- | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `action` | Required | String | Possible values: `add`, `remove`, `update` |
|
||||
| `entity` | Required | String | Any Tent hostname |
|
||||
| `id` | Varies | String | The uid representing the following on your Tent server. Required when `action` is set to `remove` or `update` |
|
||||
| `groups` | Optional | Array | List of group names attached to the following on your Tent server. |
|
||||
| `name` | Optional | String | The name you use to reference the entity |
|
||||
|
||||
### Follower
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/follower",
|
||||
"version": "0.1.0",
|
||||
"name": "Following",
|
||||
"description": "Describes an entity that is following you",
|
||||
"views": {},
|
||||
"content": {
|
||||
"action" "add",
|
||||
"entity": "johnsmith.com",
|
||||
"id": "your-uid-of-follower",
|
||||
"groups" ["random-people"],
|
||||
"name": "John Smith"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `action` | Required | String | Possible values: `add`, `remove`, `update` |
|
||||
| `entity` | Required | String | Any Tent hostname |
|
||||
| `id` | Varies | String | The uid representing the follower on your Tent server. Required when `action` is set to `remove` or `update` |
|
||||
| `groups` | Optional | Array | List of group names attached to the follower on your Tent server. |
|
||||
| `name` | Optional | String | The name you use to reference the entity |
|
||||
|
||||
### Photo
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "1.0.0",
|
||||
"name": "Photo",
|
||||
"description": "any format of photo",
|
||||
"views": {
|
||||
"meta": ["exif", "filetype", "caption", "album", "tags"]
|
||||
},
|
||||
"content": {
|
||||
"exif": {
|
||||
},
|
||||
"binary": "...",
|
||||
"filetype": "jpeg",
|
||||
"caption": "Short description of photo",
|
||||
"album": "travel",
|
||||
"tags": ["motion", "dark"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Content
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `exif` | Required | Object | [exif](http://en.wikipedia.org/wiki/Exchangeable_image_file_format) key/value pairs |
|
||||
| `filetype` | Required | String | Type of photo (e.g. png) |
|
||||
| `binary` | Required | String | Base64 encoded photo binary |
|
||||
| `caption` | Optional | String | Short description of photo (max of 160 characters) |
|
||||
| `album` | Optional | String | Name of album photo belongs to |
|
||||
| `tags` | Optional | Array | List of tags describing the photo |
|
||||
|
||||
### Video
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/video",
|
||||
"version": "1.0.0",
|
||||
"name": "Video",
|
||||
"description": "any format of video",
|
||||
"views": {
|
||||
"meta": ["exif", "filetype", "caption", "album", "tags", "length"]
|
||||
},
|
||||
"content": {
|
||||
"exif": {
|
||||
},
|
||||
"binary": "...",
|
||||
"filetype": "mpeg",
|
||||
"caption": "Short description of video",
|
||||
"album": "travel",
|
||||
"tags": ["under the sun"],
|
||||
"length": 160
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Content
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `exif` | Required | Object | [exif](http://en.wikipedia.org/wiki/Exchangeable_image_file_format) key/value pairs |
|
||||
| `filetype` | Required | String | Type of video (e.g. mpeg) |
|
||||
| `binary` | Required | String | Base64 encoded video binary |
|
||||
| `caption` | Optional | String | Short description of video (max of 160 characters) |
|
||||
| `album` | Optional | String | Name of album video belongs to |
|
||||
| `tags` | Optional | Array | List of tags describing the video |
|
||||
| `length` | Required | Number | Length of video in seconds |
|
||||
|
||||
### Message
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://tent.io/types/posts/message",
|
||||
"version": "1.0.0",
|
||||
"name": "Message",
|
||||
"description": "Tent equivalent of email",
|
||||
"views": {
|
||||
"meta": ["to", "cc", "bcc"]
|
||||
},
|
||||
"content": {
|
||||
"to": ["johndoe.me", "briansmith.com"],
|
||||
"cc": ["carla-laura.me"],
|
||||
"bcc": [],
|
||||
"attachments": [
|
||||
{
|
||||
"content_type": "jpeg",
|
||||
"content_encoding": "base64",
|
||||
"binary": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Content
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ---------------- |
|
||||
| `to` | Required | Array | List of entities to whom the message is to |
|
||||
| `cc` | Optional | Array | List of entities who are carbon copied |
|
||||
| `bcc` | Optional | Array | List of entities who are blind carbon copied (empty unless you are the sender) |
|
||||
| `attachments` | Optional | Array | List of attachment objects |
|
||||
|
||||
##### Attachment Object
|
||||
|
||||
| Name | Required | Type | Description |
|
||||
| --------------- | -------- | ------ | ----------------------------------------------------- |
|
||||
| `content_type` | Required | String | Type of attachment (e.g. pdf) |
|
||||
| `content_encoding` | Required | String | Encoding of attachment binary |
|
||||
| `binary` | Required | String | Encoded binary of attachment (see `content_encoding`) |
|
108
content/docs/profile.md
Normal file
108
content/docs/profile.md
Normal file
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
title: Tent Profile
|
||||
---
|
||||
|
||||
## Tent Profile
|
||||
|
||||
This is where you define what version(s) of Tent you're using, what urls act as
|
||||
Tent API endpoints for your content, what licences you support, your entity name
|
||||
(can be any URI with a `Tent-Server` header, and any other information about you
|
||||
(e.g. Your real name, email, interest, etc.)
|
||||
|
||||
A very basic profile might look like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "johnsmith.io",
|
||||
"servers": [
|
||||
"https://tent.johnsmith.io"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The JSON is an array of objects complying with an info-type schema (See [info
|
||||
types](/docs/info-types)). You may have multiple objects of the same type in
|
||||
order to support multiple versions.
|
||||
|
||||
You could add support for another Tent version like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "johnsmith.io",
|
||||
"servers": [
|
||||
"https://tent.johnsmith.io"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "johnsmith.io",
|
||||
"servers": [
|
||||
"https://tent.johnsmith.io"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
You could add your basic information:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "johnsmith.io",
|
||||
"servers": [
|
||||
"https://tent.johnsmith.io"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io/types/info-types/basic-info",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"name": "John Smith",
|
||||
"age": 25
|
||||
}
|
||||
]
|
||||
```
|
||||
|
488
content/docs/server-protocol.md
Normal file
488
content/docs/server-protocol.md
Normal file
|
@ -0,0 +1,488 @@
|
|||
## Tent Server-Server Communication Protocol
|
||||
|
||||
This document describes the protocol that Tent servers use to communicate with
|
||||
each other.
|
||||
|
||||
### Server Discovery
|
||||
|
||||
Both discovery methods should be implemented.
|
||||
|
||||
#### HTML `link` tag
|
||||
|
||||
The `link` tag should be placed in the `head` tag of all HTML pages associated
|
||||
with the Tent entity.
|
||||
|
||||
```html
|
||||
<link rel="tent" href="https://tent.titanous.com" />
|
||||
```
|
||||
|
||||
#### HTTP Header
|
||||
|
||||
The HTTP header allows discovery of Tent servers by just doing a HEAD request
|
||||
instead of getting the page and parsing it for the `link` tag. It should be
|
||||
added to all responses associated with the Tent entity.
|
||||
|
||||
```text
|
||||
Tent-Server: https://tent.titanous.com
|
||||
```
|
||||
|
||||
The `Tent-Server` header can contain multiple comma-separated urls that should
|
||||
be tried in order.
|
||||
|
||||
|
||||
### Entity Profile
|
||||
|
||||
```text
|
||||
GET /profile
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io",
|
||||
"version": "0.2.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"entity": "titanous.com",
|
||||
"servers": [
|
||||
"https://tent.titanous.com",
|
||||
"https://eqt5g4fuenphqinx.onion",
|
||||
"https://titn.us/api"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"url": "https://tent.io/types/profile/music",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
"bands": [ "foo", "bar" ]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
### Follow an entity
|
||||
|
||||
A follow request is required in order to receive notifications about posts
|
||||
published by an entity.
|
||||
|
||||
The `secret` is only returned once and should be persisted along with the `id`
|
||||
for authentication.
|
||||
|
||||
### POST /followers
|
||||
|
||||
```text
|
||||
POST /followers
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"entity": "danielsiders.com",
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "~> 1.1",
|
||||
"view": "full"
|
||||
},
|
||||
{
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "~> 1.0",
|
||||
"view": "meta"
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
201 Created
|
||||
Content-Type: application/json
|
||||
Location: https://tent.titanous.com/api/followers/775ecf8
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "775ecf8"
|
||||
"secret": "b524ce27f1882bcad98092175fbe7040",
|
||||
"mac_algorithm": "hmac-sha-256"
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
All requests must be made using SSL.
|
||||
|
||||
Authentication is required for all resources except some of the profile and
|
||||
publicly accessible posts.
|
||||
|
||||
Tent uses [MAC Access
|
||||
Authentication](http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01)
|
||||
for all requests. The `id` and `secret` from the follow response are used as the
|
||||
MAC key identifier and MAC key respectively.
|
||||
|
||||
All requests must be signed using MAC, and all notifications from the server
|
||||
are signed as well.
|
||||
|
||||
Currently the signatures in example requests are fake, they will be correct when
|
||||
the documentation generator is done.
|
||||
|
||||
|
||||
## Get Current Following
|
||||
|
||||
danielsiders.com checks its following of titanous.com
|
||||
|
||||
### GET /followers/:id
|
||||
|
||||
```text
|
||||
GET /followers/775ecf8
|
||||
Accept: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "775ecf8",
|
||||
"entity": "danielsiders.com",
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "~> 1.1",
|
||||
"view": "full"
|
||||
},
|
||||
{
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "~> 1.0",
|
||||
"view": "meta"
|
||||
},
|
||||
],
|
||||
"mac_algorithm": "hmac-sha-256"
|
||||
}
|
||||
```
|
||||
|
||||
## Edit Following
|
||||
|
||||
### PATCH /followers/:id
|
||||
|
||||
```text
|
||||
PATCH /followers/775ecf8
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "775ecf8",
|
||||
"entity": "danielsiders.com",
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "~> 1.1",
|
||||
"view": "full"
|
||||
},
|
||||
{
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "~> 1.0",
|
||||
"view": "thumb"
|
||||
},
|
||||
],
|
||||
"mac_algorithm": "hmac-sha-256"
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "775ecf8",
|
||||
"entity": "danielsiders.com",
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "~> 1.1",
|
||||
"view": "full"
|
||||
},
|
||||
{
|
||||
"url": "https://tent.io/types/posts/photo",
|
||||
"version": "~> 1.0",
|
||||
"view": "thumb"
|
||||
},
|
||||
],
|
||||
"mac_algorithm": "hmac-sha-256"
|
||||
}
|
||||
```
|
||||
|
||||
## Stop Following
|
||||
|
||||
### DELETE /followers/:id
|
||||
|
||||
```text
|
||||
DELETE /followers/775ecf8
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```text
|
||||
204 No Content
|
||||
```
|
||||
|
||||
## Notifications
|
||||
|
||||
Notification from titanous.com to danielsiders.com that new content has been
|
||||
posted.
|
||||
|
||||
### POST /notifications
|
||||
|
||||
```text
|
||||
POST /notifications
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "titanous.com",
|
||||
"time": 1345322351,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "public",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "Tent.io is awesome!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### POST /notifications
|
||||
|
||||
```text
|
||||
POST /notifications
|
||||
Content-Type: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "8c73440",
|
||||
"entity": "titanous.com",
|
||||
"time": 1345322351,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "public",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/delete",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "titanous.com",
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Fetch Post Feed
|
||||
|
||||
### GET /posts
|
||||
|
||||
#### Parameters
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Required</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>post_types</code></td>
|
||||
<td>Optional</td>
|
||||
<td>string</td>
|
||||
<td>Specifies the post types and views to return. ex: <code>https://tent.io/types/posts/blog#excerpt,https://tent.io/types/posts/photo#meta</code>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>since_id</code></td>
|
||||
<td>Optional</td>
|
||||
<td>string</td>
|
||||
<td>Show posts newer than this id.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>before_id</code></td>
|
||||
<td>Optional</td>
|
||||
<td>string</td>
|
||||
<td>Show posts older than this id.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>since_time</code></td>
|
||||
<td>Optional</td>
|
||||
<td>integer</td>
|
||||
<td>Show posts made since this time (unix epoch time).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>before_time</code></td>
|
||||
<td>Optional</td>
|
||||
<td>integer</td>
|
||||
<td>Show posts made before this time (unix epoch time).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>count</code></td>
|
||||
<td>Optional</td>
|
||||
<td>integer</td>
|
||||
<td>The number of posts to return.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
```text
|
||||
GET /posts
|
||||
Accept: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "titanous.com",
|
||||
"time": 1345322351,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "public",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "Tent.io is awesome!"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Fetch Single Post
|
||||
|
||||
### GET /posts/:id
|
||||
|
||||
```text
|
||||
GET /posts/jA4Mzdh
|
||||
Accept: application/json
|
||||
Authorization: MAC id="775ecf8",
|
||||
ts="1336363200",
|
||||
nonce="dj83hs9s",
|
||||
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
|
||||
```
|
||||
|
||||
```text
|
||||
200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "jA4Mzdh",
|
||||
"entity": "titanous.com",
|
||||
"time": 1345322351,
|
||||
"licenses": [
|
||||
{
|
||||
"url": "https://tent.io/types/licenses/creative-commons",
|
||||
"version": "3.0.0"
|
||||
}
|
||||
],
|
||||
"scope": "public",
|
||||
"content": {
|
||||
"type": {
|
||||
"url": "https://tent.io/types/posts/status",
|
||||
"version": "1.2.0",
|
||||
"view": "full"
|
||||
},
|
||||
"text": "Tent.io is awesome!"
|
||||
}
|
||||
}
|
||||
```
|
|
@ -2,6 +2,5 @@
|
|||
.navbar-inner
|
||||
a.brand href='/' Tent
|
||||
ul.nav
|
||||
== nav_link_with_active 'Intro', '/'
|
||||
== nav_link_with_active 'Blog', '/blog'
|
||||
== nav_link_with_active 'Docs', '/docs'
|
||||
== nav_link_with_active 'Blog', '/blog', top: true
|
||||
== nav_link_with_active 'Docs', '/docs', top: true
|
||||
|
|
25
layouts/doc.slim
Normal file
25
layouts/doc.slim
Normal file
|
@ -0,0 +1,25 @@
|
|||
doctype html
|
||||
html lang='en'
|
||||
head == render '_head'
|
||||
body
|
||||
== render '_navbar'
|
||||
.container
|
||||
.row
|
||||
.span2.doc-nav
|
||||
ul.nav.nav-list.well
|
||||
li.nav-header Tent
|
||||
li == nav_link_with_active 'Protocol Introduction', '/docs'
|
||||
li == nav_link_with_active 'Server Protocol', '/docs/server-protocol'
|
||||
li == nav_link_with_active 'Tent Profile', '/docs/profile'
|
||||
li == nav_link_with_active 'App Authentication', '/docs/app-auth'
|
||||
li == nav_link_with_active 'Server API for Apps', '/docs/app-server'
|
||||
li == nav_link_with_active 'App Notifications', '/docs/app-notifications'
|
||||
li.nav-header Types
|
||||
li == nav_link_with_active 'Post Types', '/docs/post-types'
|
||||
li == nav_link_with_active 'Profile Info Types', '/docs/info-types'
|
||||
li.nav-header Examples
|
||||
li == nav_link_with_active 'Conversation', '/docs/example-conversation'
|
||||
li == nav_link_with_active 'Conversation Thread', '/docs/example-conversation-thread'
|
||||
.span8
|
||||
== yield
|
||||
== render '_footer'
|
10
lib/nav.rb
10
lib/nav.rb
|
@ -1,13 +1,13 @@
|
|||
include Nanoc::Helpers::LinkTo
|
||||
|
||||
def nav_link_with_active(text, target, attributes = {})
|
||||
path = target.is_a?(String) ? target : target.path
|
||||
rep_path = @item_rep.path
|
||||
target_path = target.is_a?(String) ? target : target.path
|
||||
item_path = @item_rep.path.sub(/\..+/, '')
|
||||
|
||||
active = if path == '/'
|
||||
path == rep_path
|
||||
active = if attributes.delete(:top)
|
||||
/^#{target_path}/ =~ item_path
|
||||
else
|
||||
/^#{path}/ =~ rep_path
|
||||
target_path == item_path
|
||||
end
|
||||
|
||||
"<li #{'class="active"' if active}>" + link_to(text, target, attributes) + "</li>"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue