1/** 2 * Provide CSRF protection support. 3 */ 4 var csrfProtection = csrfProtection || (function () { // Prevents loading this definition more than once 5 /** 6 * Returns an anti-CSRF token, which is a SHA-256 hash of the value of the X-CSRF-Token cookie and a nonce, 7 * postfixed with the used nonce. 8 * 9 * @return An anti-CSRF token. 10 */ 11 function getCsrfToken() { 12 const cookies = document.cookie.match("X-CSRF-Token=([^;]*)"); 13 var token = (cookies != null ? cookies[1] : ''); 14 if (token !== '') { 15 const nonce = Date.now().toString(36).substring(2) + Math.random().toString(36).substring(2, 12).padEnd(10, '0'); 16 token = _sha256(token + nonce) + nonce; 17 } 18 return token; 19 } 20 21 /** 22 * Fills all 'csrftoken' inputs with the value of the X-CSRF-Token cookie when their value is empty. 23 * 24 * @param selector a custom document selector to select the inputs to fill. 25 */ 26 function setCsrfTokenInputs(selector = "input[name='csrftoken']") { 27 document.querySelectorAll(selector).forEach((input) => { 28 _setCsrfToken(input); 29 }); 30 } 31 32 /** 33 * Helper function for addCsrfTokenInputs. 34 * Adds a csrf token input to a single form object. 35 * @param {*} form Form element 36 */ 37 function _addCsrfTokenInput(form) { 38 if (form instanceof HTMLElement) { 39 const csrfTokenInput = form.querySelector("input[name='csrftoken']"); 40 if (csrfTokenInput) { 41 _setCsrfToken(csrfTokenInput); 42 } else { 43 const input = document.createElement("input"); 44 input.type = "hidden"; 45 input.name = "csrftoken"; 46 input.value = getCsrfToken(); 47 form.appendChild(input); 48 } 49 } 50 } 51 52 /** 53 * Adds a 'csrftoken' input to forms with a POST action and fills them with the value of the X-CSRF-Token 54 * cookie. When a form already has a 'csrftoken' input, no new one is created and it is only filled. 55 * 56 * When `selector` is empty, a 'csrftoken' input is added to all forms with a POST action. 57 * 58 * @param selector a custom selector to select the relevant form. 59 */ 60 function addCsrfTokenInputs(selectorOrForm = "form[method='post']") { 61 if (typeof selectorOrForm === "string") { 62 document.querySelectorAll(selectorOrForm).forEach((form) => { 63 _addCsrfTokenInput(form); 64 }); 65 } else if (selectorOrForm instanceof HTMLElement) { 66 _addCsrfTokenInput(selectorOrForm); 67 } 68 } 69 70 /** 71 * Adds a 'csrftoken' input to a form and fills it with the token argument, or with the value of the 72 * X-CSRF-Token cookie when the token argument is absent. 73 * When the form already has a 'csrftoken' input, no new one is created and it is only filled. 74 * 75 * @param form The form to which to add the 'csrftoken' input. 76 * @param token The token value (optional). 77 */ 78 function addCsrfToken(form, token) { 79 var csrfTokenInput = form.csrftoken; 80 if (csrfTokenInput) { 81 _setCsrfToken(csrfTokenInput, token); 82 } else { 83 var input = document.createElement("input"); 84 input.type = "hidden"; 85 input.name = "csrftoken"; 86 input.value = token ? token : getCsrfToken(); 87 form.appendChild(input); 88 } 89 } 90 91 /** 92 * Fills an input with the CSRF token when it does not have a value. The CSRF token is taken from 93 * the token argument when it is not empty, or otherwise from the X-CSRF-Token cookie. 94 * 95 * @param input The input. 96 * @param token The token value (optional). 97 */ 98 function _setCsrfToken(input, token) { 99 if (input.value === "") { 100 input.value = token ? token : getCsrfToken(); 101 } 102 } 103 104 /** 105 * Calculates the SHA-256 hash of an ASCII string. 106 * This implementation has been provided instead of using the browser native crypto.subtle.digest 107 * function, because the latter is only available in secure contexts and its presence can therefore 108 * not be guaranteed. 109 */ 110 function _sha256(text) { 111 function rightRotate(value, amount) { 112 return (value>>>amount) | (value<<(32 - amount)); 113 } 114 115 var maxWord = Math.pow(2, 32); 116 var result = '' 117 var words = []; 118 var textBitLength = text['length']*8; 119 var hash = []; 120 var k = []; 121 var primeCounter = 0; 122 var i, j; 123 124 var isComposite = {}; 125 for (var candidate = 2; primeCounter < 64;
125 candidate++) { 126 if (!isComposite[candidate]) { 127 for (i = 0; i < 313; i += candidate) { 128 isComposite[i] = candidate; 129 } 130 hash[primeCounter] = (Math.pow(candidate, 0.5)*maxWord) | 0; 131 k[primeCounter++] = (Math.pow(candidate, 1/3)*maxWord) | 0; 132 } 133 } 134 135 text += '\x80' 136 while (text['length']%64 - 56){ 137 text += '\x00' 138 } 139 140 for (i = 0; i < text['length']; i++) { 141 j = text.charCodeAt(i); 142 if (j>>8) { 143 return; // ASCII check: only accept characters in range 0-255 144 } 145 words[i>>2] |= j << ((3 - i)%4)*8; 146 } 147 words[words['length']] = ((textBitLength/maxWord)|0); 148 words[words['length']] = (textBitLength) 149 150 for (j = 0; j < words['length'];) { 151 var w = words.slice(j, j += 16); 152 var oldHash = hash; 153 hash = hash.slice(0, 8); 154 155 for (i = 0; i < 64; i++) { 156 var w15 = w[i - 15], w2 = w[i - 2]; 157 var a = hash[0], e = hash[4]; 158 var temp1 = hash[7] 159 + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) 160 + ((e&hash[5])^((~e)&hash[6])) // ch 161 + k[i] 162 + (w[i] = (i < 16) ? w[i] : ( 163 w[i - 16] 164 + (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) 165 + w[i - 7] 166 + (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) 167 ) | 0 168 ); 169 var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) 170 + ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj 171 172 hash = [(temp1 + temp2)|0].concat(hash); 173 hash[4] = (hash[4] + temp1)|0; 174 } 175 176 for (i = 0; i < 8; i++) { 177 hash[i] = (hash[i] + oldHash[i])|0; 178 } 179 } 180 181 for (i = 0; i < 8; i++) { 182 for (j = 3; j + 1; j--) { 183 var b = (hash[i]>>(j*8))&255; 184 result += ((b < 16) ? 0 : '') + b.toString(16); 185 } 186 } 187 return result; 188 } 189 190 // If the addOnLoad attribute has been added to the script tag for this file 191 // then call the addCsrfTokenInputs function automatically when the page has loaded. 192 // This is done either by registering the addCsrfTokenInputs function with the addOnLoadListener 193 // function when it is present (it is defined in the global_edit-javascript_util template) and we 194 // are not in an iframe, or by registering it with the DOMContentLoaded event handler. 195 if (document.currentScript.getAttribute("addonload") === "true") { 196 if (typeof addOnLoadListener === "function" && window.location === window.parent.location) { 197 addOnLoadListener(addCsrfTokenInputs); 198 } else { 199 document.addEventListener("DOMContentLoaded", function() { 200 addCsrfTokenInputs(); 201 }); 202 } 203 } 204 205 // Public methods 206 return { 207 getCsrfToken: getCsrfToken, 208 setCsrfTokenInputs: setCsrfTokenInputs, 209 addCsrfTokenInputs: addCsrfTokenInputs, 210 addCsrfToken: addCsrfToken 211 } 212})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.