atproto-identity 0.2.0

An ATProtocol identity library
Documentation

atproto-identity

A Rust library for AT Protocol identity resolution and management.

Overview

atproto-identity provides comprehensive support for resolving and managing identities in the AT Protocol ecosystem. This library handles multiple DID (Decentralized Identifier) methods including did:plc and did:web, as well as AT Protocol handle resolution via both DNS and HTTP methods.

This project was extracted from the open-sourced Smokesignal project and is designed to be a standalone, reusable library for AT Protocol identity operations.

Features

  • Handle Resolution: Resolve AT Protocol handles to DIDs using DNS TXT records and HTTP well-known endpoints
  • DID Document Retrieval: Fetch and parse DID documents for did:plc and did:web identifiers
  • Multiple Resolution Methods: Supports both DNS and HTTP-based handle resolution with conflict detection
  • Configurable DNS: Custom DNS nameserver support with fallback to system defaults
  • Cryptographic Key Operations: Support for P-256 and K-256 key identification, signature validation, and signing
  • Structured Logging: Built-in tracing support for debugging and monitoring
  • Type Safety: Comprehensive error handling with structured error types

Supported DID Methods

  • did-method-plc: Public Ledger of Credentials DIDs via PLC directory
  • did-method-web: Web-based DIDs following the did:web specification with URL conversion utilities
  • ATProtocol Handle Resolution: AT Protocol handles (e.g., ngerakines.me) can be resolved to DIDs

Installation

Add this to your Cargo.toml:

[dependencies]
atproto-identity = "0.2.0"

Usage

Basic Handle Resolution

use atproto_identity::resolve::{resolve_subject, create_resolver};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let http_client = reqwest::Client::new();
    let dns_resolver = create_resolver(&[]);
    
    let did = resolve_subject(&http_client, &dns_resolver, "ngerakines.me").await?;
    println!("Resolved DID: {}", did);
    
    Ok(())
}

DID Document Retrieval

use atproto_identity::{plc, web};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let http_client = reqwest::Client::new();
    
    // Query PLC DID document
    let plc_doc = plc::query(&http_client, "plc.directory", "did:plc:example123").await?;
    
    // Query Web DID document
    let web_doc = web::query(&http_client, "did:web:example.com").await?;
    
    // Convert Web DID to URL (for custom processing)
    let did_url = web::did_web_to_url("did:web:example.com")?;
    println!("DID document URL: {}", did_url);
    
    Ok(())
}

Web DID URL Conversion

The web module provides utilities for converting DID identifiers to their HTTPS document URLs:

use atproto_identity::web;

fn main() -> anyhow::Result<()> {
    // Convert simple hostname DID
    let url = web::did_web_to_url("did:web:example.com")?;
    // Returns: "https://example.com/.well-known/did.json"
    
    // Convert DID with path components  
    let url = web::did_web_to_url("did:web:example.com:path:subpath")?;
    // Returns: "https://example.com/path/subpath/did.json"
    
    Ok(())
}

Cryptographic Key Operations

The key module provides utilities for working with cryptographic keys:

use atproto_identity::key::{identify_key, validate, KeyType};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Identify a key from a DID key string
    let key_data = identify_key("did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA")?;
    
    match key_data.0 {
        KeyType::K256Public => println!("K-256 public key"),
        KeyType::P256Public => println!("P-256 public key"),
        KeyType::K256Private => println!("K-256 private key"),
        KeyType::P256Private => println!("P-256 private key"),
    }
    
    // Validate a signature (example with dummy data)
    let content = b"hello world";
    let signature = vec![0u8; 64]; // Replace with actual signature
    validate(&key_data, &signature, content)?;
    
    Ok(())
}

Configuration

The library supports various configuration options through environment variables:

# Custom PLC directory hostname
export PLC_HOSTNAME=plc.directory

# Custom DNS nameservers (semicolon-separated)
export DNS_NAMESERVERS=8.8.8.8;1.1.1.1

# Custom CA certificate bundles (semicolon-separated paths)
export CERTIFICATE_BUNDLES=/path/to/cert1.pem;/path/to/cert2.pem

# Custom User-Agent string
export USER_AGENT="my-app/1.0"

Command Line Tool

The library includes a command-line tool for testing and resolution:

# Install the binary
cargo install --path .

# Resolve a handle to DID
atproto-identity-resolve ngerakines.me

# Get full DID document
atproto-identity-resolve --did-document ngerakines.me

Architecture

The library is organized into several modules:

  • resolve: Core resolution logic for handles and DIDs
  • plc: PLC directory client for did:plc resolution
  • web: Web DID client for did:web resolution and URL conversion
  • model: Data structures for DID documents and AT Protocol entities
  • validation: Input validation for handles and DIDs
  • config: Configuration management and environment variable handling
  • errors: Structured error types following project conventions
  • key: Cryptographic key operations including signature validation and key identification for P-256 and K-256 curves

Error Handling

All errors follow a structured format:

error-atproto-identity-<domain>-<number> <message>: <details>

Examples:

  • error-atproto-identity-resolve-1 Multiple DIDs resolved for method
  • error-atproto-identity-plc-1 HTTP request failed: https://plc.directory/did:plc:example Not Found
  • error-did-web-1 Invalid DID format: missing 'did:web:' prefix

Contributing

Contributions are welcome! Please ensure that:

  1. All tests pass: cargo test
  2. Code is properly formatted: cargo fmt
  3. No linting issues: cargo clippy
  4. New functionality includes appropriate tests

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgments

This library was extracted from the Smokesignal project, an open-source event and RSVP management and discovery application.