Files
astrololo/services/presentation/app/static/wyloguj.js
T
gitea 71bb3b9c0a
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m17s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 5s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 4s
build / build (push) Successful in 1m18s
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 / Build obrazu silnika B (swisseph) (push) Successful in 5s
Testy / Kontrola składni wszystkich warstw (push) Successful in 4s
feat(bezpieczeństwo): przycisk wylogowania (LOG-32)
Aplikacja nie miała jak z siebie wyjść: raz podane hasło działało do zamknięcia
przeglądarki, a na wspólnym komputerze nie było sposobu, żeby oddać ekran komuś
innemu.

HTTP BASIC NIE MA PRAWDZIWEGO WYLOGOWANIA i to jest sedno tej zmiany. Nie ma
sesji do skasowania: przeglądarka zapamiętuje login i hasło, po czym dosyła je
SAMA przy każdym żądaniu. Serwer nie ma czego zapomnieć — kolejne kliknięcie
przyszłoby z kompletem poświadczeń i weszłoby z powrotem.

Działa natomiast doprowadzenie do tego, żeby to PRZEGLĄDARKA porzuciła zapamiętane
dane, i robimy to dwutorowo, bo ani jedno, ani drugie osobno nie wystarcza:

  1. /wyloguj odpowiada ZAWSZE 401 z nagłówkiem WWW-Authenticate, co wymusza
     ponowne pytanie o hasło. Działa bez JavaScriptu, ale samo w sobie zostawia
     stare dane w pamięci przeglądarki: po anulowaniu okienka wystarczyłoby wejść
     na dowolny adres, żeby wrócić do środka.
  2. wyloguj.js wysyła żądanie z CELOWO błędnymi danymi, którym przeglądarka
     nadpisuje swój wpis. To jest część, która faktycznie czyści pamięć — ale
     opiera się na zachowaniu powszechnym, a nie zapisanym w standardzie, więc
     nie może być jedynym mechanizmem.

Strona wylogowania mówi wprost, że pewnym sposobem w KAŻDEJ przeglądarce jest
zamknięcie okna. Nie obiecujemy więcej, niż Basic potrafi — obietnica bez pokrycia
byłaby tu gorsza od braku przycisku, bo dawałaby złudzenie, że ekran jest oddany.

Trasa stoi POZA bramką logowania, celowo: inaczej dostałaby 200 od zalogowanej
sesji i nie miałaby jak odpowiedzieć 401. Odpowiada też bez logowania — inaczej
wyjście wymagałoby bycia w środku, co jest błędnym kołem. Nagłówki zakazują
zapamiętania strony, bo oddana z pamięci podręcznej nie dotarłaby do serwera
i okienko w ogóle by się nie pojawiło.

Obok wyjścia pokazujemy, KTO jest zalogowany: bez tego przycisk jest w połowie
bezużyteczny, bo na wspólnym komputerze nie wiadomo, kogo się wylogowuje. Przy
wyłączonym logowaniu nie ma ani jednego, ani drugiego — przycisk sugerowałby
ochronę, której nie ma.

Sprawdzone w przeglądarce: oba żądania wychodzą (to z błędnymi danymi i samo
przejście), oba wracają 401, strona renderuje się poprawnie. Samego unieważnienia
pamięci poświadczeń NIE dało się tu potwierdzić — wymaga okienka systemowego,
którego automat nie obsłuży.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:52:04 +02:00

45 lines
1.8 KiB
JavaScript

// Wylogowanie z HTTP Basic (LOG-32).
//
// PROBLEM, KTÓREGO NIE DA SIĘ ROZWIĄZAĆ PO STRONIE SERWERA. Basic nie ma sesji:
// przeglądarka zapamiętuje login i hasło, po czym dosyła je SAMA przy każdym
// żądaniu. Serwer nie ma czego „zapomnieć" — następne kliknięcie przyszłoby
// z kompletem poświadczeń i weszłoby z powrotem.
//
// Działa natomiast doprowadzenie do tego, żeby PRZEGLĄDARKA porzuciła to, co
// zapamiętała: żądanie z celowo błędnymi danymi, którym nadpisuje ona swój wpis
// dla tej witryny. To jest zachowanie powszechne w przeglądarkach, ale NIE
// ZAPISANE w żadnym standardzie — dlatego jest tu jako uzupełnienie, a nie
// jedyny mechanizm: sama trasa /wyloguj odpowiada 401 i wymusza okienko
// logowania nawet przy wyłączonym JavaScripcie.
(function () {
'use strict';
function ready(fn) {
if (document.readyState !== 'loading') fn();
else document.addEventListener('DOMContentLoaded', fn);
}
ready(function () {
var link = document.querySelector('a[data-wyloguj]');
if (!link) return;
link.addEventListener('click', function (e) {
e.preventDefault();
// Znacznik czasu w loginie: gdyby przeglądarka zapamiętała nawet TE dane,
// przy kolejnym wylogowaniu byłyby już inne, więc nie da się przypadkiem
// trafić w cokolwiek działającego.
var bezsensowne = 'Basic ' + btoa('wyloguj:' + Date.now());
fetch(link.href, {
headers: {Authorization: bezsensowne},
cache: 'no-store',
credentials: 'omit'
}).catch(function () {
// Brak sieci nie może zablokować wyjścia — i tak przechodzimy dalej,
// bo sama trasa /wyloguj odpowie 401 i wywoła okienko logowania.
}).then(function () {
window.location.href = link.href;
});
});
});
})();