T27: FIT Wiki connection (session cookie or one-time login) #27

Open
dzenda wants to merge 3 commits from t27-fitwiki-connection into main
Owner

T27: FIT Wiki connection

FIT Wiki (fit-wiki.cz, DokuWiki) is readable only by registered FIT students, with no API or SSO. FIT-OS therefore acts with the user's own DokuWiki session:

  • Paste session cookie: only the DokuWiki and DW<hash> cookies are kept (parseWikiCookies), and the session is verified by loading a page as the user.
  • Log in once: username and password are sent once to fit-wiki.cz with "remember me" set (wikiLogin: login form → sectok → POST → session check). The password is never stored. Only the resulting DokuWiki cookies are saved.
  • Cookies are stored AES-GCM encrypted in connections (provider fitwiki, kind cookie) and are never returned. Disconnect deletes them.
  • POST /api/connections/fitwiki requires a session and passes isSameOriginRequest. Password logins are limited per user by FITWIKI_LOGIN_LIMIT (5/min, a config-only rate-limit binding), so FIT-OS can't be used to guess wiki passwords. Requests go only to fit-wiki.cz, use manual redirects and a 15 s timeout, read at most 1 MB, and send an identified user agent.
  • New MCP service switch "FIT Wiki"; the provider functions come in T28.
  • Connections UI: a FIT Wiki card with both modes, help text and a registration link (en/cs).
  • PLAN.md: the part 2 plan (FIT Wiki, Bílá kniha, Courses API with cvut:cpages:common:read, GitLab as fallback).

Note for the next production deploy: add FITWIKI_LOGIN_LIMIT to env.production (PR #26).

Review (Astra)

  • Fixed [P2]: switching from "paste cookie" to "log in" reused the input element, so a pasted cookie could show up as text in the username field. The form now remounts per mode (verified in a browser).

Checks

lint, typecheck and test: 318 passing. Dev smoke test: the card renders in both modes, and a fake cookie is checked against fit-wiki.cz, rejected with the friendly error and not stored.

🤖 Generated with Claude Code

## T27: FIT Wiki connection FIT Wiki (fit-wiki.cz, DokuWiki) is readable only by registered FIT students, with no API or SSO. FIT-OS therefore acts with the user's own DokuWiki session: - **Paste session cookie:** only the `DokuWiki` and `DW<hash>` cookies are kept (`parseWikiCookies`), and the session is verified by loading a page as the user. - **Log in once:** username and password are sent once to fit-wiki.cz with "remember me" set (`wikiLogin`: login form → `sectok` → POST → session check). **The password is never stored.** Only the resulting DokuWiki cookies are saved. - Cookies are stored AES-GCM encrypted in `connections` (provider `fitwiki`, kind `cookie`) and are never returned. Disconnect deletes them. - `POST /api/connections/fitwiki` requires a session and passes `isSameOriginRequest`. Password logins are limited per user by `FITWIKI_LOGIN_LIMIT` (5/min, a config-only rate-limit binding), so FIT-OS can't be used to guess wiki passwords. Requests go only to fit-wiki.cz, use manual redirects and a 15 s timeout, read at most 1 MB, and send an identified user agent. - New MCP service switch "FIT Wiki"; the provider functions come in T28. - Connections UI: a FIT Wiki card with both modes, help text and a registration link (en/cs). - PLAN.md: the part 2 plan (FIT Wiki, Bílá kniha, Courses API with `cvut:cpages:common:read`, GitLab as fallback). Note for the next production deploy: add `FITWIKI_LOGIN_LIMIT` to `env.production` (PR #26). ### Review (Astra) - Fixed [P2]: switching from "paste cookie" to "log in" reused the input element, so a pasted cookie could show up as text in the username field. The form now remounts per mode (verified in a browser). ### Checks lint, typecheck and test: 318 passing. Dev smoke test: the card renders in both modes, and a fake cookie is checked against fit-wiki.cz, rejected with the friendly error and not stored. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- src/lib/fitwiki.ts: cookie normalisation (DokuWiki/DW<hash> only), one-shot login with
  'remember me', session check; bounded, manual redirects, identified UA
- POST /api/connections/fitwiki (session + same-origin; per-user login rate limit
  FITWIKI_LOGIN_LIMIT); provider fitwiki, kind cookie; disconnect; MCP service switch
- Connections: FIT Wiki card with both modes; en/cs
- PLAN.md: part 2 plan

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin t27-fitwiki-connection:t27-fitwiki-connection
git switch t27-fitwiki-connection

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff t27-fitwiki-connection
git switch t27-fitwiki-connection
git rebase main
git switch main
git merge --ff-only t27-fitwiki-connection
git switch t27-fitwiki-connection
git rebase main
git switch main
git merge --no-ff t27-fitwiki-connection
git switch main
git merge --squash t27-fitwiki-connection
git switch main
git merge --ff-only t27-fitwiki-connection
git switch main
git merge t27-fitwiki-connection
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dzenda/os!27
No description provided.