Kontrola dostępu: konta z uprawnieniami do zakładek i funkcji (PRE-27) #68

Merged
gitea merged 1 commits from feat/kontrola-dostepu into master 2026-08-07 12:18:14 +00:00
Owner

Ekran „Konta" dla administratora: zakładanie, kasowanie, nadawanie uprawnień. Zestaw funkcji zależy od konta, a konto ograniczone widzi program kompletny — tylko mniejszy.

Podział na grupy

Ekrany (7 zakładek) — naturalna jednostka, bo to je widać w nawigacji: Horoskop, Interpretacje, Kalendarz, Synastria, Sygnifikatory, Skompiluj, Ustawienia.

Rozszerzenia — poziomy złożoności wewnątrz ekranów:

klucz co daje
houses_compare wybór systemu domów, zestawienie kilku obok siebie, obrót koła
extra_charts aspektarian, wykres deklinacji, oś antyscji
advanced_calc stacje, tabele żywiołów i faz, aspekty poboczne, zodiaki syderyczne
ai horoskopy pisane przez model (każde użycie kosztuje)
export pobieranie PDF i Excela

Konto bez houses_compare dostaje horoskop w Whole Sign i nie wie, że systemów jest trzynaście.

Nic nie zdradza, że jest więcej

  • brak pozycji w menu zamiast pozycji wyszarzonej
  • 404 zamiast 403 — odmowa z powodem sama mówi, że coś tam jest
  • rysunki bez uprawnienia w ogóle nie powstają, więc nie ma ich nawet w źródle strony
  • automatyczna dokumentacja API wyłączona

Ten ostatni punkt znalazł test, nie przegląd kodu: /docs, /redoc i /openapi.json wypisują komplet tras, czyli spis wszystkich funkcji programu. Ochrona zakładek nic by nie dała, gdyby obok leżał ich katalog.

Konto administracyjne

Zostaje w APP_USER/APP_PASSWORD, jak było. Nie leży w pliku kont, więc nie da się go skasować ani ograniczyć z ekranu. Konto założone w pliku o tym samym loginie nie przesłoni administracyjnego — kolejność sprawdzania jest odwrotna, inaczej dałoby się odebrać uprawnienia jedynemu, kto może je nadawać. Uprawnienia administracyjnego nie da się też nadać z formularza: odsiewamy je w normalise(), nie w handlerze.

Gdzie leży granica

W handlerze, nie w szablonie. Ukrycie pola chroni przed przypadkiem, nie przed kimś, kto zna nazwy pól — _limit_options() ścina opcje po stronie serwera, a test wysyła spreparowane żądanie z stations=true&zodiac=sidereal_lahiri&house_systems=koch, żeby potwierdzić, że nic z tego nie przechodzi.

Mapa trasa → uprawnienie jest jedna (features.ROUTES). Trasa bez wpisu wymaga administratora: przeoczenie ma zamykać, nie otwierać. Test idzie po trasach aplikacji, nie po wpisach mapy — inaczej potwierdzałby tylko sam siebie (i to on znalazł /docs).

Przechowywanie

Plik JSON na własnym podkatalogu NFS, nie tam, gdzie bazy — zamontowanie całego udziału obeszłoby bokiem DAN-25. Hasła wyłącznie jako hash scrypt, tym samym mechanizmem co APP_USERS. Zapis atomowy, bo przerwanie zapisu obcięłoby plik, czyli skasowało wszystkie konta naraz.

⚠️ Wymaga wolumenu — osobny PR w repo deploy (gałąź feat/konta-prezentacja). Bez niego konta znikną przy restarcie poda.

Weryfikacja

21 testów kontroli dostępu, w tym pełny obieg: administrator zakłada konto → osoba loguje się i dostaje dokładnie przyznany zestaw → odebranie uprawnienia działa od razu → skasowanie konta odcina logowanie. Suity: prezentacja 281, logika 342, render 41, dane 13.

Przy okazji przepisane trzy testy, które greppowały nawigację i main.py — menu powstaje teraz z katalogu, więc szukanie sztywnych linków w base.html niczego już nie sprawdzało.

