M
MOKATE · allegro-serwer-test
serwer aktywny
Serwer tymczasowy · North Europe

Panel serwera
i aplikacji webowych

Punkt startowy do wszystkich aplikacji uruchomionych na tej maszynie oraz skrócona instrukcja jej obsługi. Od lipca 2026 część ruchu przechodzi przez nową, centralną bramę logowania (oauth2-proxy + authz.py) — w pełni /targety/, (od 10.07.2026) /allegro_api/ oraz (od 14.07.2026) /generator_produktow/ oraz (od 15.07.2026) /autoprezentacja/; /karty/ ma logowanie własne. Od 14.07.2026 ta sama brama potrafi też dokładać apkom delegowany dostęp do Microsoft Graph/SharePoint (X-Graph-Token) — obecnie /allegro_api/ i /autoprezentacja/, patrz punkt 09. Pełny słownik pojęć i architektury niżej.

Nowa brama (2026) · w pełni: /targety/, /allegro_api/, /generator_produktow/, /autoprezentacja/
żądanie ──▶ NGINX ──▶ authz.py :5098 ──▶ oauth2-proxy · sesja Entra ID + Azure SQL · dostęp do apki ──▶ /targety/ /allegro_api/ /generator_produktow/ /autoprezentacja/ authz.py = punkt krytyczny logowania
Graf / SharePoint (nowość 14.07.2026 · /allegro_api/, /autoprezentacja/)
authz.py ──▶ Microsoft Graph prompt=none refresh token · zaszyfrowany ──▶ X-Graph-Token niezależne od X-Sql-Token (inny „aud”)
Logowanie własne (bez zmian)
żądanie ──▶ NGINX ──▶ własny login OIDC w apce ──▶ /karty/ niezależne od nowej bramy
Nazwa Azure
allegro-serwer-test
Publiczne IP
74.234.19.63
Etykieta DNS
mokate-dabid-serwer.northeurope.cloudapp.azure.com
Konfiguracja Entra ID
Logowanie DABiD
Brama logowania (nowość)
oauth2-proxy + authz.py · /targety/, /allegro_api/, /generator_produktow/, /autoprezentacja/ (pełna migracja)
Delegowany Graf (nowość 14.07.2026)
authz.py · /authz/graph/connect+callback · /allegro_api/, /autoprezentacja/

Od 17.07.2026 publiczny adres serwera to mokate-dabid-serwer.northeurope.cloudapp.azure.com — dawny allegro-test-mokate… już nie odpowiada (zmieniono etykietę DNS na tym samym Public IP). IP 74.234.19.63 oraz nazwa VM allegro-serwer-test — bez zmian.

Aplikacje

7 usług

Słownik pojęć

architektura logowania

Krótkie wyjaśnienie każdego elementu, który dokłada się do procesu logowania i routingu na tym serwerze — od lipca 2026.

NGINX

Serwer WWW i reverse proxy. Obsługuje TLS (certyfikaty przez Certbot) i kieruje żądania do właściwej aplikacji po ścieżce URL. Konfiguracja: /etc/nginx/strony/.

Entra ID

Usługa Microsoft do logowania kontem firmowym @mokate.com.pl. Jedna apka „Logowanie DABiD” w Entra jest wspólnym rejestrem dla całego serwera.

oauth2-proxy

Lokalny mikroserwis (port 4180). Przeprowadza logowanie do Entra ID i pamięta sesję w ciastku. Odpowiada na pytanie „czy to Ty”.

authz.py

Nasz mikroserwis Flask (port 5098). Łączy sprawdzenie sesji (oauth2-proxy) ze sprawdzeniem uprawnień do konkretnej apki (SQL). Odpowiada na pytanie „czy Ty masz dostęp do TEJ apki”.

auth_request

Mechanizm NGINX do pod-żądań autoryzacyjnych. Limit: tylko jedno wywołanie per lokalizacja — stąd authz.py, który sam odpytuje oauth2-proxy w środku.

Nagłówki X-*

Dane o zalogowanym użytkowniku (e-mail, imię, nazwisko, token SQL), które brama dokleja do żądania. Apka może im ufać bez własnego logowania.

JWT

Token w formacie header.payload.signature (base64url). Claimy (e-mail, imię, nazwisko) można odczytać bez weryfikacji podpisu — podpis zweryfikował już oauth2-proxy.

