This commit is contained in:
timka123 committed 2026-10-19 09:41:32 +03:00
1 parent 4bdbc8bfa8
commit 2be074f191
22 files changed
+1034 -25

No files matched your search

+50 -8
View File
@@ -179,6 +179,8 @@ and you can fill everything in from **Settings**.
| `JIRA_*`, `TODOIST_*`, `GOOGLE_*`, `LAUNDRY_*` | seeds for the sources |
| `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID` | the bot |
| `SCHEDULER_ENABLED`, `TELEGRAM_BOT_ENABLED` | switch the background jobs / bot off |
| `AUTH_USERNAME`, `AUTH_PASSWORD` | closes the **browser UI** behind a login; see [Going public](#going-public) |
| `TELEGRAM_OWNER_ID`, `TELEGRAM_BOT_USERNAME` | lets that same browser login happen via the Telegram Login Widget |
---
@@ -200,7 +202,7 @@ and you can fill everything in from **Settings**.
* `backend/` — FastAPI app. `app/services/` holds the thinking (timer, tasks,
stats, report, blocker policy, scheduler, bot); `app/sources/` holds one module
per integration; `app/api/` is a thin HTTP layer. 44 tests under `backend/tests`.
per integration; `app/api/` is a thin HTTP layer. 63 tests under `backend/tests`.
* `frontend/` — React + TypeScript + MUI, built by Vite into the backend image and
served from the same origin (so there is no CORS to configure).
* **The look** — warm paper, ink type, hairline rules instead of boxes and
@@ -228,14 +230,46 @@ make report # build and send today's report right now
The backend also has a CLI, handy from cron or a systemd timer:
```bash
python -m app.cli refresh # pull every source once
python -m app.cli briefing # send the morning briefing
python -m app.cli report # build and send today's report
python -m app.cli stats # print the numbers as JSON
python -m app.cli refresh # pull every source once
python -m app.cli briefing # send the morning briefing
python -m app.cli report # build and send today's report
python -m app.cli stats # print the numbers as JSON
python -m app.cli set-password # set/rotate the web login password (prompts, never argv)
```
---
## Going public
Kadence is still single-user: `AUTH_USERNAME`/`AUTH_PASSWORD` and
`TELEGRAM_OWNER_ID` all name *you*, not a user table. What they do is close the
**browser UI** to everyone else once the backend is reachable beyond your own
machine — `API_TOKEN` already protected the raw API; this is the same idea with
a login screen instead of a header the desktop app fills in for you.
1. **Password.** Set `AUTH_PASSWORD` (and optionally `AUTH_USERNAME`, default
`timka`) in `.env` and restart — the hash is seeded into the database on
first boot, the plaintext is never stored. A browser now has to sign in at
`/`; the desktop app is unaffected, it keeps sending `X-API-Token`. Rotate
the password later from **Settings → Access** (while signed in) or by
running `make set-password` on the server — the UI never accepts a new
password over an unauthenticated connection.
2. **Telegram login, in addition** (optional). You already have the bot token
(`TELEGRAM_BOT_TOKEN`) for notifications; login reuses it:
* DM [@userinfobot](https://t.me/userinfobot) for your numeric Telegram id
→ `TELEGRAM_OWNER_ID`.
* Tell [@BotFather](https://t.me/BotFather) `/setdomain` and give it this
site's **HTTPS** domain — the Login Widget refuses to render anywhere else.
* Set `TELEGRAM_BOT_USERNAME` (no `@`) in `.env`, or fill it in under
**Settings → Access** once the UI is reachable.
* Restart. The login screen grows a "Log in with Telegram" button under the
password form.
3. Either credential alone is enough to close the UI; set both and either one
signs you in. With neither set, the browser stays as open as the bare API
always was — nothing changes until you opt in.
---
## Security notes
* The desktop app never runs as root. The only privileged code is
@@ -245,6 +279,14 @@ python -m app.cli stats # print the numbers as JSON
hostname. It is authorised by polkit (`auth_admin_keep` by default — one prompt
per session; `install.sh --passwordless` drops that for one user).
* Tokens live in the database and in `.env`, are masked in every API response,
and are never sent to the browser in full.
* Set `API_TOKEN` before exposing the backend beyond localhost; put it behind TLS
if it leaves your network.
and are never sent to the browser in full. The password is never stored at
all — only a salted PBKDF2 hash.
* Set `API_TOKEN` before exposing the backend beyond localhost (protects the
raw API — desktop app, scripts, cron); see [Going public](#going-public) to
close the **browser UI** the same way, with a login instead of a header.
* The login cookie is `HttpOnly`, `SameSite=Lax`, and `Secure` whenever the
request arrives as HTTPS (directly or via `X-Forwarded-Proto` from a reverse
proxy) — put the backend behind TLS before relying on it over the open
internet, same as `API_TOKEN` always needed.
* Login attempts are rate-limited per source IP (in-process; fine for one
instance, one user).