mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-10-17 07:21:32 +02:00
docs: MIT LICENSE (Such Software LLC) + README for v0.3.0
- LICENSE: MIT, © Such Software LLC (published under the company umbrella). - Cargo.toml: license = "MIT". - README: rewritten for the feature-complete release — non-custodial guarantee, chains, public API + operator surface, running it, security posture, testing.
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ edition = "2021"
|
|||||||
authors = ["John Winter Murphy <jw@such.software>"]
|
authors = ["John Winter Murphy <jw@such.software>"]
|
||||||
description = "Open, self-hostable backend for the Smirk non-custodial multi-chain wallet"
|
description = "Open, self-hostable backend for the Smirk non-custodial multi-chain wallet"
|
||||||
repository = "https://github.com/smirk-cash/smirk-backend-core"
|
repository = "https://github.com/smirk-cash/smirk-backend-core"
|
||||||
# license: TBD — deciding MIT vs AGPL-3.0-or-later (see README). Left unset until chosen.
|
license = "MIT"
|
||||||
# Not a library for crates.io; this is a deployable server. Guard against accidental publish.
|
# Not a library for crates.io; this is a deployable server. Guard against accidental publish.
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Such Software LLC
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,51 +1,123 @@
|
|||||||
# smirk-backend-core
|
# smirk-backend-core
|
||||||
|
|
||||||
Open, self-hostable backend for the [Smirk](https://smirk.cash) non-custodial,
|
Open, self-hostable backend for the [Smirk](https://smirk.cash) non-custodial
|
||||||
multi-chain wallet. It provides the chain-access and identity surface a Smirk
|
multi-chain wallet. Rust + Axum + PostgreSQL.
|
||||||
wallet needs — authentication, per-chain wallet access (Bitcoin, Litecoin,
|
|
||||||
Monero, Wownero, Grin), the Grin slatepack relay, and Nostr-based identity —
|
|
||||||
so anyone can run their own backend and a Smirk wallet can connect to it.
|
|
||||||
|
|
||||||
> **Status: early, under active development.** Interfaces and the database
|
It gives a wallet chain access (balances, history, UTXOs, spend inputs, fee
|
||||||
> schema may change before the first tagged release. Not yet recommended for
|
estimation, broadcast), Nostr-native identity, a fiat price feed, and an async
|
||||||
> production self-hosting.
|
Grin slatepack relay — **without ever holding a spend key or seed**. Run your
|
||||||
|
own; the wallet is backend-agnostic.
|
||||||
|
|
||||||
## What it is
|
> **Status:** v0.3.0 — feature-complete and security-reviewed, but young. The
|
||||||
|
> schema/API may still evolve. Run your own chain backends where you can, review
|
||||||
|
> the code, and treat early deployments accordingly.
|
||||||
|
|
||||||
- **Non-custodial.** The server never holds spend keys or seeds. It brokers
|
## Non-custodial by construction
|
||||||
access to blockchain data and relays wallet-to-wallet messages.
|
|
||||||
- **Open core, feature-flagged.** Every feature ships in this codebase and is
|
|
||||||
toggled per deployment; the wallet reads `GET /api/v1/capabilities` and
|
|
||||||
adapts to what a given backend offers.
|
|
||||||
- **Identity via "Sign in with Smirk".** Authentication uses a seed-derived
|
|
||||||
Nostr key (NIP-98); the server stores only public keys.
|
|
||||||
- **Privacy first.** No PII is required to use it; operator and user privacy
|
|
||||||
are explicit design goals.
|
|
||||||
|
|
||||||
## Architecture
|
The server stores **public addresses, public keys, and (for Monero/Wownero)
|
||||||
|
incoming view keys only** — never a spend key, never a seed. View credentials are
|
||||||
|
**forwarded per request** to the chain backends that scan with them and are not
|
||||||
|
persisted here. The wallet signs and broadcasts locally; the backend reads chains
|
||||||
|
and relays bytes.
|
||||||
|
|
||||||
Rust + [Axum](https://github.com/tokio-rs/axum), PostgreSQL via
|
## Chains
|
||||||
[sqlx](https://github.com/launchbadge/sqlx). The public HTTP contract is
|
|
||||||
generated from the handlers with [utoipa](https://github.com/juhaku/utoipa)
|
|
||||||
(OpenAPI), which in turn drives the wallet's generated TypeScript client —
|
|
||||||
one source of truth, checked for drift in CI.
|
|
||||||
|
|
||||||
## Quickstart
|
| Chain | Source | Notes |
|
||||||
|
|-------|--------|-------|
|
||||||
|
| Bitcoin, Litecoin | Electrum / Fulcrum | reads, fee estimation, broadcast |
|
||||||
|
| Monero, Wownero | light-wallet-server (LWS) | stateless view-key forwarding |
|
||||||
|
| Grin | grin-wallet (view-only) + node | `rewind_hash` scan, broadcast, slatepack relay |
|
||||||
|
|
||||||
|
Each chain is independently feature-flagged; a chain whose source isn't configured
|
||||||
|
is reported `enabled: false` by `/capabilities` rather than failing at call time.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
The HTTP contract is generated from the handlers and committed to
|
||||||
|
[`openapi.json`](openapi.json) — the single source of truth for the API and the
|
||||||
|
wallet's generated client. A CI gate fails the build on any drift.
|
||||||
|
|
||||||
|
Public surface (`/api/v1`):
|
||||||
|
|
||||||
|
- **Identity & auth** — NIP-98 (Nostr) sign-in + link, wallet-signature auth,
|
||||||
|
audience-separated JWT sessions, NIP-05 directory (`/.well-known/nostr.json`).
|
||||||
|
- **Chain access** — per-chain balance / history / UTXOs / spend inputs / fee /
|
||||||
|
broadcast.
|
||||||
|
- **Grin relay** — non-custodial store-and-forward mailbox for interactive Grin
|
||||||
|
transfers (feature-flagged).
|
||||||
|
- **Capabilities** (`/capabilities`) — what this instance enables, so the wallet
|
||||||
|
adapts per-instance.
|
||||||
|
- **Prices** (`/prices`) — cached fiat feed, per-feed operator control.
|
||||||
|
- **Self-service erasure** (`/account/erasure`, `/account/export`) — action-bound,
|
||||||
|
two-phase delete-my-data + export.
|
||||||
|
- **Health** (`/health`) and an optional, default-off public landing (`/`).
|
||||||
|
|
||||||
|
## Operator surface
|
||||||
|
|
||||||
|
Operator/admin functions live on a **separate loopback listener** (front it with
|
||||||
|
Tor or an SSH tunnel) — confidentiality by socket, never merged into the public
|
||||||
|
router or OpenAPI.
|
||||||
|
|
||||||
|
- **Sign-in-with-Smirk admin auth** — a NIP-98 *signed action* over a single-use
|
||||||
|
nonce (AUTHN) + a MAC-protected key allowlist (AUTHZ), composed so a route can't
|
||||||
|
run without both.
|
||||||
|
- **First-run bootstrap** — an explicit, MAC-protected latch (no trust-on-first-
|
||||||
|
use); a live deployment adopts as already-bootstrapped; tampering fails closed.
|
||||||
|
- **`smirk-admin` CLI** — break-glass key management, `create-admin-wallet`
|
||||||
|
(zeroized), `doctor`. Talks to Postgres directly, bypassing the network plane.
|
||||||
|
- **Tamper-evident audit** — privileged actions are written to a hash-chained
|
||||||
|
audit trail, fail-closed (the state change rolls back if the audit write fails).
|
||||||
|
|
||||||
|
## Running it
|
||||||
|
|
||||||
|
Requires Rust (stable) and PostgreSQL.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cp .env.example .env # then fill in DATABASE_URL, JWT_SECRET, node URLs
|
cp .env.example .env # then edit: DATABASE_URL + the required secrets
|
||||||
cargo run # starts the API server
|
createdb smirk_backend_core # or point DATABASE_URL at an existing database
|
||||||
|
cargo run --release # migrations run automatically on startup
|
||||||
```
|
```
|
||||||
|
|
||||||
A full self-hosting guide (node requirements, reverse proxy, Tor admin onion,
|
The server **fails closed**: it refuses to start on a missing/weak secret or an
|
||||||
backups) will live in `docs/` as it stabilises.
|
inconsistent feature configuration rather than booting with a control silently
|
||||||
|
defeated. Generate secrets with `openssl rand -hex 32`. See
|
||||||
|
[`.env.example`](.env.example) for the full, documented configuration surface.
|
||||||
|
|
||||||
## Security
|
First admin (headless — the supported bootstrap):
|
||||||
|
|
||||||
Please report vulnerabilities privately — see [SECURITY.md](SECURITY.md).
|
```sh
|
||||||
Do not open public issues for security reports.
|
smirk-admin create-admin-wallet --out admin.secret # generates a key, registers the pubkey
|
||||||
|
# import admin.secret into your NIP-98 signer; it activates on first admin login
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security posture
|
||||||
|
|
||||||
|
- **Fail-closed configuration** — the only place that reads the environment;
|
||||||
|
validates secrets (length + placeholder checks) and feature consistency at boot.
|
||||||
|
- **Identity at rest is peppered** — `pubkey_hash` / `seed_fingerprint` are stored
|
||||||
|
as HMACs, so the database is not a seed-existence oracle or a cross-instance
|
||||||
|
linker.
|
||||||
|
- **Strict JWTs** — HS256 pinned, zero leeway, audience-separated; admin tokens
|
||||||
|
are cryptographically distinct from user tokens.
|
||||||
|
- **Bounded, hardened upstream I/O** — TLS with hostname verification, streaming
|
||||||
|
size caps, and per-request timeouts on every external call.
|
||||||
|
- **Adversarially reviewed** — every security-critical subsystem was built clean
|
||||||
|
(never ported) and put through a multi-agent adversarial review before landing.
|
||||||
|
|
||||||
|
Report vulnerabilities privately — see [SECURITY.md](SECURITY.md). Please do not
|
||||||
|
open public issues for security reports.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo test # unit + doc tests (no database needed)
|
||||||
|
TEST_DATABASE_URL=postgres://… cargo test --tests # + L1 integration against Postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
Integration tests self-skip when `TEST_DATABASE_URL` is unset. They use only
|
||||||
|
deterministic, non-sensitive test secrets and ephemeral identities — never a
|
||||||
|
funded or otherwise sensitive wallet seed.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
To be finalized (MIT vs AGPL-3.0-or-later). Until a `LICENSE` file is added,
|
[MIT](LICENSE) © Such Software LLC — run it, embed it, modify it. Built for interop.
|
||||||
all rights are reserved.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user