1 /* Licensed to the Apache Software Foundation (ASF) under one or more
  2  * contributor license agreements.  See the NOTICE file distributed with
  3  * this work for additional information regarding copyright ownership.
  4  * The ASF licenses this file to you under the Apache License, Version 2.0
  5  * (the "License"); you may not use this file except in compliance with
  6  * the License.  You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 /**
 18  * @namespace
 19  * @name window
 20  * @description Eval routines, depending on the browser.
 21  * <p/>
 22  * The problem solved in this class is the problem on how to perform
 23  * a global eval on multiple browsers. Some browsers auto eval themselves
 24  * they do not need to be called
 25  * <li>Some work with a window.eval.call(window,... </li>
 26  * <li>Others use simply execScript <li>
 27  * <li>Some others work only with the head appendix method
 28  * head.appendChild(<script...., head.removeChild(<script </li>
 29  * <p/>
 30  * Note: The code here already is precompressed because the compressor
 31  * fails on it, the deficits in readability will be covered by more comments
 32  *
 33  */
 34 
 35 
 36 if (!window.myfaces) {
 37     /**
 38      * @namespace
 39      * @name myfaces
 40      */
 41     var myfaces = new function() {
 42     };
 43     window.myfaces = myfaces;
 44 }
 45 
 46 /**
 47  * @memberOf myfaces
 48  * @namespace
 49  * @name _impl
 50  */
 51 myfaces._impl = (myfaces._impl) ? myfaces._impl : {};
 52 /**
 53  * @memberOf myfaces._impl
 54  * @namespace
 55  * @name core
 56  */
 57 myfaces._impl.core = (myfaces._impl.core) ? myfaces._impl.core :{};
 58 
 59 if (!myfaces._impl.core._EvalHandlers) {
 60     /**
 61      * @memberOf myfaces._impl.core
 62      * @namespace
 63      * @name _EvalHandlers
 64      */
 65     myfaces._impl.core._EvalHandlers = new function() {
 66         //the rest of the namespaces can be handled by our namespace feature
 67         //helper to avoid unneeded hitches
 68         /**
 69          * @borrows myfaces._impl.core._Runtime as _T
 70          */
 71         var _T = this;
 72 
 73         // note it is safe to remove the cascaded global eval
 74         // the head appendix method is the standard method and has been
 75         // for over a decade even on ie6 (see file history)
 76         /**
 77          * an implementation of eval which drops legacy support
 78          * and allows nonce
 79          * @param code
 80          * @param cspMeta optional csp metadata, only allowed key atm nonce
 81          */
 82         _T.globalEval = function(code, cspMeta) {
 83             //check for jsf nonce
 84             var nonce = cspMeta ? cspMeta.nonce : this._currentScriptNonce();
 85 
 86             var element = document.createElement("script");
 87             element.setAttribute("type", "text/javascript");
 88             element.innerHTML = code;
 89             if(nonce) {
 90                 element.setAttribute("nonce", nonce);
 91             }
 92             //head appendix method, modern browsers use this method savely to eval scripts
 93             //we did not use it up until now because there were really old legacy browsers where
 94             //it did not work
 95             var htmlScriptElement = document.head.appendChild(element);
 96             document.head.removeChild(htmlScriptElement);
 97         };
 98 
 99         _T.resolveNonce = function(item) {
100             var nonce = null;
101             if(!!(item && item.nonce)) {
102                 nonce = item.nonce;
103             } else if(!!item && item.getAttribute) {
104                 nonce = item.getAttribute("nonce");
105             }
106             //empty nonce means no nonce, the rest
107             //of the code treats it like null
108             return (!nonce) ? null : nonce;
109         }
110         /*
111         * determines the jsfjs nonce and adds them to the namespace
112         * this is done once and only lazily
113         */
114         _T._currentScriptNonce = function() {
115             //already processed
116             if(myfaces.config && myfaces.config.cspMeta) {
117                 return myfaces.config.cspMeta.nonce;
118             }
119 
120             //since our baseline atm is ie11 we cannot use document.currentScript globally
121             if(_T.resolveNonce(document.currentScript)) {
122                 // fastpath for modern browsers
123                 return _T.resolveNonce(document.currentScript);
124             }
125 
126             var _Lang = myfaces._impl._util._Lang;
127             var scripts = _Lang.objToArray(document.getElementsByTagName("script"))
128                 .concat(_Lang.objToArray(document.getElementsByTagName("link")));
129 
130             var jsf_js = null;
131 
132             //we search all scripts
133             for(var cnt = 0; scripts && cnt < scripts.length; cnt++) {
134                 var scriptNode = scripts[cnt];
135                 if(!_T.resolveNonce(scriptNode)) {
136                     continue;
137                 }
138                 var src = scriptNode.getAttribute("src") || "";
139                 if(src && !src.match(/jsf\.js\?ln\=javax\.faces/gi)) {
140                     jsf_js = scriptNode;
141                     //the first one is the one we have our code in
142                     //subsequent ones do not overwrite our code
143                     break;
144                 }
145             }
146             //found
147             myfaces.config = myfaces.config || {};
148             myfaces.config.cspMeta = myfaces.config.cspMeta || {
149                 nonce: null
150             };
151             if(jsf_js) {
152                 myfaces.config.cspMeta.nonce = _T.resolveNonce(jsf_js);
153             }
154             return myfaces.config.cspMeta.nonce;
155         };
156 
157     };
158 }