feat(gdpr): configurable privacy banner (PR4 of #6701)#7549
feat(gdpr): configurable privacy banner (PR4 of #6701)#7549JohnMcLear wants to merge 10 commits intodevelopfrom
Conversation
Review Summary by QodoAdd configurable GDPR privacy banner with dismissible/sticky modes
WalkthroughsDescription• Add configurable privacy banner to settings.json with title, body, learn-more link, and dismissal mode • Wire banner config through clientVars to browser for rendering on pad load • Implement client-side banner rendering with XSS-safe textContent and per-origin localStorage persistence • Add Playwright tests covering disabled-by-default, sticky, and dismissible modes with localStorage verification • Include comprehensive documentation and styling for the colibris skin Diagramflowchart LR
Settings["Settings.ts<br/>privacyBanner block"] -- "getPublicSettings()" --> ClientVars["ClientVars<br/>privacyBanner payload"]
ClientVars -- "sent to browser" --> PadHTML["pad.html<br/>hidden banner DOM"]
PadHTML -- "populated by" --> PrivacyBanner["privacy_banner.ts<br/>showPrivacyBannerIfEnabled"]
PrivacyBanner -- "textContent + localStorage" --> Rendered["Rendered banner<br/>dismissible or sticky"]
File Changes1. src/node/utils/Settings.ts
|
Code Review by Qodo
1.
|
Qodo review: showPrivacyBannerIfEnabled assigned config.learnMoreUrl directly to <a href>, so a misconfigured settings.privacyBanner. learnMoreUrl of `javascript:alert(1)` or `data:…<script>…` would run script on click. Validate via URL parsing and allow only http(s) / mailto; everything else yields no link. Playwright regression guards the four cases (javascript, data, https, mailto). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ac03929 to
006618b
Compare
SamTV12345
left a comment
There was a problem hiding this comment.
Besides the important flag nothing strikes my eyes. Great job :)
|
|
||
| /* GDPR privacy banner (PR4) */ | ||
| .privacy-banner[hidden] { | ||
| display: none !important; |
There was a problem hiding this comment.
Do we really need important here? Maybe a more specific rule can fix this?
Summary
privacyBannerblock insettings.json(enabled / title / body / learnMoreUrl / dismissal). Defaults to disabled so existing instances are unchanged.clientVars.privacyBanner; client renders it withtextContent(HTML is escaped).dismissiblestores a per-origin flag inlocalStorageso the user sees the notice once;stickyshows it every load.Part of the GDPR work in #6701. PR1 #7546, PR2 #7547, PR3 #7548 already in flight. PR5 (author erasure) is the last.
Design:
docs/superpowers/specs/2026-04-19-gdpr-pr4-privacy-banner-design.mdPlan:
docs/superpowers/plans/2026-04-19-gdpr-pr4-privacy-banner.mdTest plan
pnpm --filter ep_etherpad-lite run ts-check