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>
3.7 KiB
Konta i uprawnienia (PRE-27)
Rozszerzenie kont imiennych z PRE-17: konta zakłada się z aplikacji, a każde dostaje własny zestaw funkcji.
Dwie zasady, z których wynika reszta
1. Konto ograniczone widzi program KOMPLETNY — tylko mniejszy. Nic nie może zdradzać, że istnieje coś więcej. Żadnych wyszarzonych zakładek, żadnego „brak uprawnień", żadnego 403 — bo 403 samo w sobie jest informacją, że pod tym adresem coś jest. Ścieżka bez uprawnienia odpowiada 404, tak samo jak adres, którego nie ma.
Z tej zasady wynikło też wyłączenie /docs, /redoc i /openapi.json.
Automatyczna dokumentacja FastAPI wypisuje komplet tras — czyli spis wszystkich
funkcji programu. Ochrona zakładek nic by nie dała, gdyby obok leżał ich katalog.
(Znalezione testem, nie przeglądem kodu.)
2. Konto administracyjne pochodzi WYŁĄCZNIE ze środowiska.
APP_USER / APP_PASSWORD (albo APP_USERS) — jak dotąd. To konto ma wszystkie
uprawnienia i jako jedyne zarządza pozostałymi. Nie leży w pliku kont, więc
nie da się go skasować ani ograniczyć z ekranu — nawet przez pomyłkę, nawet
spreparowanym żądaniem. Konto założone w pliku o tym samym loginie nie
przesłoni administracyjnego (kolejność sprawdzania jest odwrotna).
Podział funkcji
Ekrany — zakładki widoczne w nawigacji:
| klucz | zakładka |
|---|---|
chart |
Horoskop |
interpret |
Interpretacje |
timeline |
Kalendarz |
synastry |
Synastria |
significators |
Sygnifikatory |
compile |
Skompiluj |
settings |
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 planet, tabele żywiołów i faz, aspekty poboczne, zodiaki syderyczne |
ai |
horoskopy pisane przez model językowy (każde użycie kosztuje) |
export |
pobieranie PDF i Excela |
Konto bez houses_compare dostaje horoskop w Whole Sign i nie widzi, że
systemów jest trzynaście. Konto bez ai nie zobaczy przycisku generowania ani
nie wywoła go z pominięciem interfejsu.
Gdzie leży granica
W handlerze, nie w szablonie. Ukrycie pola w formularzu chroni przed przypadkiem,
ale nie przed kimś, kto zna nazwy pól — dlatego _limit_options() ścina opcje
po stronie serwera, a rysunki dodatkowe bez uprawnienia w ogóle nie powstają
(nie ma ich nawet w źródle strony).
Mapa trasa → uprawnienie jest jedna, w app/features.py. Rozproszenie jej
po dekoratorach kończy się trasą, o której ochronie ktoś zapomniał — a taka dziura
jest niewidoczna do chwili, gdy ktoś ją znajdzie. Trasa bez wpisu w mapie wymaga
uprawnień administracyjnych: przeoczenie ma zamykać, nie otwierać. Test
przechodzi po wszystkich trasach aplikacji i wymaga, by każda była opisana.
Gdzie leżą konta
Plik JSON wskazany przez ACCOUNTS_FILE (domyślnie /app/state/accounts.json),
na NFS — własny podkatalog prezentacji, nie katalog z bazami: zamontowanie
tutaj całego udziału obeszłoby bokiem zamknięcie dostępu z DAN-25.
Hasła wyłącznie jako hash scrypt, tym samym mechanizmem co APP_USERS — jedna
implementacja, więc nie ma czego rozjechać. Zapis jest atomowy (plik
tymczasowy + os.replace w tym samym katalogu): przerwanie zapisu nie obetnie
pliku, czyli nie skasuje wszystkich kont naraz.
Czego ten mechanizm NIE robi
Nie zastępuje ochrony baz na poziomie sieci ani NFS (DAN-25). Ktoś z dostępem do udziału albo do warstwy danych nadal je odczyta — uprawnienia w aplikacji ograniczają to, co widać przez aplikację, i tyle.