multi-tenant relay und card-push to user

This commit is contained in:
th committed 2026-04-10 18:23:07 +02:00
1 parent 7219bae655
commit 5b18c46ac2
22 files changed
+7453 -519

No files matched your search

+74 -33
View File
@@ -342,30 +342,37 @@ When running multiple hyprcrd instances that share CalDAV credentials, you need
## Relay
A minimal web service for mobile note capture and card sharing between hyprcrd instances.
A self-hosted **multi-tenant** message relay for hyprcrd. Multiple users
share one relay instance — each one has their own login, their own
client encryption secret, and their own inbox. Cards (and in the future:
encrypted chat messages) can be sent **between tenants** on the same
relay.
**Full documentation:** [`relay/README.md`](relay/README.md)
### Architecture
```
[Phone/Browser] → https://relay.example.com → [Relay Service]
↓ poll
[hyprcrd (local)]
[hyprcrd alice] ──push──┐ ┌──poll── [hyprcrd alice]
├──► [Relay] ◄────────────┤
[hyprcrd bob] ──push──┘ tenants: alice, bob └──poll── [hyprcrd bob]
[hyprcrd A] → push card → [Relay] ← poll ← [hyprcrd B]
sender encrypts → relay decrypts with sender's secret →
re-encrypts with shared inter-tenant key → stores →
on recipient poll: decrypts → re-encrypts with recipient's secret
```
### Deploy to Webspace
### Deploy
**Webspace** (any PHP host with `mod_rewrite` and `pdo_sqlite`):
```bash
cd relay
./dist.sh
# upload hyprcrd-relay.zip and extract into your webspace
```
Upload the resulting `hyprcrd-relay.zip` to your webspace and extract it. The SQLite database is created automatically on first request. Open the URL and set a password + shared secret.
Requirements: PHP 8.3+ with `pdo_sqlite`, Apache with `mod_rewrite`.
### Deploy with Docker
**Docker**:
```bash
cd relay
@@ -373,42 +380,76 @@ docker build -t hyprcrd-relay .
docker run -d -p 8081:80 -v relay-data:/var/www/html/data hyprcrd-relay
```
The `data/` directory is created on first request and contains the
SQLite DB plus the master encryption key (chmod 600, blocked from web
access via `.htaccess`).
### Development (both together)
```bash
./dev.sh
```
Starts hyprcrd on `http://localhost:8088` and the relay on `http://localhost:8081` in the same Docker network. Source files are bind-mounted — changes are live without rebuilding.
Starts hyprcrd on `http://localhost:8088` and the relay on `http://localhost:8081` in the same Docker network. Source files are bind-mounted — changes are live without rebuilding. From inside the hyprcrd container, the relay is reachable at `http://relay:80`.
From inside the hyprcrd container, the relay is reachable at `http://relay:80`.
### Setup workflow
### Setup
1. Open the relay URL **from a desktop browser** — the setup wizard
is desktop-friendly
2. Create the first **admin** account: username + password (UI login)
+ shared secret (client encryption)
3. As admin, click the **users** tab and create accounts for any
additional users you want to give relay access to
4. Each user enters their credentials in their own hyprcrd:
**Settings → Relay** → relay URL + username + shared secret
5. To send a card from one tenant to another, use the relay UI's
compose form (recipient picker) — or push cards from hyprcrd
1. Open the relay URL, set a **password** (for UI login) and a **shared secret** (for encryption)
2. In hyprcrd: **Settings > Relay** — enter the relay URL and the same shared secret
3. Click **save**
### How it works (high level)
### How it works
- **Mobile inbox**: type a note on the relay UI, it arrives as a card with `#inbox` tag
- **Push to relay**: right-click any card → "push to relay" — other instances pick it up on next poll
- Messages are encrypted client-side (AES-256-CBC) before sending to the relay
- The relay only stores ciphertext — it cannot read your messages
- hyprcrd polls the relay every 45 seconds in the background
- Messages are kept on the relay for 24 hours, then auto-deleted
- Cards pushed from the same instance are not re-imported
- Enter to send, Shift+Enter for newline
- **Per-tenant inboxes**: each user only sees their own messages
- **Cross-tenant routing**: send a card to another tenant on the same
relay; the relay decrypts with the sender's secret, re-encrypts with
a shared inter-tenant key for storage, then re-encrypts with the
recipient's secret on delivery
- **At-rest encryption**: every sensitive value in the DB (tenant
secrets, the inter-tenant key, message bodies) is encrypted. The
master key lives outside the DB in a chmod-600 file
- **24-hour ephemeral**: messages and attachments auto-delete after a
day. Cards extracted in hyprcrd are the long-term store
- **Future: end-to-end encrypted chat** between tenants is planned and
will require per-pair key exchange — see `relay/README.md` for the
roadmap
### Relay Security
- Separate password (UI login) and shared secret (API + encryption)
- Bcrypt hashing for both credentials
- Rate-limited login (5 attempts/minute)
- AES-256-CBC client-side encryption — relay never sees plaintext
- Per-tenant bcrypt-hashed passwords + secrets
- Master key encryption for tenant secrets and the inter-tenant key
at rest
- HttpOnly + SameSite=Strict session cookies
- Rate-limited login (5 attempts/minute per IP)
- AES-256-CBC for all message encryption
- Security headers (X-Frame-Options, HSTS, X-Content-Type-Options)
- SQLite database blocked from direct download via `.htaccess`
- Request size limited to 256KB
- `data/` directory blocked from direct download via `.htaccess`
- Request size limited to 256KB (15MB for attachments)
- Last-admin protection prevents accidental lockout
For the full security model (including what's NOT protected and the
roadmap to strict E2E for chat), see [`relay/README.md`](relay/README.md).
### Migrating from the old single-tenant relay
When you upgrade an existing relay installation, the new code automatically
detects the legacy schema and drops the old `messages` and `attachments`
tables (the data is 24h-ephemeral anyway). The setup wizard appears on
your next visit. You'll need to:
1. Run through the desktop setup wizard to create the first admin
2. Recreate any other tenant accounts that need access
3. On every connected hyprcrd, update **Settings → Relay** to add the
new **username** field and the new shared secret
The old `relay_key` was bcrypt-hashed and cannot be recovered, so all
client secrets need to be reissued.
## Rebuilding Tailwind CSS