Token delegowany do SQL

Token dostępowy konkretnego użytkownika (nie konto serwisowe), którym apki łączą się prosto do Azure SQL — z takimi uprawnieniami, jakie ma dany użytkownik.

X-Graph-Token

Analogicznie do X-Sql-Token, ale do Microsoft Graph (SharePoint) — delegowany token konkretnego zalogowanego użytkownika. Zdobywa go authz.py osobnym, cichym logowaniem (prompt=none), niezależnym od sesji SQL/oauth2-proxy. Dziś dla /allegro_api/ i /autoprezentacja/.

prompt=none

Parametr OIDC każący Microsoft zalogować w tle, bez żadnego ekranu — działa, bo zgoda administratora już jest, a przeglądarka ma żywą sesję SSO z chwili głównego logowania chwilę wcześniej.

src.SerwerDostepyAplikacji

Tabela w Azure SQL: „ten e-mail ma dostęp do tej apki”. Jedyne miejsce, gdzie ręcznie zarządza się dostępami do bramy.

tmux

Terminal multiplexer. Każda aplikacja żyje w panelu jednej z dwóch sesji (mokate-server, app-targety-ph) — odłączenie się nie zatrzymuje apek.

systemd

Usługa mokate-server.service odpala jeden skrypt (auto-start.sh), który sam odtwarza sesje tmux po restarcie serwera.

Certbot

Automatyczne certyfikaty TLS dla NGINX — dzięki nim aplikacje wymagające logowania Entra ID działają po HTTPS na porcie 443.

Stan migracji

nowa brama logowania
ApkaZa nową bramą?Uwagi
/targety/✅ TakW pełni zmigrowana — NGINX i kod apki czytają nagłówki z bramy
/allegro_api/✅ TakW pełni zmigrowana (od 10.07.2026) — NGINX i kod apki czytają nagłówki z bramy, bez podwójnego logowania. Od 14.07.2026 pierwsza apka z delegowanym dostępem do Microsoft Graph (X-Graph-Token, patrz punkt 09)
/generator_produktow/✅ Tak (od 14.07.2026)W pełni zmigrowana — wcześniej całkiem otwarta (bez logowania), teraz NGINX i kod apki czytają nagłówki z bramy. Bez X-Graph-Token (mają to /allegro_api/ i /autoprezentacja/)
/autoprezentacja/✅ Tak (od 15.07.2026)W pełni zmigrowana — NGINX i kod apki czytają nagłówki z bramy, bez własnego logowania. Delegowany dostęp do Microsoft Graph/SharePoint (X-Graph-Token) od 15.07.2026 — druga apka po /allegro_api/. Uwaga: nazwa w APPS_NEEDING_GRAPH musi być dokładnie „autoprezentacja" (= pierwszy segment URL-a), nie „autoryzacja" (katalog authz.py) — patrz punkt 09
/karty/❌ NieWłasne logowanie .NET OIDC — trzeba je wyłączyć przed migracją

Instrukcja

obsługa serwera
01 Połączenie z serwerem (SSH / RDP)

SSH (konsola — CMD lub PowerShell). Użytkownik administracyjny: dabid.

ssh dabid@74.234.19.63

tylko IP MOKATE Port 22 (SSH) jest osiągalny wyłącznie z sieci MOKATE — spoza niej połączenie nie przejdzie (dotyczy też tunelu RDP poniżej, bo idzie przez SSH).

Hasło administratora nie jest zapisane na tej stronie — ta strona jest publiczna (route / nie ma logowania Entra ID). Hasło trzymajcie w menedżerze haseł / prywatnej notatce.

RDP (pulpit zdalny) — MOKATE blokuje RDP spoza sieci, więc łączymy się przez tunel SSH. Najszybciej pobrać oba gotowe pliki:

Kolejność użycia:

  1. Uruchom polacz-rdp.bat — otwiera tunel SSH z lokalnego portu 3390 na port RDP serwera. Zaloguj się (okno zostaw otwarte). Odpowiednik komendy:
    ssh -L 3390:localhost:3389 dabid@74.234.19.63
  2. Otwórz serwer.rdp, zatwierdź ostrzeżenia (OK / Zgadzam się) i zaloguj się na konto maszyny. Plik zawiera jedną linię:
    full address:s:localhost:3390

