Redesign admin peering settings and catalogs

This commit is contained in:
Codex committed 2026-10-11 01:06:03 +02:00
1 parent 492477f86a
commit da40d73f02
16 files changed
+1037 -85

No files matched your search

+49 -30
View File
@@ -11,21 +11,30 @@ received chapters. No database server or second library writer is introduced.
## Roles and direction
The admin UI is **Settings → Peering**, and all users can open the **Peers** catalog
page. Each server may have many peers. For every peer, its admin independently sets:
The interface is administrator-only and split by task: **Settings → Admin → Peering**
manages server identity, peers, grants and transfer limits; **Peer catalogs** manages
per-peer title approvals and remote catalog browsing. Ordinary users cannot see either
page or call their APIs. Each server may have many peers.
- **Serve approved manga**: expose only individually checked library titles to that
peer. Off is the default and invalidates the current serving grant.
- **Allow downloads**: queue and pull chapters from that peer. Off is the default;
a verified pairing and imported grant still allow browsing its approved catalog.
- **Let readers queue**: ordinary readers may request transfers; otherwise only an
admin may queue. Browsing a permitted catalog does not disclose the local user to
the remote server.
- Upload streams, bytes/s and bytes/day, and receiving pages in flight and bytes/s.
Defaults are two in-flight pages and 2 MiB/s in each direction per peer. The
publisher's caps remain authoritative. A gateway-wide four-stream ceiling applies.
- **Grant scopes**: Catalog permits catalog, covers and metadata. Download includes
Catalog and permits chapter transfers. Each direction has its own grant.
- **Serving state**: Active or Paused. Pausing preserves the grant/token; explicit
Revoke invalidates it. Scope changes take effect without exchanging a new token.
- **Approved titles**: the publisher chooses titles on Peer catalogs, not in the
connection settings. Pairing or a grant alone does not share a title.
- **Local receiving** is a separate switch. Browsing works with Catalog permission
even when local receiving is off; downloads require an active Download grant and
local receiving enabled.
- Transfer limits cover upload streams, bytes/s and bytes/day, plus receiving pages
in flight and bytes/s. Defaults are two in-flight pages and 2 MiB/s each direction
per peer. Publisher caps remain authoritative; a gateway-wide four-stream ceiling
applies.
Serving and receiving are separate directions. Pairing by itself exposes no title.
The required local server display name is 1–25 ASCII letters/digits. It is a friendly
label, not the cryptographic identity; changing it does not rotate the certificate.
An invitation expires after 48 hours, the certificate currently lasts one year, and
a grant lasts up to 90 days bounded by certificate validity. The UI labels these as
separate lifetimes.
## Deployment
@@ -38,8 +47,9 @@ scraper queue, Docker socket, or writable library mount. It must never be scaled
past one instance for the same usage-counter directory.
1. Build the image and start the normal stack as documented in
[`compose-deployment.md`](compose-deployment.md). Generate the local certificate
in **Settings → Peering**. Keep `/data/peering/identity.key` private and backed up.
[`compose-deployment.md`](compose-deployment.md). Set the local server name and
generate its certificate in **Settings → Admin → Peering**. Keep
`/data/peering/identity.key` private and backed up.
2. Start the optional service with `docker compose --profile peering up -d
peer-gateway`. Verify `docker compose --profile peering ps` shows healthy and
`https://127.0.0.1:8093/health` responds. `/health` is deliberately unauthenticated
@@ -65,12 +75,12 @@ require administrator-supervised re-pairing; there is no automatic key rotation
2. Both admins import the other's invitation and press **Test & verify pairing**.
The HTTPS handshake presents client and server certificates, checks their exact
pins and dates, and consumes the one-use invitation code. Both sides must probe.
3. A publisher checks specific titles under that peer, enables **Serve**, issues a
90-day random grant, and sends the token privately to the receiving admin. The
receiving admin imports the grant and enables **Allow downloads**. Reverse
direction needs its own share selection and grant. The server stores only a hash
of a grant it issued; the receiver stores its imported token server-side.
4. A local user browses the catalog, selects missing/newest/last-five or an exact
3. A publisher approves titles for that peer on **Peer catalogs**, chooses Catalog
or Download grant scopes, and sends the one-time token privately. The receiving
admin imports it and independently enables local receiving for downloads. Reverse
direction needs its own approvals and grant. The server stores only a hash of a
grant it issued; the receiver stores its imported token server-side.
4. An admin browses the permitted catalog, selects missing/newest/last-five or an exact
chapter, and queues it through the normal scraper. The peer adapter downloads up
to the configured pages in flight, validates size and SHA-256, resumes a partial
page with HTTP Range, checkpoints between batches, and atomically publishes each
@@ -82,15 +92,19 @@ the human reader. It can still observe requested titles, times and byte counts.
## Peer v1 HTTP interface
All content endpoints require TLS 1.3 client certificate pinning, a paired/serving
peer, and a currently valid certificate-bound bearer grant. There is no insecure
HTTP fallback and no path-based file browsing.
Catalog, cover, manifest and blob endpoints require TLS 1.3 client certificate
pinning, paired identity, an active grant with the matching scope, and no serving
pause. There is no insecure HTTP fallback or path-based file browsing. `/access`
requires the pinned client certificate and reports status without a bearer grant so
an admin can distinguish pairing from permission.
| Request | Response |
| --- | --- |
| `GET /peer/v1/hello` with one-use invitation headers | Protocol version and server identity fingerprint; no catalog |
| `GET /peer/v1/catalog?cursor=N` | Up to 50 approved opaque title IDs, title/year/status, next cursor |
| `GET /peer/v1/manga/{id}?cursor=N` | Up to 100 complete chapter IDs and light metadata |
| `GET /peer/v1/access` | Pairing state, certificate expiry and current grant status/scopes; no catalog |
| `GET /peer/v1/catalog?cursor=N` | Up to 50 approved opaque title IDs, safe metadata and cover availability |
| `GET /peer/v1/covers/{mangaId}` | Approved cover image only; bounded to 5 MiB and charged to peer byte quota |
| `GET /peer/v1/manga/{id}?cursor=N` | Up to 100 complete chapter IDs and public metadata |
| `GET /peer/v1/manga/{id}/chapters/{id}` | Ordered page IDs, MIME, byte size, SHA-256 and ETag |
| `GET /peer/v1/blobs/{id}` | One image, optional `Range: bytes=N-` and `If-Match`; 206 on resume |
@@ -111,8 +125,13 @@ parallelism, not unbounded connections.
`npm run test:peer` creates disposable A/B identities, gateways and libraries and
tests mTLS pairing, no-cert/bad-grant rejection, private catalog, per-title sharing,
manifest hashes, a resumed range response, scraper publication, duplicate skip and
revocation. `npm test` includes it. An isolated Compose acceptance is:
catalog-only cover access, manifest hashes, a resumed range response, scraper
publication, duplicate skip, pause and revocation. `npm run test:peer-ab` additionally
builds two independent Compose projects from synthetic fixtures, exercises real
two-way pairing, browsing, cover retrieval, permission updates and sequential queueing,
checks the queue remains paused, and tears both stacks down. The UI suite checks the
guided setup, approvals, and non-admin boundary. An isolated single-stack Compose
acceptance is:
```powershell
$env:APP_IMAGE = 'mangacircus:local' # replace with the image just built
@@ -133,6 +152,6 @@ without affecting reading or existing local downloads. Do not delete the identit
to recover from a network error; that would break every peer pin.
Current limits: no automatic certificate renewal, invitation cancellation UI,
peer cover-image endpoint, multi-peer performance pilot, VM deployment, or public
internet exposure review. The gateway has no automated hoster-interaction logic;
multi-peer performance pilot, VM deployment, or public internet exposure review.
The gateway has no automated hoster-interaction logic;
source scraping remains subject to the existing source-safety policy.