🤖 Generated with Claude Code

Ekran **„Konta"** dla administratora: zakładanie, kasowanie, nadawanie uprawnień. Zestaw funkcji zależy od konta, a konto ograniczone widzi program **kompletny — tylko mniejszy**. ## Podział na grupy **Ekrany** (7 zakładek) — naturalna jednostka, bo to je widać w nawigacji: Horoskop, Interpretacje, Kalendarz, Synastria, Sygnifikatory, Skompiluj, Ustawienia. **Rozszerzenia** — poziomy złożoności *wewnątrz* ekranów: | klucz | co daje | |---|---| | `houses_compare` | wybór systemu domów, zestawienie kilku obok siebie, obrót koła | | `extra_charts` | aspektarian, wykres deklinacji, oś antyscji | | `advanced_calc` | stacje, tabele żywiołów i faz, aspekty poboczne, zodiaki syderyczne | | `ai` | horoskopy pisane przez model (**każde użycie kosztuje**) | | `export` | pobieranie PDF i Excela | Konto bez `houses_compare` dostaje horoskop w Whole Sign i **nie wie**, że systemów jest trzynaście. ## Nic nie zdradza, że jest więcej - brak pozycji w menu zamiast pozycji wyszarzonej - **404 zamiast 403** — odmowa z powodem sama mówi, że coś tam jest - rysunki bez uprawnienia **w ogóle nie powstają**, więc nie ma ich nawet w źródle strony - **automatyczna dokumentacja API wyłączona** Ten ostatni punkt znalazł **test, nie przegląd kodu**: `/docs`, `/redoc` i `/openapi.json` wypisują komplet tras, czyli spis wszystkich funkcji programu. Ochrona zakładek nic by nie dała, gdyby obok leżał ich katalog. ## Konto administracyjne Zostaje w `APP_USER`/`APP_PASSWORD`, jak było. **Nie leży w pliku kont**, więc nie da się go skasować ani ograniczyć z ekranu. Konto założone w pliku o tym samym loginie **nie przesłoni** administracyjnego — kolejność sprawdzania jest odwrotna, inaczej dałoby się odebrać uprawnienia jedynemu, kto może je nadawać. Uprawnienia administracyjnego nie da się też nadać z formularza: odsiewamy je w `normalise()`, nie w handlerze. ## Gdzie leży granica **W handlerze, nie w szablonie.** Ukrycie pola chroni przed przypadkiem, nie przed kimś, kto zna nazwy pól — `_limit_options()` ścina opcje po stronie serwera, a test wysyła spreparowane żądanie z `stations=true&zodiac=sidereal_lahiri&house_systems=koch`, żeby potwierdzić, że nic z tego nie przechodzi. Mapa `trasa → uprawnienie` jest **jedna** (`features.ROUTES`). Trasa bez wpisu wymaga administratora: **przeoczenie ma zamykać, nie otwierać**. Test idzie po trasach *aplikacji*, nie po wpisach mapy — inaczej potwierdzałby tylko sam siebie (i to on znalazł `/docs`). ## Przechowywanie Plik JSON na **własnym podkatalogu NFS**, nie tam, gdzie bazy — zamontowanie całego udziału obeszłoby bokiem DAN-25. Hasła wyłącznie jako hash scrypt, tym samym mechanizmem co `APP_USERS`. Zapis atomowy, bo przerwanie zapisu obcięłoby plik, czyli skasowało wszystkie konta naraz. ⚠️ **Wymaga wolumenu** — osobny PR w repo `deploy` (gałąź `feat/konta-prezentacja`). Bez niego konta znikną przy restarcie poda. ## Weryfikacja 21 testów kontroli dostępu, w tym pełny obieg: administrator zakłada konto → osoba loguje się i dostaje dokładnie przyznany zestaw → odebranie uprawnienia działa od razu → skasowanie konta odcina logowanie. Suity: prezentacja 281, logika 342, render 41, dane 13. Przy okazji przepisane trzy testy, które greppowały nawigację i `main.py` — menu powstaje teraz z katalogu, więc szukanie sztywnych linków w `base.html` niczego już nie sprawdzało. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
gitea added 1 commit 2026-08-06 19:46:01 +00:00
feat(bezpieczeństwo): konta z uprawnieniami do zakładek i funkcji (PRE-27)
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m31s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m33s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 17s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m32s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m32s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 19s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 10s
73af7205d1
Ekran „Konta" dla administratora: zakładanie, kasowanie i nadawanie uprawnień.
Zestaw funkcji zależy od konta, a konto ograniczone widzi program KOMPLETNY —
tylko mniejszy.

