You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2022/10/14 12:25:38 UTC

[myfaces] branch main updated: https://issues.apache.org/jira/browse/MYFACES-4479: nonce handling ported over from 2.3-next branch

This is an automated email from the ASF dual-hosted git repository.

werpu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/main by this push:
     new cf2acb55a https://issues.apache.org/jira/browse/MYFACES-4479: nonce handling ported over from 2.3-next branch
     new c62a8f57b Merge pull request #344 from werpu/main
cf2acb55a is described below

commit cf2acb55aee516c2e7a29516e0c71d66a969b802
Author: Werner Punz <we...@gmail.com>
AuthorDate: Fri Oct 14 14:18:43 2022 +0200

    https://issues.apache.org/jira/browse/MYFACES-4479:
    nonce handling ported over from 2.3-next branch
---
 .../META-INF/resources/myfaces/_impl/_util/_Dom.js | 161 ++++++++++++---------
 .../resources/myfaces/_impl/core/_EvalHandlers.js  |  19 ++-
 .../resources/myfaces/_impl/core/_Runtime.js       |   4 +
 3 files changed, 113 insertions(+), 71 deletions(-)

diff --git a/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js b/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js
index 27c8ba66b..e70f14b2b 100644
--- a/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js
+++ b/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Dom.js
@@ -56,45 +56,54 @@ _MF_SINGLTN(_PFX_UTIL + "_Dom", Object, /** @lends myfaces._impl._util._Dom.prot
     runCss: function(item/*, xmlData*/) {
 
         var  UDEF = "undefined",
-                _RT = this._RT,
-                _Lang = this._Lang,
-                applyStyle = function(item, style) {
-                    var newSS = document.createElement("style");
-
-                    newSS.setAttribute("rel", item.getAttribute("rel") || "stylesheet");
-                    newSS.setAttribute("type", item.getAttribute("type") || "text/css");
-                    if(item.getAttribute("nonce")) {
-                        newSS.setAttribute("nonce", item.getAttribute("nonce"));
+        _T = this;
+        _RT = this._RT,
+            _Lang = this._Lang;
+        var applyStyle = function(item, style) {
+                var newSS = document.createElement("style");
+
+                newSS.setAttribute("rel", item.getAttribute("rel") || "stylesheet");
+                newSS.setAttribute("type", item.getAttribute("type") || "text/css");
+                const nonceValue = _RT.resolveNonce(item);
+                if(nonceValue) {
+                    if('undefined' != typeof newSS.nonce) {
+                        newSS['nonce'] = nonceValue;
+                    } else {
+                        newSS.setAttribute("nonce", nonceValue);
                     }
+                }
 
-                    document.getElementsByTagName("head")[0].appendChild(newSS);
-                    //ie merrily again goes its own way
-                    if (window.attachEvent && !_RT.isOpera && UDEF != typeof newSS.styleSheet && UDEF != newSS.styleSheet.cssText) newSS.styleSheet.cssText = style;
-                    else newSS.appendChild(document.createTextNode(style));
-                },
-
-                execCss = function(item) {
-                    var equalsIgnoreCase = _Lang.equalsIgnoreCase;
-                    var tagName = item.tagName;
-                    if (tagName && equalsIgnoreCase(tagName, "link") && equalsIgnoreCase(item.getAttribute("type"), "text/css")) {
-                        applyStyle(item, "@import url('" + item.getAttribute("href") + "');");
-                    } else if (tagName && equalsIgnoreCase(tagName, "style") && equalsIgnoreCase(item.getAttribute("type"), "text/css")) {
-                        var innerText = [];
-                        //compliant browsers know child nodes
-                        var childNodes = item.childNodes;
-                        if (childNodes) {
-                            var len = childNodes.length;
-                            for (var cnt = 0; cnt < len; cnt++) {
-                                innerText.push(childNodes[cnt].innerHTML || childNodes[cnt].data);
-                            }
-                            //non compliant ones innerHTML
-                        } else if (item.innerHTML) {
-                            innerText.push(item.innerHTML);
-                        }
+                document.getElementsByTagName("head")[0].appendChild(newSS);
+                //ie merrily again goes its own way
+                if (window.attachEvent && !_RT.isOpera && UDEF != typeof newSS.styleSheet && UDEF != newSS.styleSheet.cssText) newSS.styleSheet.cssText = style;
+                else newSS.appendChild(document.createTextNode(style));
+            },
 
-                        applyStyle(item, innerText.join(""));
+            execCss = function(item) {
+                var equalsIgnoreCase = _Lang.equalsIgnoreCase;
+                var tagName = item.tagName;
+                if (tagName && equalsIgnoreCase(tagName, "link") && equalsIgnoreCase(item.getAttribute("type"), "text/css")) {
+                    applyStyle(item, "@import url('" + item.getAttribute("href") + "');");
+                } else if (tagName && equalsIgnoreCase(tagName, "style") && equalsIgnoreCase(item.getAttribute("type"), "text/css")) {
+                    // we do not handle css items blockwise like we do scripts
+                    // but we do have to deal with the child elements instead of the markup
+                    // nonce can be handled on tag level though
+                    var innerText = [];
+                    //compliant browsers know child nodes
+                    var childNodes = item.childNodes;
+                    if (childNodes) {
+                        var len = childNodes.length;
+                        for (var cnt = 0; cnt < len; cnt++) {
+                            innerText.push(childNodes[cnt].innerHTML || childNodes[cnt].data);
+                        }
+                        //non compliant ones innerHTML
+                    } else if (item.innerHTML) {
+                        innerText.push(item.innerHTML);
                     }
-                };
+
+                    applyStyle(item, innerText.join(""));
+                }
+            };
 
         try {
             var scriptElements = this.findByTagNames(item, {"link":1,"style":1}, true);
@@ -121,43 +130,66 @@ _MF_SINGLTN(_PFX_UTIL + "_Dom", Object, /** @lends myfaces._impl._util._Dom.prot
      * @param {Node} item
      */
     runScripts: function(item, xmlData) {
+        var _T = this;
+        var finalScripts = [];
+        var _RT = this._RT;
+
+        var evalCollectedScripts = function (scriptsToProcess) {
+            if (scriptsToProcess && scriptsToProcess.length) {
+                //script source means we have to eval the existing
+                //scripts before running the include
+                var joinedScripts = [];
+                for(var scrptCnt = 0; scrptCnt < scriptsToProcess.length; scrptCnt++) {
+                    var item = scriptsToProcess[scrptCnt];
+                    if (!item.cspMeta) {
+                        joinedScripts.push(item.text)
+                    } else {
+                        if (joinedScripts.length) {
+                            _RT.globalEval(joinedScripts.join("\n"));
+                            joinedScripts.length = 0;
+                        }
+                        _RT.globalEval(item.text, item.cspMeta);
+                    }
+                }
+
+                if (joinedScripts.length) {
+                    _RT.globalEval(joinedScripts.join("\n"));
+                    joinedScripts.length = 0;
+                }
+            }
+            return [];
+        }
+
+
         var _Lang = this._Lang,
-            _RT = this._RT,
-            finalScripts = [],
             execScrpt = function(item) {
                 var tagName = item.tagName;
                 var type = item.type || "";
                 //script type javascript has to be handled by eval, other types
                 //must be handled by the browser
                 if (tagName && _Lang.equalsIgnoreCase(tagName, "script") &&
-                        (type === "" ||
+                    (type === "" ||
                         _Lang.equalsIgnoreCase(type,"text/javascript") ||
                         _Lang.equalsIgnoreCase(type,"javascript") ||
                         _Lang.equalsIgnoreCase(type,"text/ecmascript") ||
                         _Lang.equalsIgnoreCase(type,"ecmascript"))) {
 
-                    var nonce = item.getAttribute("nonce") || null;
+                    //now given that scripts can embed nonce
+                    //we cannoit
+                    var nonce = _RT.resolveNonce(item);
 
                     var src = item.getAttribute('src');
                     if ('undefined' != typeof src
-                            && null != src
-                            && src.length > 0
-                            ) {
+                        && null != src
+                        && src.length > 0
+                    ) {
                         //we have to move this into an inner if because chrome otherwise chokes
                         //due to changing the and order instead of relying on left to right
-                        //if faces.js is already registered we do not replace it anymore
-                        if ((src.indexOf("ln=scripts") == -1 && src.indexOf("ln=jakarta.faces") == -1) || (src.indexOf("/faces.js") == -1
-                                && src.indexOf("/faces-uncompressed.js") == -1)) {
-
-                            if (finalScripts.length) {
-                                //script source means we have to eval the existing
-                                //scripts before running the include
-                                for(var cnt = 0; cnt < finalScripts.length; cnt++) {
-                                    _RT.globalEval(finalScripts[cnt].text, finalScripts[cnt]["cspMeta"] || null);
-                                }
-
-                                finalScripts = [];
-                            }
+                        //if jsf.js is already registered we do not replace it anymore
+                        if ((src.indexOf("ln=scripts") == -1 && src.indexOf("ln=javax.faces") == -1) || (src.indexOf("/jsf.js") == -1
+                            && src.indexOf("/jsf-uncompressed.js") == -1)) {
+
+                            finalScripts = evalCollectedScripts(finalScripts);
                             _RT.loadScriptEval(src, item.getAttribute('type'), false, "UTF-8", false, nonce ? {nonce: nonce} : null );
                         }
 
@@ -188,7 +220,6 @@ _MF_SINGLTN(_PFX_UTIL + "_Dom", Object, /** @lends myfaces._impl._util._Dom.prot
                         }: {
                             text: test
                         });
-
                     }
                 }
             };
@@ -198,11 +229,7 @@ _MF_SINGLTN(_PFX_UTIL + "_Dom", Object, /** @lends myfaces._impl._util._Dom.prot
             for (var cnt = 0; cnt < scriptElements.length; cnt++) {
                 execScrpt(scriptElements[cnt]);
             }
-            if (finalScripts.length) {
-                for(var cnt = 0; cnt < finalScripts.length; cnt++) {
-                    _RT.globalEval(finalScripts[cnt].text, finalScripts[cnt]["cspMeta"] || null);
-                }
-            }
+            evalCollectedScripts(finalScripts);
         } catch (e) {
             //we are now in accordance with the rest of the system of showing errors only in development mode
             //the default error output is alert we always can override it with
@@ -348,9 +375,9 @@ _MF_SINGLTN(_PFX_UTIL + "_Dom", Object, /** @lends myfaces._impl._util._Dom.prot
         if (markup === "") return null;
 
         var evalNodes = this._buildEvalNodes(item, markup),
-                currentRef = item,
-                parentNode = item.parentNode,
-                ret = [];
+            currentRef = item,
+            parentNode = item.parentNode,
+            ret = [];
         for (var cnt = evalNodes.length - 1; cnt >= 0; cnt--) {
             currentRef = parentNode.insertBefore(evalNodes[cnt], currentRef);
             ret.push(currentRef);
@@ -372,9 +399,9 @@ _MF_SINGLTN(_PFX_UTIL + "_Dom", Object, /** @lends myfaces._impl._util._Dom.prot
         if (markup === "") return null;
 
         var evalNodes = this._buildEvalNodes(item, markup),
-                currentRef = item,
-                parentNode = item.parentNode,
-                ret = [];
+            currentRef = item,
+            parentNode = item.parentNode,
+            ret = [];
 
         for (var cnt = 0; cnt < evalNodes.length; cnt++) {
             if (currentRef.nextSibling) {
diff --git a/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_EvalHandlers.js b/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_EvalHandlers.js
index 43f78f4cb..6921f47e8 100644
--- a/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_EvalHandlers.js
+++ b/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_EvalHandlers.js
@@ -94,6 +94,17 @@ if (!myfaces._impl.core._EvalHandlers) {
             document.head.removeChild(htmlScriptElement);
         };
 
+        _T.resolveNonce = function(item) {
+            var nonce = null;
+            if(!!(item && item.nonce)) {
+                nonce = item.nonce;
+            } else if(!!item) {
+                nonce = item.getAttribute("nonce");
+            }
+            //empty nonce means no nonce, the rest
+            //of the code treats it like null
+            return (!nonce) ? null : nonce;
+        }
         /*
         * determines the facesjs nonce and adds them to the namespace
         * this is done once and only lazily
@@ -105,9 +116,9 @@ if (!myfaces._impl.core._EvalHandlers) {
             }
 
             //since our baseline atm is ie11 we cannot use document.currentScript globally
-            if(document.currentScript && document.currentScript.getAttribute("nonce")) {
+            if(_T.resolveNonce(document.currentScript)) {
                 //fastpath for modern browsers
-                return document.currentScript.getAttribute("nonce") || null;
+                return _T.resolveNonce(document.currentScript);
             }
 
             var scripts = document.querySelectorAll("script[src], link[src]");
@@ -116,7 +127,7 @@ if (!myfaces._impl.core._EvalHandlers) {
             //we search all scripts
             for(var cnt = 0; scripts && cnt < scripts.length; cnt++) {
                 var scriptNode = scripts[cnt];
-                if(!scriptNode.getAttribute("nonce")) {
+                if(!_T.resolveNonce(scriptNode)) {
                     continue;
                 }
                 var src = scriptNode.getAttribute("src") || "";
@@ -133,7 +144,7 @@ if (!myfaces._impl.core._EvalHandlers) {
                 nonce: null
             };
             if(faces_js) {
-                myfaces.config.cspMeta.nonce = faces_js.getAttribute("nonce") || null;
+                myfaces.config.cspMeta.nonce = _T.resolveNonce(faces_js);
             }
             return myfaces.config.cspMeta.nonce;
         };
diff --git a/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js b/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js
index 51196b7ef..90ce05d3d 100644
--- a/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js
+++ b/api/src/main/javascript/META-INF/resources/myfaces/_impl/core/_Runtime.js
@@ -77,6 +77,10 @@ if (!myfaces._impl.core._Runtime) {
             return myfaces._impl.core._EvalHandlers.globalEval(code, cspMeta);
         };
 
+        _T.resolveNonce = function(item) {
+            return myfaces._impl.core._EvalHandlers.resolveNonce(item);
+        };
+
         /**
          * applies an object to a namespace
          * basically does what bla.my.name.space = obj does