A library for ATProtocol identities.
Rust 100.0%
4 1 26

Clone this repository

https://tangled.org/smokesignal.events/atproto-identity-rs
git@tangled.org:smokesignal.events/atproto-identity-rs

For self-hosted knots, clone URLs may differ based on your setup.

README.md

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.