# @http2/api 🏵

Management service for [`@http2/server`](https://gitlab.com/http2/server) and [`@http2/live`](https://gitlab.com/http2/live).

This acts as coordinator of CDN edge nodes.

The core API:

- receives deployments and other input from clients via its API endpoints,
- uploads files to the object store (S3 or DigitalOcean SPaces),
- stores data in MongoDB (Atlas or self-hosted),
- issues certificates using the ACME protocol (LetsEncrypt),
- publishes notifications to the data stream network (PubNub),
- checks authorisation tokens (Auth0).

## Usage

```
http2api <configuration>
```

Where `<configuration>` is the path to a file containing the configuration options. It can be JavaScript or JSON.

Example configuration file: [`api.conf.example.js`](./api.conf.example.js)

## System Dependencies

- [acme.sh](https://acme.sh)

## Service Dependencies

- [LetsEncrypt](https://letsencrypt.org) or ACME API-compatible Certificate Authority
- [Auth0](https://www.auth0.com)
- [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) or any MongoDB instance
- [DigitalOcean Spaces](https://www.digitalocean.com/products/object-storage/) or [AWS S3](https://aws.amazon.com/s3/) API-compatible object store
- [PubNub](https://www.pubnub.com)

## Environment Variables and Configuration Options

See: [./api.conf.example.js](./api.conf.example.js)

## Setting up AWS S3 IAM

See: [./setup-aws-iam.md](./setup-aws-iam.md)

## Authentication

Supply a JSON Web Token (JWT) to authenticate the request. The token is issued by Auth0 and signed using the `RS256` algorithm.

```
Authorization: Bearer eyJhbGciOiJSUzI1NiI...
```

## Content Type

Requests must include a valid content type header. Typically indicating JSON or a multipart request.

```
curl https://api.http2.live:8888/v1/sites \
  -H "content-type: application/json" \
  ; echo
```

## Errors

A response with HTTP status code 4xx-5xx contains JSON with the following properties.

- `message` A human readable description of the problem.
- `statusCode` The HTTP status code.
- `error` The HTTP status message.

Example:

```json
{
  "message": "Missing uploaded files",
  "error": "Internal Server Error",
  "statusCode": 500
}
```

## IDN

Any use of domain names, in URL path segments or other instances, supports the use of internationalised domain names (IDN). Values are automatically converted to lowercase and normalised to Punycode using the [`ToASCII` algorithm](https://tools.ietf.org/html/rfc3490#section-4.1). For example `💩.EXAMPLE.NET` becomes `xn--ls8h.example.net`.

## Endpoints

### `GET /v2/configurations`

Scope: `global_read`

Retrieve stored configurations for all sites.

Supports the `if-modified-since` header to return a `304` status code if no configurations have been changed.

```js
[
  {
    domain: 'example.net',
    modified: '2020-02-20T02:20:02.202',
    configuration: { ... }
  },
  {
    domain: 'example.com',
    modified: '2020-10-10T10:10:10.101',
    configuration: { ... }
  }
]
```

### `GET /v2/domains/available{?domain}`

Check whether a domain is still available or already taken by a site.

Returns `200` status code if the domain is available, otherwise returns `410` status code. The response body is always empty.

### `GET /v2/domains/suggestions{?project}`

Retrieve a list of suggested and available domains. Up to 5 strings are returned.

Domains are based on the given project name or randomly generated.

```js
[
  'project.example.net',
  'finest-witty-turtle.example.net',
  'magnificent-kind-sloth.example.net'
]
```

### `GET /sites{/domain}/certificate`

*Not yet implemented.*

Retrieve certificate information.

```js
{
  modified: '2020-02-20T02:20:02.202',
  domain: 'example.net',
  san: [
    'example.net',
    '*.example.net',
    'a.example.com',
    'b.example.com'
  ]
}
```

### `PUT /sites{/domain}/certificate`

*Not yet implemented.*

Issue a certificate with the given Subject Alternative Name (SAN or `subjectAltName`) extension field.

```js
{
  san: [
    'example.net',
    '*.example.net',
    'a.example.com',
    'b.example.com'
  ]
}
```

### `GET /v2/sites{/domain}/configuration`

Scope: `global_read` or `deploy`

Retrieve the stored configuration for a domain.

```js
{
  modified: '2020-02-20T02:20:02.202',
  domain: 'example.net',
  configuration: {
    // ... host options ...
  }
}
```

### `PATCH /v2/sites{/domain}/configuration`

*Not yet implemented.*

Edit the site configuration.

### `PUT /v2/sites{/domain}/configuration`

*Not yet implemented.*

Set the site configuration.

### `GET /v2/sites{/domain}/files{/directory}/`

*Not yet implemented.*

List all files in a given directory.

### `DELETE /v2/sites{/domain}/files{/file}`

*Not yet implemented.*

Remove a file.

### `PUT /v2/sites{/domain}/files{/file}`

*Not yet implemented.*

Add or replace a file.

### `GET /v2/sites{/domain}/info`

*Not yet implemented.*

Get site metadata.

### `PATCH /v2/sites{/domain}/info`

*Not yet implemented.*

Edit site metadata.

### `PUT /v2/sites{/domain}/info`

*Not yet implemented.*

Set site metadata.

### `DELETE /v2/sites{/domain}`

Scope: `deploy`

Unpublish a site. This removes all configuration data and files associated with the site.

Returns `200` upon success, with an empty body.

### `PUT /v2/sites{/domain}`

Scope: `deploy`

Deploys a site by the given domain. Optionally provide files and a configuration.

If the `domain` value is invalid, a `400` status is returned. If the site is owned by another user, a `403` status is returned.

Content type of the request must be `multipart/form-data`.

The `configuration` field contains JSON data of the host options. A `400` status is returned if the data does not comply with the [@http2/configuration](https://gitlab.com/http2/configuration) `host` JSON Schema.

There are constraints on the number of individual files as well as the total size of all files.

One or more `directory` fields contain all files to be deployed. The filename may contain a relative path, as per the [`webkitdirectory` attribute](https://wicg.github.io/entries-api/#dom-htmlinputelement-webkitdirectory). Any previously hosted files for the domain are removed. To update or remove only a single file, see the `/v2/sites{/domain}/files{/file}` endpoint.

If a new certificate is required, it will be issued asynchronously.

The response message is also published as a notification.

Returns `200` upon success with an object containing the published domain.

```js
{
  type: 'site-deploy',
  domain: 'example.net',
  isNewDomain: true,
  hasNewFiles: true,
  hasNewConfiguration: true
}
```

### `GET /v2/sites`

List all sites owned by the authenticated user.

```js
[
  {
    modified: '2020-02-20T02:20:02.202',
    userId: 'auth0|1234567890',
    domain: 'example.net'
  },
  {
    modified: '2020-10-10T10:10:10.101',
    userId: 'auth0|abcdef',
    domain: 'example.com'
  }
]
```

### `PATCH /v2/users{/id}`

Update the email address or password of the authenticated user.

### `POST /v1/deploy`

*Deprecated*

Use `PUT /v2/sites{/domain}` instead.

### `POST /v1/sites`

*Deprecated*

Use `PUT /v2/sites{/domain}` instead.

### `GET /`

Retrieve server health information. The `uptime` value is measured in seconds.

```js
{
  status: 'OK',
  uptime: 120
}
```

## Colophon

Made with ❤️ by Sebastiaan Deckers in 🇸🇬 Singapore.