PODZIAŁ NA GRUPY. Ekrany to zakładki (7), bo zakładka jest naturalną jednostką —
to ją widać w nawigacji. Rozszerzenia to POZIOMY ZŁOŻONOŚCI wewnątrz ekranów:
porównanie systemów domów, wykresy dodatkowe, obliczenia zaawansowane, generowanie
tekstu przez model (kosztuje pieniądze) i eksport plików. Konto bez porównania
domów dostaje horoskop w Whole Sign i nie wie, że systemów jest trzynaście.

NIC NIE ZDRADZA, ŻE JEST WIĘCEJ:
- brak pozycji w menu zamiast pozycji wyszarzonej,
- 404 zamiast 403 — odmowa z powodem sama mówi, że coś tam jest,
- rysunki bez uprawnienia w OGÓLE NIE POWSTAJĄ, więc nie ma ich nawet w źródle,
- automatyczna dokumentacja API wyłączona. /docs, /redoc i /openapi.json wypisują
  komplet tras, czyli spis wszystkich funkcji programu — ochrona zakładek nic by
  nie dała, gdyby obok leżał ich katalog. Znalezione TESTEM przechodzącym po
  trasach aplikacji, nie przeglądem kodu.

KONTO ADMINISTRACYJNE zostaje w APP_USER/APP_PASSWORD, jak było. Nie leży w pliku
kont, więc nie da się go skasować ani ograniczyć z ekranu. Konto założone w pliku
o tym samym loginie NIE przesłoni administracyjnego — kolejność sprawdzania jest
odwrotna, inaczej dałoby się odebrać uprawnienia jedynemu, kto może je nadawać.
Uprawnienia administracyjnego nie da się też nadać z formularza: odsiewamy je
w normalise(), a nie w handlerze, więc żadne spreparowane żądanie tam nie sięgnie.

GRANICA JEST W HANDLERZE, NIE W SZABLONIE. Ukrycie pola chroni przed przypadkiem,
nie przed kimś, kto zna nazwy pól — _limit_options() ścina opcje po stronie
serwera i test wysyła spreparowane żądanie, żeby to potwierdzić.

MAPA TRASA→UPRAWNIENIE JEST JEDNA (features.ROUTES). Rozproszenie jej po
dekoratorach kończy się trasą, o której ochronie ktoś zapomniał — a taka dziura
jest niewidoczna, dopóki ktoś jej nie znajdzie. Trasa bez wpisu wymaga
administratora: przeoczenie ma ZAMYKAĆ, nie otwierać. Test idzie po trasach
APLIKACJI, nie po wpisach mapy — inaczej potwierdzałby tylko sam siebie.

Konta w pliku JSON na własnym podkatalogu NFS (nie tam, gdzie bazy — zamontowanie
całego udziału obeszłoby bokiem DAN-25). Hasła wyłącznie jako hash scrypt, tym
samym mechanizmem co APP_USERS. Zapis atomowy, bo przerwanie zapisu na NFS
obcięłoby plik, czyli skasowało wszystkie konta naraz.

Przy okazji przepisane trzy testy, które greppowały nawigację i main.py: menu
powstaje teraz z katalogu funkcji, więc szukanie sztywnych linków w base.html
niczego już nie sprawdzało.

Wymaga wolumenu na konta — osobny PR w repo deploy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gitea merged commit a833965909 into master 2026-08-07 12:18:14 +00:00
gitea deleted branch feat/kontrola-dostepu 2026-08-07 12:18:14 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gitea/astrololo#68