338ec24e90
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m20s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m26s
Testy / Testy astrodemo (pull_request) Successful in 9m25s
Testy / Testy astroklient (pull_request) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 6s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 5s
build / build (push) Successful in 12s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m21s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Testy astrodemo (push) Successful in 9m25s
Testy / Testy astroklient (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 6s
Testy / Kontrola składni wszystkich warstw (push) Successful in 4s
Astroklient przedstawiał się na stronie głównej jako „astrololo" — w tytule karty i w nagłówku. To najpoważniejszy z możliwych śladów: mówi klientowi wprost, że trzyma okrojoną wersję czegoś większego, i podaje frazę, po której da się wyszukać, czego mu nie dano. Cała reszta izolacji przestaje mieć znaczenie, gdy produkt sam się przedstawia nazwą rodzica. Wzięło się stąd, że nazwa była wpisana na sztywno w szablony, a szablony są WSPÓLNE — dokładnie ta sama przyczyna, co przy zaszytym w base.html warunku na administratora. Nazwa mieszka teraz w module `produkt.py`, który nakładka produktu nadpisuje; szablony o nią pytają, zamiast ją znać. astrodemo NIE było dotknięte: ma własne kopie szablonów i pokazuje „astrodemo". DRUGIE ŹRÓDŁO WYCIEKU, mniej oczywiste: nazwa siedziała też w identyfikatorach JavaScriptu, które widzi każdy, kto otworzy narzędzia deweloperskie — zdarzenie `astrololo:coords` i klucz `astrololo.form.v1` w localStorage. Przemianowane na neutralne `kosmogram:*`; te identyfikatory nie mają powodu nosić nazwy rodziny produktów. SKUTEK UBOCZNY: zmiana klucza w localStorage kasuje raz zapamiętane wersje robocze formularza. Sprawdzone, że NIE wyciekają: nagłówki X-Astrololo-* jadą wyłącznie między warstwami, a dokumentacja OpenAPI (gdzie zostaje tytuł aplikacji FastAPI) oddaje 404 także zalogowanemu. TEST rozdziela to, co widzi człowiek, od identyfikatorów wewnętrznych. Nazwa rdzenia wolno występować w nazwach loggerów, materiale do wyprowadzania kluczy i nagłówkach międzywarstwowych; nie wolno w szablonach, zasobach ani w treści odpowiedzi. Zakaz na wszystko byłby albo obejściem przez zmianę nazw kluczy kryptograficznych, albo martwą regułą wyłączaną przy pierwszej okazji. Sprawdzony w obie strony: po cofnięciu nakładki test pada. Testy: astroklient 15, presentation 368, astrodemo 28, logic 342, data 42, render 41. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
65 lines
3.3 KiB
HTML
65 lines
3.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="pl">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{ produkt }} · {% block title %}{% endblock %}</title>
|
|
{# Arkusz wspólny niesie WYŁĄCZNIE powłokę i logowanie — wszystko, co nazywa
|
|
jakąkolwiek funkcję, mieszka w arkuszu tej funkcji i dokłada je `styles`.
|
|
Inaczej jeden plik, pobierany też przed zalogowaniem, byłby spisem treści
|
|
programu: nazwa selektora opowiada o funkcji tak samo dobrze jak przycisk. #}
|
|
<link rel="stylesheet" href="{{ static('base.css') }}">
|
|
{% block styles %}{% endblock %}
|
|
{# Skrypty dokłada ekran, który ich potrzebuje. Ładowane stąd docierały na
|
|
KAŻDĄ stronę — także do konta, które ma wyłącznie Pliki — a ich treść
|
|
wymienia z nazwy ekrany, których takie konto nie ma prawa znać.
|
|
Blok jest w <head>, bo `defer` wykonuje skrypty w kolejności dokumentu:
|
|
formsync musi odtworzyć współrzędne, ZANIM geo.js zbuduje mapę. #}
|
|
{% block head_scripts %}{% endblock %}
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<header class="topbar">
|
|
<h1>{{ produkt }}</h1>
|
|
{# Zakładki WYŁĄCZNIE z uprawnień konta. Nie wyszarzamy niedostępnych —
|
|
ich po prostu nie ma, bo sama obecność wyszarzonej pozycji mówi, że
|
|
program umie więcej, niż pokazuje (PRE-26). #}
|
|
<nav>
|
|
{% for tab in nav_screens(request) %}
|
|
<a href="{{ tab.href }}" class="{{ 'active' if nav_active is defined and nav_active == tab.key else '' }}">{{ tab.label }}</a>
|
|
{% endfor %}
|
|
{# Pozycje specjalne z REJESTRU, już przefiltrowane uprawnieniem. Wpisany
|
|
tu na sztywno odsyłacz zostawał w produkcie, który tego ekranu nie ma —
|
|
razem z nazwą ekranu i martwym adresem. #}
|
|
{% for klucz, adres, etykieta in nav_extra(request) %}
|
|
<a href="{{ adres }}" class="{{ 'active' if nav_active is defined and nav_active == klucz else '' }}">{{ etykieta }}</a>
|
|
{% endfor %}
|
|
{# Wyjście na końcu paska i odsunięte: to nie jest zakładka, tylko
|
|
czynność — pomylenie go z zakładką kosztuje przypadkowe wylogowania.
|
|
Pokazujemy też KTO jest zalogowany, bo bez tego przycisk wyjścia jest
|
|
w połowie bezużyteczny: na wspólnym komputerze nie wiadomo, kogo się
|
|
wylogowuje. Bez włączonego logowania nie ma z czego wychodzić. #}
|
|
{% if auth_on() %}
|
|
<span class="whoami" title="Zalogowano jako">{{ current_user(request) }}</span>
|
|
{# POST, nie odsyłacz: pod adresem GET wystarczyłby obrazek na obcej
|
|
stronie, żeby wylogować kogoś bez jego wiedzy. #}
|
|
<form method="post" action="/wyloguj" class="wyloguj-form">
|
|
<button type="submit" class="wyloguj">Wyloguj</button>
|
|
</form>
|
|
{% endif %}
|
|
</nav>
|
|
</header>
|
|
{% block content %}{% endblock %}
|
|
{# Stopka wymienia warstwy architektury i nazywa całość „widokiem testowym" —
|
|
czyli mówi, że to nie jest gotowy produkt i że za nim stoi łańcuch usług.
|
|
Widzi ją wyłącznie konto z uprawnieniem nienadawalnym; dla pozostałych
|
|
program ma wyglądać na kompletny. #}
|
|
{% if widok_diagnostyczny(request) %}
|
|
<footer class="foot">
|
|
prezentacja → logika → dane · widok testowy
|
|
</footer>
|
|
{% endif %}
|
|
</main>
|
|
</body>
|
|
</html>
|