docs: Add NodeInfo 2.1 specification and schema

Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale/-/merge_requests/2499>
environments/review-docs-nodei-zb4y5a/deployments/18082
Ciarán Ainsworth 2023-06-18 14:46:01 +02:00 zatwierdzone przez Ciarán Ainsworth
rodzic 232ca0f050
commit 1b57d3e36e
5 zmienionych plików z 837 dodań i 2 usunięć

Wyświetl plik

@ -0,0 +1 @@
Added NodeInfo 2.1 specification

Wyświetl plik

@ -69,13 +69,19 @@ templates_path = ["_templates"]
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = ".rst"
source_suffix = ".md"
# The root toctree document.
root_doc = "index"
# Enable colon fences
myst_enable_extensions = ["colon_fence", "attrs_block"]
myst_enable_extensions = [
"colon_fence",
"attrs_block",
"tasklist",
"fieldlist",
"deflist",
]
# Autogenerate anchors

Wyświetl plik

@ -94,6 +94,17 @@ contributor/translation
```
```{toctree}
---
maxdepth: 1
caption: Specifications
hidden: true
---
specs/nodeinfo21/index
```
```{toctree}
---
caption: Reference

Wyświetl plik

@ -0,0 +1,218 @@
# NodeInfo 2.1
{bdg-secondary}`In progress`
## The issue
Servers need to communicate their capabilities in a network of communicating nodes to negotiate a common protocol.
## Proposed solution
Use [NodeInfo](http://nodeinfo.diaspora.software), a well-defined standard for exactly this purpose that's widely used within the Fediverse.
## Feature behavior
The NodeInfo endpoint is used to communicate the features and capabilities of a server. It presents details about:
- Implemented protocols
- Enabled features
- Usage statistics
- Content metadata
:::{seealso}
Read [the NodeInfo specification for more information](https://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.1#$$expand).
:::
The NodeInfo endpoint must contain all mandatory elements listed in the specification. In addition to this, Funkwhale's implementation should list additional details about the instance.
`actorId` (URL)
: The URL of the pod service actor
`private` (Boolean)
: Whether the pod is private
`shortDescription` (String)
: A short description of the pod
`longDescription` (String)
: A longer description of the pod
`rules` (String)
: A collection of rules users of the pod must abide by
`contactEmail` (Email address)
: The email address of the pod administrator
`terms` (String)
: The terms of use associated with the pod
`nodeName`(String)
: The name of the pod
`banner` (URL)
: The URL of the banner image
`defaultUploadQuota` (Number)
: The default upload quota (in megabytes) allowed for new users
`library.federationEnabled` (Boolean)
: Whether federation is enabled
`library.anonymousCanListen` (Boolean)
: Whether public endpoints require authentication
`supportedUploadExtensions` (Array\<String\>)
: A list of file extensions enabled for upload
`allowlist.enabled` (Boolean)
: Whether the pod admin has enabled allow-listing
`allowlist.domains` (Array\<String\>)
: A list of allowed domains
`funkwhaleSupportMessageEnabled` (Boolean)
: Whether the admin has enabled the Funkwhale project support message
`instanceSupportMessage` (String)
: The support message associated with the instance
`content.top_music_categories` (Array\<Object\>)
: The top three music genres and the number of uploads tagged with them
`content.top_podcast_categories` (Array\<Object\>)
: The top three podcast categories and the number of uploads tagged with them
`instance_policy.moderation_policy` (String)
: The moderation policy of the pod
`instance_policy.terms_of_service` (String)
: The terms of service of the pod
`instance_policy.languages` (Array\<String\>)
: The languages spoken by the pod administrators
`instance_policy.location` (String)
: The country the pod is located in
`federation.follows_instances` (Number)
: The number of Funkwhale pods that the target pod follows
`federation.following_instances` (Number)
: The number of Funkwhale pods that publicly follow the target pod
`features` (Array\<String\>)
: A list of enabled features
### Backend
A new NodeInfo endpoint will be created that sits alongside the existing `v1` endpoint for backwards-compatibility.
```text
/api/v2/instance/nodeinfo/2.1
```
This endpoint supports only `GET` requests and responds with the information outlined in the NodeInfo specification.
Example response:
```json
{
"version": "2.1",
"software": {
"name": "Funkwhale",
"version": "1.4.0",
"repository": "https://dev.funkwhale.audio/funkwhale/funkwhale",
"homepage": "https://funkwhale.audio"
},
"protocols": ["activitypub"],
"services": {
"inbound": ["atom1.0"],
"outbound": ["atom1.0"]
},
"openRegistrations": true,
"usage": {
"users": {
"total": 0,
"activeHalfYear": 0,
"activeMonth": 0
},
"localPosts": 0,
"localComments": 0
},
"metadata": {
"actorId": "string",
"private": false,
"shortDescription": "string",
"longDescription": "string",
"rules": "string",
"contactEmail": "user@example.com",
"terms": "string",
"nodeName": "string",
"banner": "string",
"defaultUploadQuota": 0,
"library": {
"federationEnabled": true,
"anonymousCanListen": true
},
"supportedUploadExtensions": ["string"],
"allowList": {
"enabled": true,
"domains": ["string"]
},
"funkwhaleSupportMessageEnabled": true,
"instanceSupportMessage": "string",
"instance_policy": {
"moderation_policy": "string",
"terms_of_service": "string",
"languages": ["string"],
"location": "string"
},
"content": {
"top_music_categories": [
{
"rock": 1256
},
{
"jazz": 604
},
{
"classical": 308
}
],
"top_podcast_categories": [
{
"comedy": 12
},
{
"politics": 4
},
{
"nature": 1
}
],
"federation": {
"followed_instances": 0,
"following_instances": 0
}
},
"features": ["channels", "podcasts", "collections", "audiobooks"]
}
}
```
## Availability
- [ ] Admin panel
- [ ] App frontend
- [ ] CLI
- [x] API
## Responsible parties
Since the actual endpoint is already standardized, Backend developers need only to agree on an implementation. The Frontend group needs to check to see if changing the location of `/.well-known/nodeinfo` has an impact on the web app.
The NodeInfo endpoint MUST be accompanied by a {download}`full OpenAPI schema file <schema.yml>` for ease of reference and implementation.
## Open questions
- [ ] Does changing `/.well-known/nodeinfo` have any implications on the Frontend?

Wyświetl plik

@ -0,0 +1,599 @@
openapi: "3.0.3"
info:
description: "Interactive documentation for [Funkwhale](https://funkwhale.audio) API."
version: "2.0.0"
title: "Funkwhale API"
servers:
- url: "https://demo.funkwhale.audio"
description: "Demo server"
- url: "https://open.audio"
description: "Real server with real content"
- url: "https://{domain}"
description: "Custom server"
variables:
domain:
default: yourdomain
description: "Your Funkwhale Domain"
protocol:
enum:
- "http"
- "https"
default: "https"
tags:
- name: Instance
description: Information about the server
- name: Content
description: Information about content on the server
paths:
/api/v2/instance/nodeinfo/2.1:
get:
tags:
- Instance
summary: Retrieve nodeinfo data
description: Retrieve details about a Funkwhale server using the Nodeinfo standard
operationId: getNodeinfo
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Nodeinfo"
application/xml:
schema:
$ref: "#/components/schemas/Nodeinfo"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/podcasts:
get:
tags:
- Content
summary: Retrieve podcast categories
description: Retrieve a list of podcast categories and the number of uploads tagged with those categories
operationId: getTagsPodcasts
parameters:
- name: q
in: query
required: false
description: A free text field to filter category names
schema:
type: string
- name: page
in: query
required: false
description: The number of the result page you want to return
schema:
type: number
- name: page_size
in: query
required: false
description: The number of results to return on each page. Defaults to 50.
schema:
type: number
- name: ordering
in: query
required: false
description: |
The order in which results are presented. Preface with `-` to return items in descending order.
schema:
type: string
enum:
- "name"
- "creation_date"
- "tagged_items"
- "-name"
- "-creation_date"
- "-tagged_items"
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Categories"
application/xml:
schema:
$ref: "#/components/schemas/Categories"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/podcasts/{category}:
get:
tags:
- Content
summary: Retrieve podcast categories
description: Retrieve a list of podcast categories and the number of uploads tagged with those categories
operationId: getTagPodcasts
parameters:
- name: category
in: path
required: true
description: The category you want to return information about
schema:
type: string
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Category"
application/xml:
schema:
$ref: "#/components/schemas/Category"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/music:
get:
tags:
- Content
summary: Retrieve music genres
description: Retrieve a list of music genres and the number of uploads tagged with those categories
operationId: getTagsMusic
parameters:
- name: q
in: query
required: false
description: A free text field to filter genre names
schema:
type: string
- name: page
in: query
required: false
description: The number of the result page you want to return
schema:
type: number
- name: page_size
in: query
required: false
description: The number of results to return on each page. Defaults to 50.
schema:
type: number
- name: ordering
in: query
required: false
description: |
The order in which results are presented. Preface with `-` to return items in descending order.
schema:
type: string
enum:
- "name"
- "creation_date"
- "tagged_items"
- "-name"
- "-creation_date"
- "-tagged_items"
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Genres"
application/xml:
schema:
$ref: "#/components/schemas/Genres"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v2/tags/music/{genre}:
get:
tags:
- Content
summary: Retrieve podcast categories
description: Retrieve a list of podcast categories and the number of uploads tagged with those categories
operationId: getTagMusic
parameters:
- name: genre
in: path
required: true
description: The genre you want to return information about
schema:
type: string
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/Genre"
application/xml:
schema:
$ref: "#/components/schemas/Genre"
"401":
$ref: "#/components/responses/Unauthorized"
components:
responses:
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
code: 401
message: User not authorized
application/xml:
schema:
$ref: "#/components/schemas/Error"
example:
code: 401
message: User not authorized
schemas:
Categories:
type: object
properties:
total:
type: number
next:
type: string
format: url
previous:
type: string
format: url
results:
type: array
items:
$ref: "#/components/schemas/Category"
example:
total: 5
next: https://demo.funkwhale.audio/api/v2/categories?page=2&page_size=2&q=crime
previous: null
results:
- category: "True Crime"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/True%20Crime"
- category: "True Stories"
created_date: "2023-12-15T23:32:52.000Z"
tagged_items: 200
results_page: "https://demo.funkwhale.audio/library/categories/True%20Stories"
Category:
type: object
properties:
category:
type: string
created_date:
type: string
format: date-time
tagged_items:
type: number
results_page:
type: string
format: url
example:
category: "True Crime"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/True%20Crime"
Genres:
type: object
properties:
total:
type: number
next:
type: string
format: url
previous:
type: string
format: url
results:
type: array
items:
$ref: "#/components/schemas/Genre"
example:
total: 5
next: https://demo.funkwhale.audio/api/v2/categories?page=2&page_size=2&q=rock
previous: null
results:
- genre: "Acoustic Rock"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/Acoustic%20Rock"
- genre: "Surf Rock"
created_date: "2023-12-15T23:32:52.000Z"
tagged_items: 200
results_page: "https://demo.funkwhale.audio/library/categories/Surf%20Rock"
Genre:
type: object
properties:
genre:
type: string
created_date:
type: string
format: date-time
tagged_items:
type: number
results_page:
type: string
format: url
example:
genre: "Acoustic Rock"
created_date: "2020-01-01T00:00:00.000Z"
tagged_items: 5
results_page: "https://demo.funkwhale.audio/library/categories/Acoustic%20Rock"
Nodeinfo:
type: object
required:
- version
- software
- protocols
- services
- openRegistrations
- usage
- metadata
properties:
version:
type: string
enum:
- "2.1"
software:
type: object
required:
- name
- version
properties:
name:
type: string
enum:
- "Funkwhale"
version:
type: string
example: "1.4.0"
repository:
type: string
format: url
enum:
- "https://dev.funkwhale.audio/funkwhale/funkwhale"
homepage:
type: string
format: url
enum:
- "https://funkwhale.audio"
protocols:
type: array
minItems: 1
items:
type: string
enum:
- "activitypub"
- "buddycloud"
- "dfrn"
- "diaspora"
- "libertree"
- "ostatus"
- "pumpio"
- "tent"
- "xmpp"
- "zot"
example:
- "activitypub"
services:
type: object
required:
- inbound
- outbound
properties:
inbound:
type: array
items:
type: string
enum:
- "atom1.0"
- "gnusocial"
- "imap"
- "pnut"
- "pop3"
- "pumpio"
- "rss2.0"
- "twitter"
outbound:
type: array
items:
type: string
enum:
- "atom1.0"
- "blogger"
- "buddycloud"
- "diaspora"
- "dreamwidth"
- "drupal"
- "facebook"
- "friendica"
- "gnusocial"
- "google"
- "insanejournal"
- "libertree"
- "linkedin"
- "livejournal"
- "mediagoblin"
- "myspace"
- "pinterest"
- "pnut"
- "posterous"
- "pumpio"
- "redmatrix"
- "rss2.0"
- "smtp"
- "tent"
- "tumblr"
- "twitter"
- "wordpress"
- "xmpp"
openRegistrations:
type: boolean
usage:
type: object
required:
- users
properties:
users:
type: object
properties:
total:
type: integer
minimum: 0
activeHalfYear:
type: integer
minimum: 0
activeMonth:
type: integer
minimum: 0
localPosts:
type: integer
minimum: 0
localComments:
type: integer
minimum: 0
metadata:
type: object
properties:
actorId:
type: string
format: url
private:
type: boolean
shortDescription:
type: string
longDescription:
type: string
rules:
type: string
contactEmail:
type: string
format: email
terms:
type: string
nodeName:
type: string
banner:
type: string
format: url
defaultUploadQuota:
type: integer
library:
type: object
properties:
federationEnabled:
type: boolean
anonymousCanListen:
type: boolean
supportedUploadExtensions:
type: array
items:
type: string
allowList:
type: object
properties:
enabled:
type: boolean
domains:
type: array
items:
type: string
funkwhaleSupportMessageEnabled:
type: boolean
instanceSupportMessage:
type: string
instance_policy:
type: object
properties:
moderation_policy:
type: string
format: url
terms_of_service:
type: string
format: url
languages:
type: array
items:
type: string
location:
type: string
content:
type: object
properties:
top_music_categories:
type: array
items:
type: object
additionalProperties:
type: integer
example:
- "rock": 1256
- "jazz": 604
- "classical": 308
top_podcast_categories:
type: array
items:
type: object
additionalProperties:
type: integer
example:
- "comedy": 12
- "politics": 4
- "nature": 1
federation:
type: object
properties:
followed_instances:
type: integer
following_instances:
type: integer
features:
type: array
items:
type: string
example:
- "channels"
- "podcasts"
- "collections"
- "audiobooks"
Error:
type: object
properties:
code:
type: string
message:
type: string
required:
- code
- message
securitySchemes:
oauth2:
type: oauth2
description: This API uses OAuth 2 with the Authorization Code flow. You can register an app using the /oauth/apps/ endpoint.
flows:
authorizationCode:
authorizationUrl: /authorize
tokenUrl: /api/v1/oauth/token/
refreshUrl: /api/v1/oauth/token/
scopes:
"read": "Read-only access to all user data"
"write": "Write-only access on all user data"
"read:edits": "Read-only access to edits"
"write:edits": "Write-only access to edits"
"read:favorites": "Read-only access to favorites"
"write:favorites": "Write-only access to favorits"
"read:filters": "Read-only to to content filters"
"write:filters": "Write-only access to content-filters"
"read:follows": "Read-only to follows"
"write:follows": "Write-only access to follows"
"read:libraries": "Read-only access to library and uploads"
"write:libraries": "Write-only access to libraries"
"read:listenings": "Read-only access to listening history"
"write:listenings": "Write-only access to listening history"
"read:notifications": "Read-only access to notifications"
"write:notifications": "Write-only access to notifications"
"read:playlists": "Read-only access to playlists"
"write:playlists": "Write-only access to playlists"
"read:profile": "Read-only access to profile data"
"write:profile": "Write-only access to profile data"
"read:radios": "Read-only access to radios"
"write:radios": "Write-only access to radios"
"read:reports": "Read-only access to reports"
"write:reports": "Write-only access to reports"
"read:security": "Read-only access security settings"
"write:security": "write-only access security settings"
security:
- oauth2: []