Pliki możesz też stworzyć ręcznie — nazwa dowolna, ważne rozszerzenia .bat i .rdp.

02 NGINX — nowa struktura plików (2026)

Poprzednio jeden płaski plik. Od lipca 2026 konfiguracja jest rozbita na katalogi:

strony/kartka.conf ← server{}, oauth2/, logout, root, include apps/ strony/snippets/authz-gate.conf ← wspólny blok: auth_request + nagłówki X-* strony/snippets/proxy-common.conf ← wspólne proxy_set_header dla wszystkich apek strony/apps/<nazwa>.conf ← pojedynczy location{} per aplikacja

Ważne: główny include /etc/nginx/strony/*.conf; (w nginx.conf) wczytuje tylko pliki bezpośrednio w strony/. Pliki z strony/apps/ wczytuje osobny include .../apps/*.conf; wewnątrz bloku server{} w kartka.conf — bo zawierają gołe location{} bez własnego server{}.

Nauczone boleśnie: nigdy nie zostawiaj plików .bak w strony/ ani strony/apps/ — jeśli pasują do wzorca wildcard include, NGINX wczyta je i przy zduplikowanym server_name może po cichu wybrać stary, niezabezpieczony blok bez żadnego błędu w nginx -t. Backupy trzymamy poza /etc/nginx/ całkowicie (np. ~/nginx-backups/).

Po każdej zmianie przetestuj i przeładuj (test musi przejść, zanim reload wejdzie w życie):

sudo nginx -t && sudo systemctl reload nginx

Dodatkowa mapa potrzebna do obsługi WebSocketów w proxy:

/etc/nginx/conf.d/websocket_upgrade.conf

NGINX obsługuje tylko jeden auth_request per lokalizację — druga deklaracja bezgłośnie nadpisuje pierwszą, bez błędu w nginx -t. Dlatego sprawdzenie sesji i sprawdzenie dostępu są połączone w jednym miejscu: authz.py (patrz punkt 03).

Każda nowa aplikacja musi mieć ROOT ustawiony nie na /, lecz na swój route (np. /raporty) — zarówno w samej aplikacji, jak i w konfiguracji NGINX.

03 Brama logowania: oauth2-proxy + authz.py

Dwa niezależne pytania, dwa mechanizmy, jedna brama przed NGINX:

  1. Uwierzytelnianie — czy to w ogóle Ty, zalogowany kontem @mokate.com.pl? Odpowiada oauth2-proxy (localhost:4180) — loguje do Entra ID i pamięta sesję w ciastku.
  2. Autoryzacja — czy masz dostęp do TEJ konkretnej apki (np. targety, a nie innej)? Odpowiada authz.py (localhost:5098) — sprawdza tabelę SQL src.SerwerDostepyAplikacji (patrz punkt 06).

Przepływ dla chronionej apki (w pełni /targety/, /allegro_api/, /generator_produktow/ oraz /autoprezentacja/):

przeglądarka → NGINX → auth_request /authz/check │ authz.py (:5098) ├─ HTTP → oauth2-proxy /oauth2/auth (:4180) — sesja OK? └─ SQL → src.SerwerDostepyAplikacji — dostęp do tej apki? │ 200 + nagłówki X-* → NGINX → docelowa apka

Jeśli sesja nieprawidłowa → 401 (przekierowanie na logowanie Microsoft). Jeśli sesja OK, ale e-mail nie ma wpisu w tabeli dostępów → 403. Błąd samego SQL (np. brak zmapowanego konta) jest traktowany fail-closed — jak brak dostępu, nie jak błąd 500. Wynik jest cache’owany 60s per (apka, e-mail), żeby nie odpytywać SQL przy każdym żądaniu.

Ryzyko: authz.py jest teraz punktem krytycznym logowania dla wszystkich apek za bramą — jeśli padnie, nikt się nie zaloguje, nawet jeśli sam oauth2-proxy działa. Monitoring (Uptime Kuma) jest jeszcze do wdrożenia.

Wspólne wylogowanie dla całego serwera (łączy wylogowanie z oauth2-proxy z sesją Entra):

https://mokate-dabid-serwer.northeurope.cloudapp.azure.com/logout
04 Nagłówki X-* i JWT — jak je odczytać

Po przejściu bramy, aplikacja dostaje nagłówki, którym może ufać bez własnego logowania:

X-Email — e-mail zalogowanego użytkownika X-User — opaque ID (sub z tokenu, NIE imię i nazwisko) X-Sql-Token — delegowany token dostępowy do Azure SQL X-Name — imię (percent-encoded, wymaga unquote()) X-Surname — nazwisko (percent-encoded, wymaga unquote()) X-UserName — imię i nazwisko (percent-encoded, wymaga unquote())

X-Name/X-Surname/X-UserName są percent-encoded, bo nagłówki HTTP nie dopuszczają polskich znaków diakrytycznych bezpośrednio — odbierająca apka musi zrobić unquote().

Szybkie zdekodowanie payloadu JWT do debugowania (bez weryfikacji podpisu — token już zweryfikował oauth2-proxy):

import base64, json def decode_jwt_claims(token: str) -> dict: payload_b64 = token.split(".")[1] padded = payload_b64 + "=" * (-len(payload_b64) % 4) return json.loads(base64.urlsafe_b64decode(padded))

Podgląd żywych claimów w przeglądarce: /targety/diag/sql-token-claims (dekoduje X-Sql-Token i zwraca jako JSON).

05 Aplikacje bez Entra ID + porty w Azure

Aplikacje bez logowania nie muszą przechodzić przez NGINX — mogą być dostępne bezpośrednio po publicznym IP i porcie (jak Generator zestawów czy Panel harmonogramu). /generator_produktow/ była wcześniej w tej sytuacji (stała za NGINX, ale bez żadnego logowania) — od 14.07.2026 jest już w pełni pod nową bramą, razem z /targety/ i /allegro_api/ (patrz „Stan migracji” wyżej).

Aby port był osiągalny z zewnątrz, trzeba go wystawić w Azure:

  1. Otwórz Ustawienia sieci (przycisk powyżej) → Reguły → Utwórz regułę portu przychodzącego.
  2. Ustaw Docelowy zakres portów na numer portu aplikacji.
  3. Ustaw Źródło na My IP address, aby ograniczyć dostęp do sieci MOKATE.
06 Tabela dostępów src.SerwerDostepyAplikacji

Prosty, płaski słownik dostępu: kto ma prawo wejść do której apki. Baza mkt-sls-p-sqldb2, kolumny id, email, aplikacja.

SELECT * FROM src.SerwerDostepyAplikacji;

Dodanie dostępu dla kogoś:

INSERT INTO src.SerwerDostepyAplikacji (email, aplikacja) VALUES ('ktos@mokate.com.pl', 'targety');

Nazwa aplikacji w tej tabeli to po prostu jej główny route/URL — pierwszy segment ścieżki (np. /targety/…targety), liczony automatycznie przez wspólną mapę /etc/nginx/conf.d/authz_app_map.conf (patrz punkt 07). Tabela jest odpytywana delegowanym tokenem SQL zalogowanego użytkownika, nie kontem serwisowym — więc osoba musi też mieć zmapowane konto AAD w tej bazie (CREATE USER ... FROM EXTERNAL PROVIDER) i GRANT SELECT na tę tabelę, inaczej sprawdzenie kończy się (bezpiecznie) odmową dostępu.

07 Jak dodać nową apkę do bramy
  1. W apps/<nazwa>.conf, w bloku location dodaj:
    include /etc/nginx/strony/snippets/authz-gate.conf; include /etc/nginx/strony/snippets/proxy-common.conf;
    Nazwa apki liczy się automatycznie z jej głównego route/URL (pierwszy segment ścieżki, np. /<nazwa>/<nazwa>) przez wspólną mapę authz_app_from_path (patrz punkt 06) — nic więcej nie trzeba ustawiać. Zadbaj tylko, żeby nazwa apki w SQL (krok 4) była dokładnie tym segmentem.
  2. Jeśli apka miała własne logowanie OIDC — wyłącz je najpierw (inaczej podwójny login). Apka powinna zamiast tego czytać nagłówki z bramy (punkt 04) — nowe apki nie muszą już implementować własnego logowania Entra wcale.
  3. sudo nginx -t && sudo systemctl reload nginx
  4. Dodaj wiersze w src.SerwerDostepyAplikacji dla uprawnionych e-maili (punkt 06).
  5. Test w incognito: brak sesji → redirect na Microsoft; e-mail bez wpisu w SQL → 403; e-mail z wpisem → apka się wczytuje z poprawnymi nagłówkami.
  6. Osobno, opcjonalnie: powyższe daje apce tylko logowanie (X-Email/X-Sql-Token itd.) — jeśli ta apka ma też wołać Microsoft Graph/SharePoint w imieniu użytkownika, to NIE jest częścią tego checklistu, tylko dodatkowy, osobny krok w authz.py — patrz punkt 09.
08 Uruchamianie aplikacji (systemd + tmux)

Wszystkie aplikacje startują automatycznie przez serwis systemd, który odpala jeden skrypt startowy:

/etc/systemd/system/mokate-server.service ~/Documents/programowanie/bash/auto-start.sh

Skrypt tworzy dwie sesje tmux — każdy panel podpisany nazwą aplikacji:

SesjaPanelStart
mokate-serverGenerator-Zestawowpython server.py
mokate-serverkarta_produktow (dotnet)dotnet run
mokate-serverallegro-web (wsgi)python wsgi.py
mokate-serverallegro-bot (api)python api.py
mokate-serverGenerator produktówpython3 app.py
app-targety-phtargety-ph (kalkulator)python3 app.py
app-targety-phapp-authz (nowy)python authz.py

Podłączenie się:

tmux ls tmux attach -t mokate-server tmux attach -t app-targety-ph

Nawigacja między panelami (domyślny prefix Ctrl+b): strzałka — przeskok do panelu; o — cyklicznie następny panel; d — odłącz się (apki dalej działają w tle).

Aktualizacja apki po zmianach w repo (git już autoryzowany na serwerze):

  1. Wejdź na właściwy panel, wciśnij Ctrl+C — zatrzymuje tylko apkę, powłoka panelu zostaje żywa.
  2. git fetch && git pull — jesteś już w odpowiednim katalogu.
  3. Jeśli zmieniły się zależności: pip install -r requirements.txt albo dotnet restore.
  4. Strzałka w górę + Enter — odtwarza zapamiętaną komendę startową panelu.
  5. Ctrl+b + d, żeby się odłączyć i zostawić apkę działającą w tle.

Nie trzeba restartować całego serwera ani systemctl restart mokate-server.service — to tylko odtworzyłoby wszystkie panele od zera. Do zwykłej aktualizacji kodu wystarczą powyższe kroki w jednym panelu.

09 Delegowany dostęp do Microsoft Graph — X-Graph-Token (nowość, 14.07.2026)

Problem: niektóre apki muszą wołać Microsoft Graph (np. pobrać plik z SharePointa) W IMIENIU zalogowanego użytkownika. X-Sql-Token się do tego nie nadaje — jego „aud” to Azure SQL, Graph go odrzuci jako zły odbiorca. Azure AD v2 nie pozwala też zmieszać scope’ów z dwóch różnych zasobów w jednym logowaniu (AADSTS70011).

Wariant rozważony i odrzucony: token APLIKACYJNY Graph (client_credentials + uprawnienie Application „Sites.Read.All” + zgoda administratora). Działałby, ale dawałby appce dostęp do całego SharePointa tenanta, niezależnie od tego, kto jest zalogowany — świadomie zbyt szeroki zakres.

Rozwiązanie: authz.py sam prowadzi DRUGI, całkowicie niezależny od oauth2-proxy login OAuth2 (Authorization Code) do tej samej apki Entra „Logowanie DABiD”, scope’owany wyłącznie do Graph delegowanego (Sites.Read.All — ma już zgodę administratora sprzed migracji pod bramę, żadnej nowej zgody nie trzeba). Nowe endpointy (publiczne, NIE internal jak /authz/check):

GET /authz/graph/connect?return_to=<sciezka> — cichy login (prompt=none) GET /authz/graph/callback — odbiera kod, zapisuje refresh token

Magazyn refresh tokenów — zaszyfrowany (cryptography.Fernet), bo authz.py sam go trzyma (oauth2-proxy swojego nie eksponuje przez żaden nagłówek):

~/Documents/programowanie/autoryzacja/graph_tokens.key ← klucz, chmod 600 ~/Documents/programowanie/autoryzacja/graph_tokens.enc ← zaszyfrowane refresh tokeny, chmod 600

Automatyzacja bez klikania: dla apek wymienionych w stałej APPS_NEEDING_GRAPH w authz.py (dziś allegro_api i autoprezentacja), /check zwraca 403 + nagłówek X-Needs-Graph-Bootstrap: 1, gdy user nie ma jeszcze połączonego Grafa (zamiast zwykłego 200) — nginx na tej podstawie cicho przekierowuje przez /authz/graph/connect i z powrotem. Dzięki prompt=none to 1-2 niewidoczne przeskoki (poniżej sekundy) — user tego nie zauważa. Dla apek spoza listy nic się nie zmienia.

Pułapek nginx, boleśnie znaleziony przy wdrożeniu — kolejność FAZ: if w TEJ SAMEJ lokalizacji co auth_request_set nie działa. if biegnie w fazie rewrite, PRZED fazą access (gdzie żyje auth_request/auth_request_set) — w momencie sprawdzania warunku zmienna jest jeszcze pusta, niezależnie od tego, co zwróci authz.py (potwierdzone empirycznie: add_header w tej samej lokalizacji widziało poprawną wartość, a if na tę samą zmienną i tak nie odpalał 302). Poprawka: przenieść if do NAZWANEJ LOKACJI wywoływanej przez error_page — internal redirect z error_page wykonuje się PO fazie access, więc zmienna ma już wartość (dokładnie ten sam mechanizm co error_page 401 = @oauth2_signin). Konsekwencja: auth_request rozróżnia tylko 2xx/401/403 (inny kod = 500) — więc /check musi zwracać 403 (nie 200+nagłówek) dla „trzeba podłączyć Graf”.

snippets/authz-gate.conf — dopisane obok istniejących linii z punktu 02 (i zamieniony error_page 403):

auth_request_set $auth_graph_token $upstream_http_x_graph_token; auth_request_set $needs_graph_boot $upstream_http_x_needs_graph_bootstrap; error_page 401 = @oauth2_signin; error_page 403 = @graph_or_denied; # zamiast @access_denied proxy_set_header X-Graph-Token $auth_graph_token;

kartka.conf — nowa nazwana lokacja + nowa publiczna lokacja dla connect/callback:

location @graph_or_denied { if ($needs_graph_boot = "1") { return 302 /authz/graph/connect?return_to=$request_uri; } return 403 "Brak dostępu do tej aplikacji. Skontaktuj się z administratorem."; } location /authz/graph/ { proxy_pass http://127.0.0.1:5098/graph/; # UWAGA: http, NIE https proxy_set_header Host $host; # (authz.py to zwykly Flask, bez TLS) proxy_set_header Cookie $http_cookie; }

Jak dodać kolejną apkę do X-Graph-Token:

  1. Dopisz nazwę apki (dokładnie jej główny route/URL — pierwszy segment ścieżki, tak jak liczy go mapa authz_app_from_path, patrz punkt 06/07) do APPS_NEEDING_GRAPH w authz.py, zrestartuj panel app-authz (patrz punkt 08).
  2. Po stronie kodu apki: czytaj nagłówek X-Graph-Token (analogicznie do X-Sql-Token) — nie próbuj samemu zdobywać tokenu Graph (żadnego MSAL/client_credentials/własnego OAuth). Uwaga na zadania w tle (wątki robocze bez kontekstu żądania HTTP) — nagłówek trzeba przechwycić w widoku, PRZED wejściem do wątku, i przekazać jako argument.
  3. nginx i Entra już gotowe (wspólny snippet + wspólna rejestracja Entra) — nic więcej nie trzeba zmieniać po stronie infrastruktury.

Ważne zastrzeżenie znalezione przy wdrożeniu: delegowane Sites.Read.All daje dostęp TYLKO do tego, do czego zalogowany user REALNIE ma dostęp w samym SharePoincie (udostępnianie/ACL) — to nie jest blankietowe uprawnienie jak wersja aplikacyjna. Plik udostępniony tylko konkretnej osobie da 403 accessDenied innemu userowi mimo idealnie poprawnego tokenu/scope/zgody administratora — wygląda jak brak uprawnień w Entra, ale to zupełnie inna przyczyna (SharePoint). Diagnoza: otwórz plik bezpośrednio w SharePoincie (nie przez Graph) jako dany user — SharePoint pokaże czytelny ekran „poproś o dostęp”. Fix: doudostępnij plik „Osobom w organizacji z linkiem” zamiast linku „Określone osoby”.