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 
 74         /**
 75          * an implementation of eval which drops legacy support
 76          * and allows nonce
 77          * @param code
 78          * @param cspMeta optional csp metadata, only allowed key atm nonce
 79          */
 80         _T.globalEval = function(code, cspMeta) {
 81             //check for jsf nonce
 82             var nonce = cspMeta ? cspMeta.nonce : this._currentScriptNonce();
 83 
 84             var element = document.createElement("script");
 85             element.setAttribute("type", "text/javascript");
 86             element.innerHTML = code;
 87             if(nonce) {
 88                 element.setAttribute("nonce", nonce);
 89             }
 90             //head appendix method, modern browsers use this method savely to eval scripts
 91             //we did not use it up until now because there were really old legacy browsers where
 92             //it did not work
 93             var htmlScriptElement = document.head.appendChild(element);
 94             document.head.removeChild(htmlScriptElement);
 95         };
 96 
 97         /*
 98         * determines the jsfjs nonce and adds them to the namespace
 99         * this is done once and only lazily
100         */
101         _T._currentScriptNonce = function() {
102             //already processed
103             if(myfaces.config && myfaces.config.cspMeta) {
104                 return myfaces.config.cspMeta.nonce;
105             }
106 
107             //since our baseline atm is ie11 we cannot use document.currentScript globally
108             if(document.currentScript && document.currentScript.getAttribute("nonce")) {
109                 //fastpath for modern browsers
110                 return document.currentScript.getAttribute("nonce") || null;
111             }
112 
113             var scripts = document.querySelectorAll("script[src], link[src]");
114             var jsf_js = null;
115 
116             //we search all scripts
117             for(var cnt = 0; scripts && cnt < scripts.length; cnt++) {
118                 var scriptNode = scripts[cnt];
119                 if(!scriptNode.getAttribute("nonce")) {
120                     continue;
121                 }
122                 var src = scriptNode.getAttribute("src") || "";
123                 if(src && !src.match(/jsf\.js\?ln\=javax\.faces/gi)) {
124                     jsf_js = scriptNode;
125                     //the first one is the one we have our code in
126                     //subsequent ones do not overwrite our code
127                     break;
128                 }
129             }
130             //found
131             myfaces.config = myfaces.config || {};
132             myfaces.config.cspMeta = myfaces.config.cspMeta || {
133                 nonce: null
134             };
135             if(jsf_js) {
136                 myfaces.config.cspMeta.nonce = jsf_js.getAttribute("nonce") || null;
137             }
138             return myfaces.config.cspMeta.nonce;
139         };
140 
141     };
142 }