updates
This commit is contained in:
+17
-2
@@ -63,9 +63,24 @@ conversations → sessions → user) inside a transaction.
|
||||
**returned once** at creation/regeneration. Regeneration also wipes the
|
||||
account's sessions.
|
||||
|
||||
## Drivers
|
||||
## Local file CDN
|
||||
|
||||
`src/drivers/`: `LLMDriver` interface (`listModels`, `chat`, `chatStream`),
|
||||
`src/cdn.ts` + routes in `index.ts`. Generic namespaced layout
|
||||
(`PUT /cdn/<ns>/<key>` authed, `GET /cdn/<ns>/<key>.<ext>` public) so future
|
||||
file kinds plug into `CDN_NAMESPACES` without new routes. Today only `avatar`
|
||||
exists: key = account id (`/cdn/avatar/<id>.png`), ownership enforced.
|
||||
|
||||
- Type safety by **magic bytes** (JPEG `FF D8 FF`, PNG signature, `RIFF…WEBP`);
|
||||
only `jpg`/`png`/`webp` are representable, the stored extension is always
|
||||
detected, everything else is `415`. Route regex charsets make traversal
|
||||
unmatchable (attempts fall through to the SPA fallback).
|
||||
- Per-namespace limits: `avatar` = 5 MB max (`413`), 5 uploads / 2 h /
|
||||
account (`429` + `Retry-After`), counted on success. Re-upload replaces all
|
||||
stored variants for the key.
|
||||
- Served with detected `Content-Type`, `X-Content-Type-Options: nosniff`,
|
||||
`Cache-Control: public, max-age=3600`.
|
||||
|
||||
## Drivers`src/drivers/`: `LLMDriver` interface (`listModels`, `chat`, `chatStream`),
|
||||
`DriverRegistry` with global priority
|
||||
`ollama → mistral → puppeteer-openai (stub) → deepseek → anthropic → openai`.
|
||||
Models are addressed as `"driver:model"` (split on the first `:`).
|
||||
|
||||
+11
-1
@@ -39,7 +39,8 @@ read-only `SharePage` (no auth), everything else renders the authenticated app.
|
||||
share button), message list (`Markdown` for assistant, emerald bubble for
|
||||
user), rounded composer (Enter to send, Shift+Enter for newline).
|
||||
- `dialogs.tsx` — `ConvEditDialog` (title + topic), `ShareModal` (public link,
|
||||
copy, unshare), `SettingsModal` (display name, avatar URL, theme).
|
||||
copy, unshare), `SettingsModal` (display name, avatar upload box with
|
||||
drag & drop, avatar URL, theme).
|
||||
- `AdminPanel.tsx` — No-KYC account management: create (key shown once),
|
||||
regenerate (revokes sessions), edit, delete with confirm.
|
||||
- `SharePage.tsx` — public read-only view, fetches `/api/share/:id` unauthenticated.
|
||||
@@ -52,3 +53,12 @@ Tailwind `darkMode: "class"`. `applyTheme()` in `App.tsx` toggles the `dark`
|
||||
class from the account theme (`auto` follows `prefers-color-scheme` with a
|
||||
live media-query listener). Accent: emerald; shapes: `rounded-2xl/3xl`
|
||||
everywhere; every surface needs a `dark:` variant. UI text is English only.
|
||||
|
||||
## Mobile
|
||||
|
||||
Below the `md` breakpoint the sidebar becomes a slide-in drawer (backdrop tap
|
||||
or swipe-left closes it, hamburger in the chat header opens it). Modals render
|
||||
as bottom sheets with a drag handle — pull down past the threshold to dismiss
|
||||
(tap backdrop or Escape works too). Composer respects
|
||||
`env(safe-area-inset-bottom)`. No separate mobile codebase: same components,
|
||||
responsive Tailwind classes + minimal touch handlers.
|
||||
|
||||
+17
-2
@@ -10,6 +10,7 @@ Copy `.env.example` to `.env`. Full list:
|
||||
| `APP_PASSWORD` | *(required)* | **admin** access key — generate with `openssl rand -base64 24` |
|
||||
| `SESSION_TTL_HOURS` | `720` | Bearer session lifetime (30 days) |
|
||||
| `DATA_DIR` | `./data` | holds `kisassistant.db` (SQLite) |
|
||||
| `CDN_DIR` | `./cdn` | local file CDN storage (avatars; NixOS: under state dir) |
|
||||
| `WIKI_URL` | `https://git.kisakay.com/k/chat/wiki` | remote docs wiki — `GET /wiki` redirects (302) there |
|
||||
| `RATE_LIMIT_MAX` / `RATE_LIMIT_WINDOW_MIN` | `5` / `10` | login rate limit per IP |
|
||||
| `OLLAMA_HOST` / `OLLAMA_ENABLED` | `http://10.66.66.4:11434` / `true` | local-model driver |
|
||||
@@ -35,11 +36,25 @@ unshare. See `AGENTS.md`.
|
||||
1. Log in as `admin` with the `APP_PASSWORD` key.
|
||||
2. Open **Accounts** → *New account* → username (+ display name).
|
||||
3. Copy the one-time `ka_…` key and hand it to the owner (chat, QR code, …).
|
||||
4. Users set their display name, avatar URL (upload e.g. to `catbox.moe`, paste
|
||||
the direct link) and theme in the profile settings.
|
||||
4. Users set their display name, avatar (upload box in profile settings, or a
|
||||
remote URL e.g. from `catbox.moe`) and theme in the profile settings.
|
||||
5. Rotate a compromised key with the regenerate button (old sessions die);
|
||||
delete removes the account with all its chats and shares.
|
||||
|
||||
## Local file CDN (avatars)
|
||||
|
||||
`PUT /cdn/<ns>/<key>` (Bearer) / `GET /cdn/<ns>/<key>.<ext>` (public), e.g.
|
||||
`/cdn/avatar/<account-id>.png`. Namespaces live in `CDN_NAMESPACES`
|
||||
(`src/cdn.ts`) — add one to extend (future usage).
|
||||
|
||||
- Allowed types **only** `jpg`/`png`/`webp`, verified by **magic bytes**, never
|
||||
by extension (client filename is ignored; the stored extension comes from
|
||||
detection). Everything else → `415`, unknown namespace/ext → `404`.
|
||||
- `avatar` rules: 5 MB max (`413` above), **5 uploads max per 2 h per account**
|
||||
(`429` + `Retry-After`), ownership enforced (own id, or admin).
|
||||
- Served with fixed `Content-Type`, `nosniff`, `Cache-Control: public,
|
||||
max-age=3600`. No listing, no traversal (strict charsets + SPA fallback).
|
||||
|
||||
## NixOS deployment (`chat.kisakay.com`)
|
||||
|
||||
`flake.nix` exposes `packages.<system>.default` (backend + prebuilt frontend)
|
||||
|
||||
Reference in New Issue
Block a user