diff --git a/entryway/src/main.rs b/entryway/src/main.rs index 63c6fc1..73358ae 100644 --- a/entryway/src/main.rs +++ b/entryway/src/main.rs @@ -1,21 +1,11 @@ use router::{ Router, - xrpc::{ - XrpcEndpoint, - ProcedureInput, - Response, - error, - }, + xrpc::XrpcEndpoint, }; -use serde::Deserialize; use atproto::types::Nsid; -use http::status::StatusCode; -use tracing::{ - event, - instrument, - Level, -}; -use std::fmt::Debug; + +mod xrpc; +use xrpc::create_account; struct Config { entryway_url: String, @@ -36,22 +26,3 @@ async fn main() { router.serve().await; } -#[derive(Deserialize, Debug)] -struct CreateAccountInput { - email: Option, - handle: String, - did: Option, - invite_code: Option, - verification_code: Option, - verification_phone: Option, - password: Option, - recovery_key: Option, - plc_op: Option, -} - -#[instrument] -async fn create_account(data: ProcedureInput) -> Response { - event!(Level::INFO, "In create_account"); - - error(StatusCode::OK, "error", "message") -} diff --git a/entryway/src/xrpc/create_account.rs b/entryway/src/xrpc/create_account.rs new file mode 100644 index 0000000..60d979f --- /dev/null +++ b/entryway/src/xrpc/create_account.rs @@ -0,0 +1,186 @@ +use router::xrpc::{ProcedureInput, Response, error}; +use serde::{Deserialize, Serialize}; +use http::status::StatusCode; +use tracing::{event, instrument, Level}; + +#[derive(Deserialize, Debug)] +pub struct CreateAccountInput { + pub email: Option, + pub handle: String, + pub did: Option, + pub invite_code: Option, + pub verification_code: Option, + pub verification_phone: Option, + pub password: Option, + pub recovery_key: Option, + pub plc_op: Option, +} + +#[derive(Serialize, Debug)] +pub struct CreateAccountResponse { + pub handle: String, + pub did: String, + // pub did_doc: Option, // TODO: Define DidDocument type + pub access_jwt: String, + pub refresh_jwt: String, +} + +#[instrument] +pub async fn create_account(data: ProcedureInput) -> Response { + event!(Level::INFO, "Creating account for handle: {}", data.input.handle); + + // TODO: Implement the following steps based on the TypeScript reference: + + // 1. Input validation + let validated_input = match validate_inputs(&data.input).await { + Ok(input) => input, + Err(err) => return err, + }; + + // 2. Check handle and email availability + if let Err(err) = check_availability(&validated_input).await { + return err; + } + + // 3. Generate DID and signing key + let (did, signing_key, plc_op) = match generate_identity(&validated_input).await { + Ok(identity) => identity, + Err(err) => return err, + }; + + // 4. Create actor store entry + if let Err(err) = create_actor_store(&did, &signing_key).await { + return err; + } + + // 5. Create repository + let repo_commit = match create_repository(&did).await { + Ok(commit) => commit, + Err(err) => return err, + }; + + // 6. Submit PLC operation (if needed) + if let Some(op) = plc_op { + if let Err(err) = submit_plc_operation(&did, &op).await { + return err; + } + } + + // 7. Create account and session + let credentials = match create_account_and_session(&validated_input, &did, &repo_commit).await { + Ok(creds) => creds, + Err(err) => return err, + }; + + // 8. Sequence events (identity, account, commit, sync) + if let Err(err) = sequence_events(&did, &validated_input.handle, &repo_commit).await { + return err; + } + + // 9. Update repo root + if let Err(err) = update_repo_root(&did, &repo_commit).await { + return err; + } + + // Return success response + let response = CreateAccountResponse { + handle: validated_input.handle, + did: did.clone(), + access_jwt: credentials.access_jwt, + refresh_jwt: credentials.refresh_jwt, + }; + + event!(Level::INFO, "Account created successfully for DID: {}", did); + + // TODO: Replace with proper JSON response encoding + error(StatusCode::OK, "success", "Account created successfully") +} + +// TODO: Implement these helper functions + +async fn validate_inputs(input: &CreateAccountInput) -> Result { + // Based on validateInputsForLocalPds in the TypeScript version + // - Validate email format and not disposable + // - Validate password length + // - Check invite code if required + // - Normalize and validate handle + todo!("Implement input validation") +} + +async fn check_availability(input: &ValidatedInput) -> Result<(), Response> { + // Check that handle and email are not already taken + todo!("Implement availability checking") +} + +async fn generate_identity(input: &ValidatedInput) -> Result<(String, SigningKey, Option), Response> { + // Generate signing key + // Create DID and PLC operation if not provided + todo!("Implement identity generation") +} + +async fn create_actor_store(did: &str, signing_key: &SigningKey) -> Result<(), Response> { + // Create actor store entry for the new account + todo!("Implement actor store creation") +} + +async fn create_repository(did: &str) -> Result { + // Create empty repository for the account + todo!("Implement repository creation") +} + +async fn submit_plc_operation(did: &str, plc_op: &PlcOp) -> Result<(), Response> { + // Submit PLC operation to register/update DID + todo!("Implement PLC operation submission") +} + +async fn create_account_and_session( + input: &ValidatedInput, + did: &str, + repo_commit: &RepoCommit, +) -> Result { + // Create account record and initial session + // Generate JWT tokens + todo!("Implement account and session creation") +} + +async fn sequence_events(did: &str, handle: &str, repo_commit: &RepoCommit) -> Result<(), Response> { + // Sequence identity, account, commit, and sync events + todo!("Implement event sequencing") +} + +async fn update_repo_root(did: &str, repo_commit: &RepoCommit) -> Result<(), Response> { + // Update repository root reference + todo!("Implement repo root update") +} + +// TODO: Define these types based on our implementation needs + +#[derive(Debug)] +struct ValidatedInput { + handle: String, + email: String, + password: Option, + invite_code: Option, +} + +#[derive(Debug)] +struct SigningKey { + // TODO: Define signing key structure +} + +#[derive(Debug)] +struct PlcOp { + // TODO: Define PLC operation structure +} + +#[derive(Debug)] +struct RepoCommit { + cid: String, + rev: String, +} + +#[derive(Debug)] +struct Credentials { + access_jwt: String, + refresh_jwt: String, +} \ No newline at end of file diff --git a/entryway/src/xrpc/mod.rs b/entryway/src/xrpc/mod.rs new file mode 100644 index 0000000..96b9473 --- /dev/null +++ b/entryway/src/xrpc/mod.rs @@ -0,0 +1,3 @@ +pub mod create_account; + +pub use create_account::create_account; \ No newline at end of file