1/* ------------------------------ 2 CSRF SECURITY UTILITY 3 Management of CSRF tokens. 4-------------------------------*/ 5 6/** 7 * Update the CSRF header and retrieves existing page cookie (for Ajax/Ajax Form) 8 * 9 * Note: Weakness - this uses the existing token on the page and will not generate a new one. 10 * Multiple Ajax calls on this page will use the same token. 11 * 12 * @param {object} xhr - XML HTTP Request 13 */ 14function updateAjaxCSRF(xhr) { 15 var token = Cookies.get('csrf_token'); 16 updateCSRFHeader(xhr, token); 17} 18 19/** 20 * Update the CSRF header AND cookie (for Ajax/Ajax Form) 21 * 22 * @param {object} xhr - XML HTTP Request 23 */ 24function updateAjaxCSRFWithNewValue(xhr) { 25 var random = generateRandomString(8); 26 updateCSRFCookie(random); 27 updateCSRFHeader(xhr, random); 28} 29 30/** 31 * Update the CSRF header AND cookie (for image uploader) 32 * 33 * @param {object} uploader - The Plupload uploader object 34 */ 35function updateAjaxCSRFInUploader(uploader) { 36 var random = generateRandomString(8); 37 updateCSRFCookie(random); 38 uploader.settings.headers = { 'X-CSRF-Token' : random } 39} 40 41/** 42 * Generates a random token and updates the CSRF header 43 */ 44function getAjaxCSRFToken() { 45 var random = generateRandomString(8); 46 updateCSRFCookie(random); 47 return random; 48} 49 50/** 51 * Update the CSRF header 52 * 53 * @param {object} xhr - XML HTTP Request 54 * @param {string} token - New token 55 */ 56function updateCSRFHeader(xhr, token) { 57 xhr.setRequestHeader('X-CSRF-Token', token); 58} 59 60/** 61 * Update the CSRF cookie 62 * 63 * @param {string} token - New token 64 */ 65function updateCSRFCookie(token) { 66 Cookies.set('csrf_token', token, { path: '/' }); 67} 68 69/** 70 * Generate a new CSRF token 71 * 72 * @param {number} char - Number of characters 73 * @return {string} Random token string 74 */ 75function generateRandomString(char) { 76 char = parseInt(char); 77 var text = ""; 78 var alphaText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 79 for( var i=0; i < char; i++ ) { 80 text += alphaText.charAt(Math.floor(Math.random() * alphaText.length)); 81 } 82 return text; 83} 84 85/** 86 * Activate CSRF for forms with generic implementations 87 * (i.e. no specific JS handling) 88 * 89 * Usage: 90 * Add the "activateFormCSRF" class to <form> objects to enable CSRF for these forms. 91 * 92 * @example 93 * <form action="..." class="activateFormCSRF"> 94 */ 95function activateGenericFormCSRF() { 96 if ($('.activateFormCSRF').length > 0) { 97 $('.activateFormCSRF').unbind(); 98 $('.activateFormCSRF').submit(function() { 99 retrieveLatestCSRFTokenForForm(this); 100 }); 101 } 102} 103 104/** 105 * Retrieve latest CSRF Token and update a hidden DIV in the form 106 * (Implementation in standard form submits) 107 * 108 * Usage: 109 * Add an empty DIV with the id "csrfTokenValue" within the <form></form> body. 110 * 111 * @example 112 * <div id="csrfTokenValue"><%-- POPULATED BY AJAX --%></div> 113 */ 114 115/** 116 * If page has only a single form 117 */ 118function retrieveLatestCSRFToken() { 119 retrieveLatestCSRFTokenForForm('form'); 120} 121 122/** 123 * If page has multiple forms 124 * 125 * @param {object} formwrapper - The form DOM 126 */ 127function retrieveLatestCSRFTokenForForm(formWrapper) { 128 $.ajax({ 129 url: web_root_path + "/csrftokenvalue", 130 type: 'GET', 131 beforeSend: function(xhr) { updateAjaxCSRFWithNewValue(xhr) }, 132 async: false, 133 cache: false, 134 dataType: 'text', 135 contentType: "text/plain", 136 success: function(data){ 137 $(formWrapper).find('#csrfTokenValue').html(data); 138 } 139 }); 140} 141 142/** 143 * Activate CSRF for links. 144 * 145 * Note: Backend action must return type JSON, with the link to redirect 146 * the user to after SUCCESS to be defined in `redirectUrl`. 147 */ 148function activateLinkCSRF() { 149 if ($('.activateLinkCSRF').length > 0) { 150 $('.activateLinkCSRF').click(function() { 151 var actionUrl = $(this).attr('href'); 152 153 $.ajax({ 154 type: "POST", 155 beforeSend: function(xhr) { updateAjaxCSRFWithNewValue(xhr) }, 156 url: actionUrl, 157 success: function(data) { 158 if (checkAndShowAjaxError(data)) { 159 return false; 160 } else { 161 // To go SUCCESS path 162 window.location.href = web_root_path + data.redirectUrl; 163 } 164 }, error: function() { showFeedbackPopup(text_oops, text_error) } 165 }); 166 167 return false;
168 }) 169 } 170}
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.