aboutsummaryrefslogtreecommitdiffstats
path: root/adenosine-pds/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'adenosine-pds/src/lib.rs')
-rw-r--r--adenosine-pds/src/lib.rs134
1 files changed, 44 insertions, 90 deletions
diff --git a/adenosine-pds/src/lib.rs b/adenosine-pds/src/lib.rs
index 07905f9..cca9b0d 100644
--- a/adenosine-pds/src/lib.rs
+++ b/adenosine-pds/src/lib.rs
@@ -2,33 +2,51 @@ use adenosine::created_at_now;
use adenosine::identifiers::{AtUri, Did, Nsid, Ticker, Tid};
use anyhow::{anyhow, Result};
use askama::Template;
-use libipld::Cid;
-use libipld::Ipld;
use log::{debug, error, info, warn};
use rouille::{router, Request, Response};
use serde_json::{json, Value};
-use std::collections::BTreeMap;
use std::fmt;
use std::io::Read;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Mutex;
-mod bsky;
mod db;
-pub mod models;
+mod db_bsky;
mod web;
-pub use adenosine::crypto::{KeyPair, PubKey};
-pub use adenosine::did;
-pub use adenosine::did::DidDocMeta;
-pub use adenosine::repo::{Mutation, RepoCommit, RepoStore};
-pub use adenosine::ucan_p256::P256KeyMaterial;
-use bsky::*;
-pub use db::AtpDatabase;
-pub use models::*;
+use adenosine::app_bsky;
+use adenosine::com_atproto;
+use adenosine::crypto::KeyPair;
+use adenosine::ipld::{ipld_into_json_value, json_value_into_ipld};
+use adenosine::plc;
+use adenosine::plc::DidDocMeta;
+use adenosine::repo::{Mutation, RepoStore};
+use db::AtpDatabase;
+use db_bsky::*;
use web::*;
+#[derive(Debug)]
+pub enum XrpcError {
+ BadRequest(String),
+ NotFound(String),
+ Forbidden(String),
+ MutexPoisoned,
+}
+
+impl std::error::Error for XrpcError {}
+
+impl fmt::Display for XrpcError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::BadRequest(msg) | Self::NotFound(msg) | Self::Forbidden(msg) => {
+ write!(f, "{}", msg)
+ }
+ Self::MutexPoisoned => write!(f, "service mutex poisoned"),
+ }
+ }
+}
+
pub struct AtpService {
pub repo: RepoStore,
pub atp_db: AtpDatabase,
@@ -58,27 +76,6 @@ impl Default for AtpServiceConfig {
}
}
-#[derive(Debug)]
-enum XrpcError {
- BadRequest(String),
- NotFound(String),
- Forbidden(String),
- MutexPoisoned,
-}
-
-impl std::error::Error for XrpcError {}
-
-impl fmt::Display for XrpcError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::BadRequest(msg) | Self::NotFound(msg) | Self::Forbidden(msg) => {
- write!(f, "{}", msg)
- }
- Self::MutexPoisoned => write!(f, "service mutex poisoned"),
- }
- }
-}
-
/// Helper to take an XRPC result (always a JSON object), and transform it to a rouille response
fn xrpc_wrap<S: serde::Serialize>(resp: Result<S>) -> Response {
match resp {
@@ -256,49 +253,6 @@ impl AtpService {
}
}
-/// Intentionally serializing with this instead of DAG-JSON, because ATP schemas don't encode CID
-/// links in any special way, they just pass the CID as a string.
-fn ipld_into_json_value(val: Ipld) -> Value {
- match val {
- Ipld::Null => Value::Null,
- Ipld::Bool(b) => Value::Bool(b),
- Ipld::Integer(v) => json!(v),
- Ipld::Float(v) => json!(v),
- Ipld::String(s) => Value::String(s),
- Ipld::Bytes(b) => Value::String(data_encoding::BASE64_NOPAD.encode(&b)),
- Ipld::List(l) => Value::Array(l.into_iter().map(ipld_into_json_value).collect()),
- Ipld::Map(m) => Value::Object(serde_json::Map::from_iter(
- m.into_iter().map(|(k, v)| (k, ipld_into_json_value(v))),
- )),
- Ipld::Link(c) => Value::String(c.to_string()),
- }
-}
-
-/// Crude reverse generation
-///
-/// Does not handle base64 to bytes, and the link generation is pretty simple (object elements with
-/// key "car"). Numbers always come through as f64 (float).
-fn json_value_into_ipld(val: Value) -> Ipld {
- match val {
- Value::Null => Ipld::Null,
- Value::Bool(b) => Ipld::Bool(b),
- Value::String(s) => Ipld::String(s),
- // TODO: handle numbers better?
- Value::Number(v) => Ipld::Float(v.as_f64().unwrap()),
- Value::Array(l) => Ipld::List(l.into_iter().map(json_value_into_ipld).collect()),
- Value::Object(m) => {
- let map: BTreeMap<String, Ipld> = BTreeMap::from_iter(m.into_iter().map(|(k, v)| {
- if k == "car" && v.is_string() {
- (k, Ipld::Link(Cid::from_str(v.as_str().unwrap()).unwrap()))
- } else {
- (k, json_value_into_ipld(v))
- }
- }));
- Ipld::Map(map)
- }
- }
-}
-
fn xrpc_required_param(request: &Request, key: &str) -> Result<String> {
Ok(request.get_param(key).ok_or(XrpcError::BadRequest(format!(
"require '{}' query parameter",
@@ -424,7 +378,7 @@ fn xrpc_get_handler(
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
let did_doc = srv.atp_db.get_did_doc(&did)?;
let collections: Vec<String> = srv.repo.collections(&did)?;
- let desc = RepoDescribe {
+ let desc = com_atproto::repo::Describe {
name: did.to_string(), // TODO: handle?
did: did.to_string(),
didDoc: did_doc,
@@ -506,9 +460,9 @@ fn xrpc_get_repo_handler(srv: &Mutex<AtpService>, request: &Request) -> Result<V
pub fn create_account(
srv: &mut AtpService,
- req: &AccountRequest,
+ req: &com_atproto::AccountRequest,
create_did_plc: bool,
-) -> Result<AtpSession> {
+) -> Result<com_atproto::Session> {
// check if account already exists (fast path, also confirmed by database schema)
if srv.atp_db.account_exists(&req.handle, &req.email)? {
Err(XrpcError::BadRequest(
@@ -520,7 +474,7 @@ pub fn create_account(
let (did, did_doc) = if create_did_plc {
// generate DID
- let create_op = did::CreateOp::new(
+ let create_op = plc::CreateOp::new(
req.handle.clone(),
srv.config.public_url.clone(),
&srv.pds_keypair,
@@ -576,7 +530,7 @@ fn xrpc_post_handler(
match method {
"com.atproto.account.create" => {
// validate account request
- let req: AccountRequest = rouille::input::json_input(request)
+ let req: com_atproto::AccountRequest = rouille::input::json_input(request)
.map_err(|e| XrpcError::BadRequest(format!("failed to parse JSON body: {}", e)))?;
// TODO: validate handle, email, recoverykey
let mut srv = srv.lock().unwrap();
@@ -602,7 +556,7 @@ fn xrpc_post_handler(
Ok(json!(sess))
}
"com.atproto.session.create" => {
- let req: SessionRequest = rouille::input::json_input(request)
+ let req: com_atproto::SessionRequest = rouille::input::json_input(request)
.map_err(|e| XrpcError::BadRequest(format!("failed to parse JSON body: {}", e)))?;
let mut srv = srv.lock().unwrap();
let keypair = srv.pds_keypair.clone();
@@ -628,7 +582,7 @@ fn xrpc_post_handler(
.resolve_did(&did)?
.expect("DID matches to a handle");
- Ok(json!(AtpSession {
+ Ok(json!(com_atproto::Session {
did: did.to_string(),
name: handle,
accessJwt: jwt.to_string(),
@@ -653,7 +607,7 @@ fn xrpc_post_handler(
Ok(json!({}))
}
"com.atproto.repo.batchWrite" => {
- let batch: RepoBatchWriteBody = rouille::input::json_input(request)?;
+ let batch: com_atproto::repo::BatchWriteBody = rouille::input::json_input(request)?;
// TODO: validate edits against schemas
let did = Did::from_str(&batch.did)?;
let mut srv = srv.lock().unwrap();
@@ -690,7 +644,7 @@ fn xrpc_post_handler(
}
"com.atproto.repo.createRecord" => {
// TODO: validate edits against schemas
- let create: RepoCreateRecord = rouille::input::json_input(request)?;
+ let create: com_atproto::repo::CreateRecord = rouille::input::json_input(request)?;
let did = Did::from_str(&create.did)?;
let collection = Nsid::from_str(&create.collection)?;
let mut srv = srv.lock().unwrap();
@@ -707,7 +661,7 @@ fn xrpc_post_handler(
}
"com.atproto.repo.putRecord" => {
// TODO: validate edits against schemas
- let put: RepoPutRecord = rouille::input::json_input(request)?;
+ let put: com_atproto::repo::PutRecord = rouille::input::json_input(request)?;
let did = Did::from_str(&put.did)?;
let collection = Nsid::from_str(&put.collection)?;
let tid = Tid::from_str(&put.rkey)?;
@@ -725,7 +679,7 @@ fn xrpc_post_handler(
Ok(json!({}))
}
"com.atproto.repo.deleteRecord" => {
- let delete: RepoDeleteRecord = rouille::input::json_input(request)?;
+ let delete: com_atproto::repo::DeleteRecord = rouille::input::json_input(request)?;
let did = Did::from_str(&delete.did)?;
let collection = Nsid::from_str(&delete.collection)?;
let tid = Tid::from_str(&delete.rkey)?;
@@ -754,7 +708,7 @@ fn xrpc_post_handler(
}
// =========== app.bsky methods
"app.bsky.actor.updateProfile" => {
- let profile: ProfileRecord = rouille::input::json_input(request)?;
+ let profile: app_bsky::ProfileRecord = rouille::input::json_input(request)?;
let mut srv = srv.lock().unwrap();
let auth_did = &xrpc_check_auth_header(&mut srv, request, None)?;
bsky_update_profile(&mut srv, auth_did, profile)?;
@@ -865,7 +819,7 @@ fn repo_view_handler(srv: &Mutex<AtpService>, did: &str, request: &Request) -> R
let commit_cid = &srv.repo.lookup_commit(&did)?.unwrap();
let commit = srv.repo.get_commit(commit_cid)?;
let collections: Vec<String> = srv.repo.collections(&did)?;
- let desc = RepoDescribe {
+ let desc = com_atproto::repo::Describe {
name: did.to_string(), // TODO
did: did.to_string(),
didDoc: did_doc,