# ========================================== # 대용량 첨부의 공개 화면 /s/<토큰> (11단계 — docs/mail/api-contract.md 4절 "공개 내려받기") # # 공개 내려받기 server 가 넣는다(nginx.conf). 공개 호스트를 따로 두지 않으면 포털 server 도 넣는다(nginx-env.envsh 의 NGINX_PORTAL_SHARE=open). # 템플릿이 아니다 — /etc/nginx/snippets/share-open.conf 로 그대로 들어간다(Dockerfile). ${NGINX_*} 를 쓰지 않는다 — $page_csp 는 nginx.conf 의 http 단계. # 공개 API(/api/public-links/)는 여기가 아니라 /api/ 블록 안의 nginx-share-api-open.conf 다(대소문자를 가리지 않게 — nginx.conf 머리말). # 로그인 · 쿠키를 쓰지 않는 길이다 — 바깥 거래처의 브라우저 · 내려받기 관리자 · 받는 쪽 보안 장비가 부른다. # ========================================== # 화면 /s/<토큰> — SPA 의 공개 라우트(셸 · 로그인 없음 — 세션 복원을 건너뛴다). 파일은 토큰과 상관없이 index.html 하나다. # server 단계의 보안 헤더를 물려받지 않고 여기서 다 쓴다 — 포털 server 에 들어갈 때(같은 호스트) 포털의 Referrer-Policy(strict-origin)와 # 두 줄이 되지 않게. 포털 화면과 다른 것: Referer 를 아예 보내지 않는다(주소에 토큰이 있다 — 화면에서 나가는 요청 · 내려받기 이동에 실리지 않게), # 검색 엔진에 올리지 않는다. index.html 이라 매번 재검증한다(배포 뒤 지워진 해시 자산을 부르지 않게 — 포털의 /index.html 과 같은 까닭) # 대소문자를 가린다 — 화면 라우터도 /s/ 만 공개 화면으로 그린다(routes.ts 의 sensitive). /S/… 는 공개 내려받기 server 에서는 404, # 포털에서는 SPA 의 다른 화면이다(공개 화면이 그려지지 않는다) location ^~ /s/ { root /usr/share/nginx/html; try_files /index.html =404; add_header_inherit off; add_header Cache-Control "no-cache" always; add_header Referrer-Policy "no-referrer" always; add_header X-Robots-Tag "noindex, nofollow" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; add_header Content-Security-Policy $page_csp always; }