# cedros-sunscreen

> **This crate is in active development and is NOT ready for production use.**
> APIs may change without notice. Not yet audited for production deployment.

Sanctions screening API for blockchain addresses. Ingests data from official sources (OFAC SDN, ransomware trackers) and serves it via a simple HTTP API.

## Features

- **OFAC SDN ingestion** — parses the official U.S. Treasury SDN Advanced XML (~772 sanctioned crypto addresses across 18 currency types)
- **Ransomware tracker** — supplements with known ransomware payment addresses from ransomwhe.re
- **Sanctioned country codes** — extracts ISO 3166-1 alpha-2 codes from OFAC sanctions programs
- **Public list endpoint** — `GET /v1/lists` returns all sanctioned addresses and country codes
- **Single-address check** — `GET /v1/check/{currency}?address=X` with API key authentication
- **Background workers** — hourly data refresh from sources, minute-level API key cache refresh
- **Composable router** — embed into any axum application via `cedros_sunscreen::router()`
- **Auto-migrations** — database schema applied on startup

## Quick start

### Prerequisites

- Rust 1.80+
- PostgreSQL 14+

### Installation

```toml
[dependencies]
cedros-sunscreen = "0.1"
```

Or install the server binary:

```bash
cargo install cedros-sunscreen
```

### Configuration

```bash
# Required
DATABASE_URL=postgresql://user:password@localhost/cedros_sunscreen

# Optional (defaults shown)
OFAC_XML_URL=https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN_ADVANCED.XML
RANSOMWARE_EXPORT_URL=https://api.ransomwhe.re/export
DATA_REFRESH_INTERVAL_SECS=3600
API_KEY_REFRESH_INTERVAL_SECS=60
```

### Running the server

```bash
# Start the HTTP server (runs migrations, starts background workers)
cargo run -- serve --bind-addr 127.0.0.1:8080

# Run a single ingestion cycle and exit
cargo run -- ingest
```

## API

### Public endpoints

#### `GET /v1/lists`

Returns all sanctioned addresses and country codes. No authentication required.

```json
{
  "addresses": [
    "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    "0x098B716B8Aaf21512996dC57EB0615e2383E2f96"
  ],
  "countries": [
    "BY",
    "CU",
    "IR",
    "KP",
    "RU",
    "SY"
  ]
}
```

### Authenticated endpoints

#### `GET /v1/check/{currency}?address={address}`

Check a single address. Requires `X-API-Key` header.

```json
{
  "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "onList": true,
  "listName": "OFAC",
  "confidence": 100
}
```

## Embedding

Use as a library to embed the sanctions screening router into a larger application:

```rust
use cedros_sunscreen::{Config, Storage, ApiKeyCache};

let config = Config::from_env()?;
let storage = Storage::from_database_url(&config.database_url).await?;
storage.migrate().await?;

let api_key_cache = ApiKeyCache::new();
api_key_cache.refresh(&storage.api_key_repo).await;

// Nest into your existing axum app
let sunscreen_router = cedros_sunscreen::router(storage, api_key_cache);
let app = axum::Router::new()
    .nest("/sunscreen", sunscreen_router);
```

## Data sources

| Source | Type | Update frequency | Coverage |
|--------|------|-----------------|----------|
| [OFAC SDN Advanced XML](https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN_ADVANCED.XML) | Official (U.S. Treasury) | Hourly refresh | ~772 crypto addresses, 18 currency types, sanctions programs |
| [ransomwhe.re](https://api.ransomwhe.re/export) | Community research | Hourly refresh | Known ransomware payment addresses |

## Database

PostgreSQL with three tables (auto-migrated on startup):

- `sanctioned_addresses` — `(currency, address)` primary key, `source_type`, timestamps
- `sanctioned_countries` — `(code, program)` primary key, `name`, timestamps
- `api_keys` — API key authentication
- `user_logs` — request audit trail

## License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.
