-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
refactor: Replace inline-scripts and onclick handlers for better CSP conformance #8246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Reviewer's GuideThis PR refactors widget initialization and event handlers to conform with CSP by replacing inline scripts and onclick attributes with JSON data injections and delegated JavaScript parsing and binding. Sequence Diagram: Widget Data Initialization via JSONsequenceDiagram
participant PythonBackend as Python Backend (Widget)
participant TemplateEngine as Django Template Engine
participant BrowserHTMLDoc as Browser (HTML Document)
participant WidgetJS as Browser (Widget JavaScript)
PythonBackend->>PythonBackend: get_context() called
alt PageSmartLinkWidget / ApplicationConfigSelect
PythonBackend->>PythonBackend: Calls _build_script_data()
PythonBackend-->>PythonBackend: Returns JSON data string
else PageSelectWidget
PythonBackend->>PythonBackend: Prepares JSON for widget 'name'
end
PythonBackend-->>TemplateEngine: Context with 'script_data' (JSON string)
TemplateEngine->>TemplateEngine: Renders template
TemplateEngine->>BrowserHTMLDoc: Embeds JSON in <script type="application/json" data-cms-widget-XYZ>
BrowserHTMLDoc->>WidgetJS: HTML Document loaded
WidgetJS->>BrowserHTMLDoc: JS queries for <script data-cms-widget-XYZ>
BrowserHTMLDoc-->>WidgetJS: Returns script element
WidgetJS->>WidgetJS: Parses JSON from script.textContent
WidgetJS->>WidgetJS: Initializes widget with parsed data
Sequence Diagram: Migrating Inline 'onclick' to JavaScript Event ListenerssequenceDiagram
actor User
participant Element as Browser (HTML Element e.g., Button, Link)
participant JSModule as Browser (Relevant JS Module)
participant TargetFunction as JavaScript Function (e.g., CMS.API.changeLanguage, window.showAddAnotherPopup)
JSModule->>Element: Attaches 'click' event listener during initialization
User->>Element: Clicks element
Element->>JSModule: Executes 'click' event handler
opt Element has data attributes
JSModule->>Element: Reads data (e.g., from dataset)
end
JSModule->>TargetFunction: Calls target function (with data if any)
Updated Class Diagram: Python Widget ClassesclassDiagram
class PageSelectWidget {
+get_context(name, value, attrs)
%% _build_script() method removed
%% get_context() now populates widget.script_data with JSON
}
class PageSmartLinkWidget {
+get_context(name, value, attrs)
+_build_script_data(name, value, attrs)
%% _build_script() method removed
%% _build_script_data() method added
%% get_context() now calls _build_script_data()
}
class ApplicationConfigSelect {
+get_context(name, value, attrs)
+_build_script_data(name, value, attrs)
%% _build_script() method removed
%% _build_script_data() method added
%% get_context() now calls _build_script_data()
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @stefanw - I've reviewed your changes and found some issues that need to be addressed.
Blocking issues:
- Config model instances are not JSON serializable (link)
General comments:
- In cms/static/js/modules/cms.changeform.js the selector
'#page_form_lang_tabs button .language_button'
won’t match the<input class="language_button" />
elements—update it to something like'#page_form_lang_tabs input.language_button'
so the click handler actually binds. - When you embed data via
json.dumps
into<script type="application/json">
, make sure all string values (e.g. placeholder_text, config names) are properly escaped or consider using Django’s built-injson_script
tag to prevent potential XSS. - You renamed the link class from
add-another
toaddlink
—verify that any CSS rules or JS code referencingadd-another
have been updated so the styles and behaviors don’t break.
Here's what I looked at during the review
- 🔴 General issues: 1 blocking issue, 2 other issues
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
5c3549e
to
fb0534c
Compare
Replaced with JSON data scripts and data attributes to be conformant with Content Security Policy best practices.
fb0534c
to
0243d93
Compare
@stefanw Nice work, thank you! Did you test the widgets? |
@fsbraun that class name change is something that seems questionable - is that likely to break things for people is my current thought. Though I've only had a quick glance over this. |
I believe that somewhere between Django 3.2 and 4.2, the |
@marksweb I can add the @fsbraun I tested all widgets apart from the app hook config where I don't have a good sample setup. |
@stefanw ah ok, that makes sense then! Thank you for explaining. I think it's fine to leave as it is in that case. 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stefanw Thanks for fixing this! Looks nice!
Replaced with JSON data scripts and data attributes to be conformant with Content Security Policy best practices. Co-authored-by: Fabian Braun <fsbraun@gmx.de>
Description
This PR replaces more inline-scripts with passing data via JSON to be conformant with Content Security Policy (CSP) best practices (no
script-src: unsafe-inline
necessary).Checklist
main
Summary by Sourcery
Improve CSP compliance by replacing inline scripts and onclick attributes in widget templates with JSON-based data injection and moving event handlers into external JavaScript modules.
Enhancements: