Add LICENSE, THIRD_PARTY_NOTICES.md, AI-DECLARATION.md, and license badge/section in README, matching the reference Smol Mail implementation's license. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
88 lines
5.3 KiB
Markdown
88 lines
5.3 KiB
Markdown
# 分身 bunshin
|
|
|
|
[](LICENSE) [](https://ai-declaration.md)
|
|
|
|
A Rust implementation of the [Smol Mail](https://code.randogoth.com/randogoth/smolmail) server: a minimalist, end-to-end encrypted mail protocol over a Noise-secured TCP connection, with an optional Reticulum (RNS) mesh carrier behind the `rns` build feature. `bunshin` implements the server side only — receiving, storing and serving sealed mail — not the client.
|
|
|
|
The server never sees plaintext, sender identities or any private key. It learns only which mailbox an envelope is for, its size, and when it arrived.
|
|
|
|
The flake's main purpose is turnkey deployment on a NixOS host: import `nixosModules.default`, point it at a key, and `nixos-rebuild switch`.
|
|
|
|
## Deploying on NixOS
|
|
|
|
Add bunshin as a flake input and import the module:
|
|
|
|
```nix
|
|
{
|
|
inputs.bunshin.url = "https://code.randogoth.com/randogoth/bunshin";
|
|
|
|
outputs = { self, nixpkgs, bunshin, ... }: {
|
|
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
|
|
modules = [
|
|
bunshin.nixosModules.default
|
|
{
|
|
services.bunshin = {
|
|
enable = true;
|
|
keyFile = "/var/lib/bunshin/server.key"; # provisioned out of band, see below
|
|
openFirewall = true;
|
|
inviteTokenFile = "/run/secrets/bunshin-invite"; # or inviteToken directly
|
|
};
|
|
}
|
|
];
|
|
};
|
|
};
|
|
}
|
|
```
|
|
|
|
`services.bunshin` also takes `host`, `port`, `dataDir`, `maxEnvelope`, `quota`, `requestsQuota`, `retentionDays`, `requestsRetentionDays`, `maxTokens`, `rateConnections`, `rateSends` and `rateTokens`; see `flake.nix` for defaults. The module renders a `systemd` unit that runs `bunshin serve` under `DynamicUser`; it does not generate a key.
|
|
|
|
For the RNS carrier, build `packages.rns`, set `services.bunshin.package` to it, and enable `services.bunshin.rns` with its `keyFile`; see [RNS.md](RNS.md) for the protocol and the remaining options.
|
|
|
|
Before the first deploy, generate the server's static key once (from a dev shell or `nix run`) and place it at the configured `keyFile`:
|
|
|
|
```
|
|
nix run "https://code.randogoth.com/randogoth/bunshin" -- keygen --key server.key
|
|
```
|
|
|
|
`keygen` writes the server's static X25519 key (used for the Noise handshake, distinct from any user's Ed25519 identity) and prints its public key in base32. Publish that public key through a trusted channel — clients pin it, and a mismatch aborts the handshake.
|
|
|
|
## RNS carrier
|
|
|
|
The `rns` feature (built by `packages.rns`, wired to the module through `services.bunshin.rns`) serves the same mailbox over the Reticulum Network Stack alongside TCP: `bunshin serve --rns` runs both carriers in one process against one database. The mesh address is the `smolmail.server` destination hash — there is no key to pin, the address is the pin.
|
|
|
|
```
|
|
bunshin rns-keygen --key server.rns.key
|
|
bunshin serve --rns --key server.key --rns-key server.rns.key --db mail.db --rns-udp 0.0.0.0:4242
|
|
```
|
|
|
|
`rns-keygen` writes the 64-byte Reticulum identity and prints the destination hash; publish `smol+rns://<user>@<hash>` as the server's address. RNS-specific limits (`--rns-max-envelope`, `--rns-fetch-budget`, `--rns-max-links`, `--rns-rate-link-requests`, `--rns-rate-link-bytes`) default to mesh-friendly 32 KiB caps; the UDP interface is the one supported transport interface so far. See [RNS.md](RNS.md).
|
|
|
|
## Building
|
|
|
|
Requires a Rust toolchain (stable, edition 2021) and a C compiler — `rusqlite`'s `bundled` feature compiles SQLite from source rather than linking a system copy, so no separate SQLite install is needed. The `rns` feature additionally needs cmake, ninja and a microReticulum checkout pointed at by `MICRORETICULUM_SOURCE_DIR` — the flake's dev shell provides all of it.
|
|
|
|
```
|
|
cargo build --release
|
|
cargo test
|
|
```
|
|
|
|
The binary lands at `target/release/bunshin`. With Nix, skip the toolchain setup entirely: `nix build` produces the same binary at `./result/bin/bunshin`.
|
|
|
|
Running directly, outside the NixOS module:
|
|
|
|
```
|
|
bunshin keygen --key server.key
|
|
bunshin serve --key server.key --db mail.db --host 0.0.0.0 --port 1961
|
|
```
|
|
|
|
`serve` accepts `--max-envelope`, `--quota`, `--requests-quota`, `--retention-days`, `--requests-retention-days`, `--max-tokens`, `--invite-token`, `--rate-connections`, `--rate-sends` and `--rate-tokens` to control size limits, the mailbox's two quota tiers, their retention, the accept-token cap, registration gating and abuse control. Run `bunshin serve --help` for defaults.
|
|
|
|
## Status
|
|
|
|
Implements SPEC.md version 1.1 in full: `AUTH`, `RESOLVE`, `SEND`, `FETCH`, `DELETE` and `REGISTER`, including accept tokens and the main/requests tier split, fetch cursors, 32-byte message ids, `REGISTER` proof of possession, and dual-signed key rotation chains.
|
|
|
|
With the `rns` feature, implements the version 1.2 RNS transport: the same six operations over Reticulum Links to an announced `smolmail.server` destination, with link-bound AUTH/REGISTER signatures, per-link request and byte limits, and a concurrent-link cap. One server process can serve both carriers over one store.
|
|
|
|
## License
|
|
|
|
Licensed under the Apache License, Version 2.0 ([LICENSE](LICENSE)). Third-party dependency licenses are listed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|