···11 \/_/
12```
1314-This is an implementation of an ATProto PDS, built with [Axum](https://github.com/tokio-rs/axum) and [Atrium](https://github.com/sugyan/atrium).
15-This PDS implementation uses a SQLite database to store private account information and file storage to store canonical user data.
1617Heavily inspired by David Buchanan's [millipds](https://github.com/DavidBuchanan314/millipds).
18-This implementation forked from the [azure-rust-app](https://github.com/DrChat/azure-rust-app) starter template and the upstream [DrChat/bluepds](https://github.com/DrChat/bluepds).
19-See TODO below for this fork's changes from upstream.
02021If you want to see this fork in action, there is a live account hosted by this PDS at [@teq.shatteredsky.net](https://bsky.app/profile/teq.shatteredsky.net)!
2223> [!WARNING]
24-> This PDS is undergoing heavy development. Do _NOT_ use this to host your primary account or any important data!
2526## Quick Start
27```
···4546This is about half of the 3,000 OCPU hours and 18,000 GB hours available per month for free on the VM.Standard.A1.Flex shape. This is _without_ optimizing for costs. The PDS can likely be made much cheaper.
4748-## Code map
49-```
50-* migrations/ - SQLite database migrations
51-* src/
52- * endpoints/ - ATProto API endpoints
53- * auth.rs - Authentication primitives
54- * config.rs - Application configuration
55- * did.rs - Decentralized Identifier helpers
56- * error.rs - Axum error helpers
57- * firehose.rs - ATProto firehose producer
58- * main.rs - Main entrypoint
59- * metrics.rs - Definitions for telemetry instruments
60- * oauth.rs - OAuth routes
61- * plc.rs - Functionality to access the Public Ledger of Credentials
62- * storage.rs - Helpers to access user repository storage
63-```
64-65## To-do
66-### Teq's fork
67-- [ ] OAuth
68- - [X] `/.well-known/oauth-protected-resource` - Authorization Server Metadata
69- - [X] `/.well-known/oauth-authorization-server`
70- - [X] `/par` - Pushed Authorization Request
71- - [X] `/client-metadata.json` - Client metadata discovery
72- - [X] `/oauth/authorize`
73- - [X] `/oauth/authorize/sign-in`
74- - [X] `/oauth/token`
75- - [ ] Authorization flow - Backend client
76- - [X] Authorization flow - Serverless browser app
77- - [ ] DPoP-Nonce
78- - [ ] Verify JWT signature with JWK
79-- [ ] Email verification
80-- [ ] 2FA
81-- [ ] Admin endpoints
82-- [ ] App passwords
83-- [X] `listRecords` fixes
84- - [X] Fix collection prefixing (terminate with `/`)
85- - [X] Fix cursor handling (return `cid` instead of `key`)
86-- [X] Session management (JWT)
87- - [X] Match token fields to reference implementation
88- - [X] RefreshSession from Bluesky Client
89- - [X] Respond with JSON error message `ExpiredToken`
90-- [X] Cursor handling
91- - [X] Implement time-based unix microsecond sequences
92- - [X] Startup with present cursor
93-- [X] Respond `RecordNotFound`, required for:
94- - [X] app.bsky.feed.postgate
95- - [X] app.bsky.feed.threadgate
96- - [ ] app.bsky... (profile creation?)
97-- [X] Linting
98- - [X] Rustfmt
99- - [X] warnings
100- - [X] deprecated-safe
101- - [X] future-incompatible
102- - [X] keyword-idents
103- - [X] let-underscore
104- - [X] nonstandard-style
105- - [X] refining-impl-trait
106- - [X] rust-2018-idioms
107- - [X] rust-2018/2021/2024-compatibility
108- - [X] ungrouped
109- - [X] Clippy
110- - [X] nursery
111- - [X] correctness
112- - [X] suspicious
113- - [X] complexity
114- - [X] perf
115- - [X] style
116- - [X] pedantic
117- - [X] cargo
118- - [X] ungrouped
119-120-### High-level features
121-- [ ] Storage backend abstractions
122- - [ ] Azure blob storage backend
123- - [ ] Backblaze b2(?)
124-- [ ] Telemetry
125- - [X] [Metrics](https://github.com/metrics-rs/metrics) (counters/gauges/etc)
126- - [X] Exporters for common backends (Prometheus/etc)
127-128### APIs
129-- [X] [Service proxying](https://atproto.com/specs/xrpc#service-proxying)
130-- [X] UG /xrpc/_health (undocumented, but impl by reference PDS)
131<!-- - [ ] xx /xrpc/app.bsky.notification.registerPush
132- app.bsky.actor
133- - [X] AG /xrpc/app.bsky.actor.getPreferences
134 - [ ] xx /xrpc/app.bsky.actor.getProfile
135 - [ ] xx /xrpc/app.bsky.actor.getProfiles
136- - [X] AP /xrpc/app.bsky.actor.putPreferences
137- app.bsky.feed
138 - [ ] xx /xrpc/app.bsky.feed.getActorLikes
139 - [ ] xx /xrpc/app.bsky.feed.getAuthorFeed
···157- com.atproto.identity
158 - [ ] xx /xrpc/com.atproto.identity.getRecommendedDidCredentials
159 - [ ] AP /xrpc/com.atproto.identity.requestPlcOperationSignature
160- - [X] UG /xrpc/com.atproto.identity.resolveHandle
161 - [ ] AP /xrpc/com.atproto.identity.signPlcOperation
162 - [ ] xx /xrpc/com.atproto.identity.submitPlcOperation
163- - [X] AP /xrpc/com.atproto.identity.updateHandle
164<!-- - com.atproto.moderation
165 - [ ] xx /xrpc/com.atproto.moderation.createReport -->
166- com.atproto.repo
···168 - [X] AP /xrpc/com.atproto.repo.createRecord
169 - [X] AP /xrpc/com.atproto.repo.deleteRecord
170 - [X] UG /xrpc/com.atproto.repo.describeRepo
171- - [X] UG /xrpc/com.atproto.repo.getRecord
172- - [ ] xx /xrpc/com.atproto.repo.importRepo
173- - [ ] xx /xrpc/com.atproto.repo.listMissingBlobs
174 - [X] UG /xrpc/com.atproto.repo.listRecords
175 - [X] AP /xrpc/com.atproto.repo.putRecord
176 - [X] AP /xrpc/com.atproto.repo.uploadBlob
···178 - [ ] xx /xrpc/com.atproto.server.activateAccount
179 - [ ] xx /xrpc/com.atproto.server.checkAccountStatus
180 - [ ] xx /xrpc/com.atproto.server.confirmEmail
181- - [X] UP /xrpc/com.atproto.server.createAccount
182 - [ ] xx /xrpc/com.atproto.server.createAppPassword
183- - [X] AP /xrpc/com.atproto.server.createInviteCode
184 - [ ] xx /xrpc/com.atproto.server.createInviteCodes
185- - [X] UP /xrpc/com.atproto.server.createSession
186 - [ ] xx /xrpc/com.atproto.server.deactivateAccount
187 - [ ] xx /xrpc/com.atproto.server.deleteAccount
188 - [ ] xx /xrpc/com.atproto.server.deleteSession
189- - [X] UG /xrpc/com.atproto.server.describeServer
190 - [ ] xx /xrpc/com.atproto.server.getAccountInviteCodes
191- - [X] AG /xrpc/com.atproto.server.getServiceAuth
192- - [X] AG /xrpc/com.atproto.server.getSession
193 - [ ] xx /xrpc/com.atproto.server.listAppPasswords
194 - [ ] xx /xrpc/com.atproto.server.refreshSession
195 - [ ] xx /xrpc/com.atproto.server.requestAccountDelete
···201 - [ ] xx /xrpc/com.atproto.server.revokeAppPassword
202 - [ ] xx /xrpc/com.atproto.server.updateEmail
203- com.atproto.sync
204- - [X] UG /xrpc/com.atproto.sync.getBlob
205- - [X] UG /xrpc/com.atproto.sync.getBlocks
206- - [X] UG /xrpc/com.atproto.sync.getLatestCommit
207- - [X] UG /xrpc/com.atproto.sync.getRecord
208- - [X] UG /xrpc/com.atproto.sync.getRepo
209- - [X] UG /xrpc/com.atproto.sync.getRepoStatus
210- - [X] UG /xrpc/com.atproto.sync.listBlobs
211- - [X] UG /xrpc/com.atproto.sync.listRepos
212- - [X] UG /xrpc/com.atproto.sync.subscribeRepos
213214-## Quick Deployment (Azure CLI)
215-```
216-az group create --name "webapp" --location southcentralus
217-az deployment group create --resource-group "webapp" --template-file .\deployment.bicep --parameters webAppName=testapp
218-219-az acr login --name <insert name of ACR resource here>
220-docker build -t <ACR>.azurecr.io/testapp:latest .
221-docker push <ACR>.azurecr.io/testapp:latest
222-```
223-## Quick Deployment (NixOS)
224```nix
225{
226 inputs = {
···11 \/_/
12```
1314+This is an implementation of an ATProto PDS, built with [Axum](https://github.com/tokio-rs/axum), [rsky](https://github.com/blacksky-algorithms/rsky/) and [Atrium](https://github.com/sugyan/atrium).
15+This PDS implementation uses a SQLite database and [diesel.rs](https://diesel.rs/) ORM to store canonical user data, and file system storage to store user blobs.
1617Heavily inspired by David Buchanan's [millipds](https://github.com/DavidBuchanan314/millipds).
18+This implementation forked from [DrChat/bluepds](https://github.com/DrChat/bluepds), and now makes heavy use of the [rsky-repo](https://github.com/blacksky-algorithms/rsky/tree/main/rsky-repo) repository implementation.
19+The `actor_store` and `account_manager` modules have been reimplemented from [rsky-pds](https://github.com/blacksky-algorithms/rsky/tree/main/rsky-pds) to use a SQLite backend and file storage, which are themselves adapted from the [original Bluesky implementation](https://github.com/bluesky-social/atproto) using SQLite in Typescript.
20+2122If you want to see this fork in action, there is a live account hosted by this PDS at [@teq.shatteredsky.net](https://bsky.app/profile/teq.shatteredsky.net)!
2324> [!WARNING]
25+> This PDS is undergoing heavy development, and this branch is not at an operable release. Do _NOT_ use this to host your primary account or any important data!
2627## Quick Start
28```
···4647This is about half of the 3,000 OCPU hours and 18,000 GB hours available per month for free on the VM.Standard.A1.Flex shape. This is _without_ optimizing for costs. The PDS can likely be made much cheaper.
480000000000000000049## To-do
0000000000000000000000000000000000000000000000000000000000000050### APIs
51+- [ ] [Service proxying](https://atproto.com/specs/xrpc#service-proxying)
52+- [ ] UG /xrpc/_health (undocumented, but impl by reference PDS)
53<!-- - [ ] xx /xrpc/app.bsky.notification.registerPush
54- app.bsky.actor
55+ - [ ] AG /xrpc/app.bsky.actor.getPreferences
56 - [ ] xx /xrpc/app.bsky.actor.getProfile
57 - [ ] xx /xrpc/app.bsky.actor.getProfiles
58+ - [ ] AP /xrpc/app.bsky.actor.putPreferences
59- app.bsky.feed
60 - [ ] xx /xrpc/app.bsky.feed.getActorLikes
61 - [ ] xx /xrpc/app.bsky.feed.getAuthorFeed
···79- com.atproto.identity
80 - [ ] xx /xrpc/com.atproto.identity.getRecommendedDidCredentials
81 - [ ] AP /xrpc/com.atproto.identity.requestPlcOperationSignature
82+ - [ ] UG /xrpc/com.atproto.identity.resolveHandle
83 - [ ] AP /xrpc/com.atproto.identity.signPlcOperation
84 - [ ] xx /xrpc/com.atproto.identity.submitPlcOperation
85+ - [ ] AP /xrpc/com.atproto.identity.updateHandle
86<!-- - com.atproto.moderation
87 - [ ] xx /xrpc/com.atproto.moderation.createReport -->
88- com.atproto.repo
···90 - [X] AP /xrpc/com.atproto.repo.createRecord
91 - [X] AP /xrpc/com.atproto.repo.deleteRecord
92 - [X] UG /xrpc/com.atproto.repo.describeRepo
93+ - [ ] UG /xrpc/com.atproto.repo.getRecord
94+ - [X] xx /xrpc/com.atproto.repo.importRepo
95+ - [X] xx /xrpc/com.atproto.repo.listMissingBlobs
96 - [X] UG /xrpc/com.atproto.repo.listRecords
97 - [X] AP /xrpc/com.atproto.repo.putRecord
98 - [X] AP /xrpc/com.atproto.repo.uploadBlob
···100 - [ ] xx /xrpc/com.atproto.server.activateAccount
101 - [ ] xx /xrpc/com.atproto.server.checkAccountStatus
102 - [ ] xx /xrpc/com.atproto.server.confirmEmail
103+ - [ ] UP /xrpc/com.atproto.server.createAccount
104 - [ ] xx /xrpc/com.atproto.server.createAppPassword
105+ - [ ] AP /xrpc/com.atproto.server.createInviteCode
106 - [ ] xx /xrpc/com.atproto.server.createInviteCodes
107+ - [ ] UP /xrpc/com.atproto.server.createSession
108 - [ ] xx /xrpc/com.atproto.server.deactivateAccount
109 - [ ] xx /xrpc/com.atproto.server.deleteAccount
110 - [ ] xx /xrpc/com.atproto.server.deleteSession
111+ - [ ] UG /xrpc/com.atproto.server.describeServer
112 - [ ] xx /xrpc/com.atproto.server.getAccountInviteCodes
113+ - [ ] AG /xrpc/com.atproto.server.getServiceAuth
114+ - [ ] AG /xrpc/com.atproto.server.getSession
115 - [ ] xx /xrpc/com.atproto.server.listAppPasswords
116 - [ ] xx /xrpc/com.atproto.server.refreshSession
117 - [ ] xx /xrpc/com.atproto.server.requestAccountDelete
···123 - [ ] xx /xrpc/com.atproto.server.revokeAppPassword
124 - [ ] xx /xrpc/com.atproto.server.updateEmail
125- com.atproto.sync
126+ - [ ] UG /xrpc/com.atproto.sync.getBlob
127+ - [ ] UG /xrpc/com.atproto.sync.getBlocks
128+ - [ ] UG /xrpc/com.atproto.sync.getLatestCommit
129+ - [ ] UG /xrpc/com.atproto.sync.getRecord
130+ - [ ] UG /xrpc/com.atproto.sync.getRepo
131+ - [ ] UG /xrpc/com.atproto.sync.getRepoStatus
132+ - [ ] UG /xrpc/com.atproto.sync.listBlobs
133+ - [ ] UG /xrpc/com.atproto.sync.listRepos
134+ - [ ] UG /xrpc/com.atproto.sync.subscribeRepos
135136+## Deployment (NixOS)
000000000137```nix
138{
139 inputs = {