objective categorical abstract machine language personal data server
1# pegasus
2
3is an [atproto PDS](https://atproto.com/guides/glossary#pds-personal-data-server), along with an assortment of atproto-relevant libraries, written in OCaml.
4
5## table of contents
6
7- [Running It](#running-it)
8- [Environment](#environment)
9 - [SMTP](#smtp)
10 - [S3](#s3)
11- [Development](#development)
12- [Libraries](#libraries)
13 - [ipld](#ipld) - IPLD implementation (CIDs, CAR, DAG-CBOR)
14 - [kleidos](#kleidos) - Cryptographic key management
15 - [mist](#mist) - Merkle Search Tree implementation
16 - [hermes](#hermes) - XRPC client
17 - [frontend](#frontend) - Web interface
18 - [pegasus](#pegasus-library) - PDS implementation
19
20## running it
21
22After cloning this repo, start by running
23
24```
25docker compose pull
26```
27
28to pull the latest image, or
29
30```
31docker compose build
32```
33
34to build from source.
35
36Next, run
37
38```
39docker compose run --rm --entrypoint gen-keys pds
40```
41
42to generate some of the environment variables you'll need.
43
44Copy [`.env.example`](.env.example) to `.env` and fill in the environment variables marked as required. See [Environment](#environment) for further details on configuration.
45
46After that, run
47
48```
49docker compose up -d
50```
51
52to start the PDS, then navigate to `https://{PDS_HOSTNAME}/admin` to log in with the admin password you specified and create an invite code or a new account on the PDS.
53
54## environment
55
56Documentation for most environment variables can be found in [`.env.example`](.env.example). There are two optional categories of environment variables that add functionality:
57
58### SMTP
59
60The PDS can email users for password changes, identity updates, and account deletion. If these environment variables are not set, emails will instead be logged to the process' stdout.
61
62- `PDS_SMTP_AUTH_URI` — The URI to connect to the mail server. This should look like `smtp[s]://user:pass@host[:port]`.
63- `PDS_SMTP_STARTTLS=false` — Whether to use STARTTLS when connecting to the mail server. Defaults to false. If true, the connection will default to port 587. If false, the connection will default to port 465. Setting a port in `PDS_SMTP_AUTH_URI` will override either one.
64- `PDS_SMTP_SENDER` — The identity to send emails as. Can be an email address (`e@mail.com`) or a mailbox (`Name <e@mail.com>`).
65
66### S3
67
68The PDS can be configured to back up server data to and/or store blobs in S3(-compatible storage).
69
70- `PDS_S3_BLOBS_ENABLED=false` — Whether to store blobs in S3. By default, blobs are stored locally in `{PDS_DATA_DIR}/blobs/[did]/`.
71- `PDS_S3_BACKUPS_ENABLED=false` — Whether to back up data to S3.
72- `PDS_S3_BACKUP_INTERVAL_S=3600` — How often to back up to S3, in seconds.
73- `PDS_S3_ENDPOINT`, `PDS_S3_REGION`, `PDS_S3_BUCKET`, `PDS_S3_ACCESS_KEY`, `PDS_S3_SECRET_KEY` — S3 configuration.
74- `PDS_S3_CDN_URL` — You may optionally set this to redirect `getBlob` requests to `{PDS_S3_CDN_URL}/blobs/{did}/{cid}`. When unset, blobs will be fetched either from local storage or from S3, depending on `PDS_S3_BLOBS_ENABLED`.
75
76## libraries
77
78This repo contains several libraries in addition to the `pegasus` PDS. Each library has its own README with detailed documentation.
79
80### <a id="ipld"></a>[ipld](ipld/README.md)
81
82A mostly [DASL-compliant](https://dasl.ing/) implementation of [CIDs](https://dasl.ing/cid.html), [CAR](https://dasl.ing/car.html), and [DAG-CBOR](https://dasl.ing/drisl.html).
83
84Provides content addressing primitives for IPLD: Content Identifiers (CIDs), Content Addressable aRchives (CAR), and deterministic CBOR encoding.
85
86### <a id="kleidos"></a>[kleidos](kleidos/README.md)
87
88An atproto-valid interface for secp256k1 and secp256r1 key management, signing/verifying, and encoding/decoding.
89
90Handles cryptographic operations for both K-256 and P-256 elliptic curves with multikey encoding and did:ket generation.
91
92### <a id="mist"></a>[mist](mist/README.md)
93
94A [Merkle Search Tree](https://atproto.com/specs/repository#mst-structure) implementation for data repository purposes with a swappable storage backend.
95
96### <a id="hermes"></a>[hermes](hermes/README.md)
97
98An XRPC client for atproto with three components:
99
100- **hermes** - Core XRPC client library
101- **hermes_ppx** - PPX extension for ergonomic API calls
102- **hermes-cli** - CLI to generate OCaml types from atproto lexicons
103
104### <a id="frontend"></a>[frontend](frontend/README.md)
105
106The PDS frontend, containing the admin dashboard and account page.
107
108### <a id="pegasus-library"></a>[pegasus](pegasus/README.md)
109
110The PDS implementation.
111
112## development
113
114To start developing, you'll need:
115
116- [`opam`](https://opam.ocaml.org/doc/Install.html), the OCaml Package Manager
117- and the following packages, or their equivalents on your operating system: `cmake git libev-dev libffi-dev libgmp-dev libssl-dev libsqlite3-dev libpcre3-dev pkg-config`
118
119Start by creating an opam switch; similar to a Python virtual environment, storing the dependencies for this project and a specific compiler version. After that, install [`dune`](https://dune.build), the build system/package manager pegasus uses.
120
121```
122opam switch create . 5.2.1 --no-install
123opam install dune
124```
125
126You may need to run `eval $(opam env)` for this to work. Next, run
127
128```
129dune pkg lock
130```
131
132to solve dependencies.
133
134Set the required environment variables (see [Environment](#environment)), noting that the program won't automatically read from `.env`, then either run
135
136```
137dune exec pegasus
138```
139
140to run the program directly, or
141
142```
143dune build
144```
145
146to produce an executable that you'll likely find in `_build/default/bin`.
147
148For development, you'll also want to run
149
150```
151dune tools exec ocamlformat
152dune tools exec ocamllsp
153```
154
155to download the formatter and LSP services. You can run `dune fmt` to format the project.
156
157The [frontend](frontend/) and [email templates](pegasus/lib/emails/) are written in [MLX](https://github.com/ocaml-mlx/mlx), a JSX-ish OCaml dialect. To format them, you'll need to `opam install ocamlformat-mlx`, then `ocamlformat-mlx -i ./{frontend,pegasus}/**/*.mlx`.