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 faces 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         _T.resolveNonce = function(item) {
 98             var nonce = null;
 99             if(!!(item && item.nonce)) {
100                 nonce = item.nonce;
101             } else if(!!item && item.getAttribute) {
102                 nonce = item.getAttribute("nonce");
103             }
104             //empty nonce means no nonce, the rest
105             //of the code treats it like null
106             return (!nonce) ? null : nonce;
107         }
108         /*
109         * determines the facesjs nonce and adds them to the namespace
110         * this is done once and only lazily
111         */
112         _T._currentScriptNonce = function() {
113             //already processed
114             if(myfaces.config && myfaces.config.cspMeta) {
115                 return myfaces.config.cspMeta.nonce;
116             }
117 
118             //since our baseline atm is ie11 we cannot use document.currentScript globally
119             if(_T.resolveNonce(document.currentScript)) {
120                 //fastpath for modern browsers
121                 return _T.resolveNonce(document.currentScript);
122             }
123 
124             var scripts = document.querySelectorAll("script[src], link[src]");
125             var faces_js = null;
126 
127             //we search all scripts
128             for(var cnt = 0; scripts && cnt < scripts.length; cnt++) {
129                 var scriptNode = scripts[cnt];
130                 if(!_T.resolveNonce(scriptNode)) {
131                     continue;
132                 }
133                 var src = scriptNode.getAttribute("src") || "";
134                 if(src && !src.match(/faces\.js\?ln\=jakarta\.faces/gi)) {
135                     faces_js = scriptNode;
136                     //the first one is the one we have our code in
137                     //subsequent ones do not overwrite our code
138                     break;
139                 }
140             }
141             //found
142             myfaces.config = myfaces.config || {};
143             myfaces.config.cspMeta = myfaces.config.cspMeta || {
144                 nonce: null
145             };
146             if(faces_js) {
147                 myfaces.config.cspMeta.nonce = _T.resolveNonce(faces_js);
148             }
149             return myfaces.config.cspMeta.nonce;
150         };
151 
152     };
153 }