[ 
https://issues.apache.org/jira/browse/WW-5772?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Lukasz Lenart updated WW-5772:
------------------------------
    Fix Version/s: 7.5.0

> Remove framework-generated inline event handlers from transfer-select, 
> updownselect and combobox tags (CSP)
> -----------------------------------------------------------------------------------------------------------
>
>                 Key: WW-5772
>                 URL: https://issues.apache.org/jira/browse/WW-5772
>             Project: Struts 2
>          Issue Type: Improvement
>          Components: Core Tags
>            Reporter: Aaron Elijah Mars
>            Priority: Minor
>             Fix For: 7.5.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> h3. Problem
> The {{optiontransferselect}}, {{inputtransferselect}} and {{updownselect}} 
> tags render every button with an {{onclick}} handler that the framework 
> builds itself. The {{combobox}} tag renders its select with an inline 
> {{onChange}}. An application that wants a nonce-based Content-Security-Policy 
> without {{'unsafe-inline'}} therefore cannot use these tags, even though 
> {{<s:script>}} already applies the nonce to the scripts the same templates 
> emit.
> The generated {{onclick}} code also contains the 
> {{headerKey}}/{{doubleHeaderKey}} values as JavaScript string literals that 
> are only HTML-escaped. The browser decodes {{&#39;}} back to {{'}} before it 
> runs the handler, so a header key that contains a quote breaks the handler.
> h3. Approach
> - *Transfer selects and updownselect.* Each button now carries its action, 
> the target select id(s) and the header key(s) in {{data-struts-*}} 
> attributes, which FreeMarker HTML-escapes. {{optiontransferselect.js}} (also 
> used by updownselect) and {{inputtransferselect.js}} each register one 
> delegated click listener per page, in the capture phase, guarded against 
> double registration. The listener calls the same existing functions with the 
> same arguments as the old inline handlers, header-key/no-header-key branches 
> included. {{optiontransferselect.ftl}} folds its duplicated per-button 
> branches into one {{transferButton}} macro, about 100 lines shorter. A 
> developer-supplied {{*Onclick}} attribute is still rendered as {{onclick}} 
> and still runs after the framework action.
> - *Combobox (simple and html5).* The select carries 
> {{data-struts-combobox="<escapedId>"}}. The {{change}} listener is attached 
> from an {{<@s.script>}} block, which carries the nonce like the 
> {{autoPopulate_<id>}} function the template already emits. The script binds 
> every select with that marker that is not bound yet. Repeated comboboxes with 
> the same id (e.g. inside an iterator) therefore each get exactly one handler, 
> and fragments loaded over AJAX work too: jQuery {{.html()}} evaluates scripts 
> through a temporary element in {{<head>}}, so {{document.currentScript}} 
> cannot be used.
> - The old global JS functions are unchanged, so custom themes that copied the 
> old templates keep working.
> h3. Why it is systematic
> Each of these tags had the same pattern: framework-built JavaScript in 
> event-handler attributes. The patch removes that pattern from them entirely 
> rather than escaping individual values, so neither the CSP blocker nor the 
> quoting problem can come back through these templates.
> h3. Upgrade note (please add to the release notes / migration guide)
> The new markup needs the new {{optiontransferselect.js}} and 
> {{inputtransferselect.js}}.
> - An application that serves its own copy of the static files 
> ({{struts.serve.static=false}} or a custom {{struts.ui.staticContentPath}}) 
> must update those two files together with the templates. Otherwise the 
> transfer buttons silently do nothing.
> - The static URL is not versioned and browsers cache it for one day, so a 
> browser holding the old copy right after an upgrade sees inactive buttons 
> until the cache expires.
> - Code that calls {{button.onclick()}} directly no longer triggers the 
> framework action. Real clicks and {{element.click()}} still do.
> h3. Follow-ups (separate tickets; this PR does not make the themes fully 
> CSP-clean)
> - xhtml/css_xhtml {{form.ftl}}: default {{onreset="clearErrorMessages..."}} 
> and the {{onsubmit="return validateForm_..."}} for client-side validation
> - xhtml {{tooltip.ftl}}: {{domTT_activate}} {{onmouseover}} when 
> {{javascriptTooltip}} is on
> - {{doubleselect}}: the {{onchange="<id>Redirect(...)"}} built in 
> {{DoubleSelect.java}}
> This change was prepared with AI assistance and reviewed and tested by me.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to