[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 (function () { 2 'use strict'; 3 4 /** 5 * @package Joomla.Plugin 6 * @subpackage System.webauthn 7 * 8 * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> 9 * @license GNU General Public License version 2 or later; see LICENSE.txt 10 */ 11 window.Joomla = window.Joomla || {}; 12 13 (function (Joomla, document) { 14 /** 15 * Converts a simple object containing query string parameters to a single, escaped query string. 16 * This method is a necessary evil since Joomla.request can only accept data as a string. 17 * 18 * @param object {object} A plain object containing the query parameters to pass 19 * @param prefix {string} Prefix for array-type parameters 20 * 21 * @returns {string} 22 */ 23 var interpolateParameters = function interpolateParameters(object, prefix) { 24 if (prefix === void 0) { 25 prefix = ''; 26 } 27 28 var encodedString = ''; 29 Object.keys(object).forEach(function (prop) { 30 if (typeof object[prop] !== 'object') { 31 if (encodedString.length > 0) { 32 encodedString += '&'; 33 } 34 35 if (prefix === '') { 36 encodedString += encodeURIComponent(prop) + "=" + encodeURIComponent(object[prop]); 37 } else { 38 encodedString += encodeURIComponent(prefix) + "[" + encodeURIComponent(prop) + "]=" + encodeURIComponent(object[prop]); 39 } 40 41 return; 42 } // Objects need special handling 43 44 45 encodedString += "" + interpolateParameters(object[prop], prop); 46 }); 47 return encodedString; 48 }; 49 /** 50 * Finds the first field matching a selector inside a form 51 * 52 * @param {HTMLFormElement} form The FORM element 53 * @param {String} fieldSelector The CSS selector to locate the field 54 * 55 * @returns {Element|null} NULL when no element is found 56 */ 57 58 59 var findField = function findField(form, fieldSelector) { 60 var elInputs = form.querySelectorAll(fieldSelector); 61 62 if (!elInputs.length) { 63 return null; 64 } 65 66 return elInputs[0]; 67 }; 68 /** 69 * Find a form field described by the CSS selector fieldSelector. 70 * The field must be inside a <form> element which is either the 71 * outerElement itself or enclosed by outerElement. 72 * 73 * @param {Element} outerElement The element which is either our form or contains our form. 74 * @param {String} fieldSelector The CSS selector to locate the field 75 * 76 * @returns {null|Element} NULL when no element is found 77 */ 78 79 80 var lookForField = function lookForField(outerElement, fieldSelector) { 81 var elInput = null; 82 83 if (!outerElement) { 84 return elInput; 85 } 86 87 var elElement = outerElement.parentElement; 88 89 if (elElement.nodeName === 'FORM') { 90 elInput = findField(elElement, fieldSelector); 91 return elInput; 92 } 93 94 var elForms = elElement.querySelectorAll('form'); 95 96 if (elForms.length) { 97 for (var i = 0; i < elForms.length; i += 1) { 98 elInput = findField(elForms[i], fieldSelector); 99 100 if (elInput !== null) { 101 return elInput; 102 } 103 } 104 } 105 106 return null; 107 }; 108 /** 109 * A simple error handler. 110 * 111 * @param {String} message 112 */ 113 114 115 var handleLoginError = function handleLoginError(message) { 116 Joomla.renderMessages({ 117 error: [message] 118 }); 119 }; 120 /** 121 * Handles the browser response for the user interaction with the authenticator. Redirects to an 122 * internal page which handles the login server-side. 123 * 124 * @param { Object} publicKey Public key request options, returned from the server 125 */ 126 127 128 var handleLoginChallenge = function handleLoginChallenge(publicKey) { 129 var arrayToBase64String = function arrayToBase64String(a) { 130 return btoa(String.fromCharCode.apply(String, a)); 131 }; 132 133 var base64url2base64 = function base64url2base64(input) { 134 var output = input.replace(/-/g, '+').replace(/_/g, '/'); 135 var pad = output.length % 4; 136 137 if (pad) { 138 if (pad === 1) { 139 throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding'); 140 } 141 142 output += new Array(5 - pad).join('='); 143 } 144 145 return output; 146 }; 147 148 if (!publicKey.challenge) { 149 handleLoginError(Joomla.Text._('PLG_SYSTEM_WEBAUTHN_ERR_INVALID_USERNAME')); 150 return; 151 } 152 153 publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function (c) { 154 return c.charCodeAt(0); 155 }); 156 157 if (publicKey.allowCredentials) { 158 publicKey.allowCredentials = publicKey.allowCredentials.map(function (data) { 159 data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function (c) { 160 return c.charCodeAt(0); 161 }); 162 return data; 163 }); 164 } 165 166 navigator.credentials.get({ 167 publicKey: publicKey 168 }).then(function (data) { 169 var publicKeyCredential = { 170 id: data.id, 171 type: data.type, 172 rawId: arrayToBase64String(new Uint8Array(data.rawId)), 173 response: { 174 authenticatorData: arrayToBase64String(new Uint8Array(data.response.authenticatorData)), 175 clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)), 176 signature: arrayToBase64String(new Uint8Array(data.response.signature)), 177 userHandle: data.response.userHandle ? arrayToBase64String(new Uint8Array(data.response.userHandle)) : null 178 } 179 }; // Send the response to your server 180 181 var paths = Joomla.getOptions('system.paths'); 182 window.location = (paths ? paths.base + "/index.php" : window.location.pathname) + "?" + Joomla.getOptions('csrf.token') + "=1&option=com_ajax&group=system&plugin=webauthn&" + ("format=raw&akaction=login&encoding=redirect&data=" + btoa(JSON.stringify(publicKeyCredential))); 183 }).catch(function (error) { 184 // Example: timeout, interaction refused... 185 handleLoginError(error); 186 }); 187 }; 188 /** 189 * Initialize the passwordless login, going through the server to get the registered certificates 190 * for the user. 191 * 192 * @param {string} formId The login form's or login module's HTML ID 193 * 194 * @returns {boolean} Always FALSE to prevent BUTTON elements from reloading the page. 195 */ 196 // eslint-disable-next-line no-unused-vars 197 198 199 Joomla.plgSystemWebauthnLogin = function (formId) { 200 // Get the username 201 var elFormContainer = document.getElementById(formId); 202 var elUsername = lookForField(elFormContainer, 'input[name=username]'); 203 var elReturn = lookForField(elFormContainer, 'input[name=return]'); 204 205 if (elUsername === null) { 206 Joomla.renderMessages({ 207 error: [Joomla.Text._('PLG_SYSTEM_WEBAUTHN_ERR_CANNOT_FIND_USERNAME')] 208 }); 209 return false; 210 } 211 212 var username = elUsername.value; 213 var returnUrl = elReturn ? elReturn.value : null; // No username? We cannot proceed. We need a username to find the acceptable public keys :( 214 215 if (username === '') { 216 Joomla.renderMessages({ 217 error: [Joomla.Text._('PLG_SYSTEM_WEBAUTHN_ERR_EMPTY_USERNAME')] 218 }); 219 return false; 220 } // Get the Public Key Credential Request Options (challenge and acceptable public keys) 221 222 223 var postBackData = { 224 option: 'com_ajax', 225 group: 'system', 226 plugin: 'webauthn', 227 format: 'raw', 228 akaction: 'challenge', 229 encoding: 'raw', 230 username: username, 231 returnUrl: returnUrl 232 }; 233 postBackData[Joomla.getOptions('csrf.token')] = 1; 234 var paths = Joomla.getOptions('system.paths'); 235 Joomla.request({ 236 url: (paths ? paths.base + "/index.php" : window.location.pathname) + "?" + Joomla.getOptions('csrf.token') + "=1", 237 method: 'POST', 238 data: interpolateParameters(postBackData), 239 onSuccess: function onSuccess(rawResponse) { 240 var jsonData = {}; 241 242 try { 243 jsonData = JSON.parse(rawResponse); 244 } catch (e) { 245 /** 246 * In case of JSON decoding failure fall through; the error will be handled in the login 247 * challenge handler called below. 248 */ 249 } 250 251 handleLoginChallenge(jsonData); 252 }, 253 onError: function onError(xhr) { 254 handleLoginError(xhr.status + " " + xhr.statusText); 255 } 256 }); 257 return false; 258 }; // Initialization. Runs on DOM content loaded since this script is always loaded deferred. 259 260 261 var loginButtons = [].slice.call(document.querySelectorAll('.plg_system_webauthn_login_button')); 262 263 if (loginButtons.length) { 264 loginButtons.forEach(function (button) { 265 button.addEventListener('click', function (_ref) { 266 var currentTarget = _ref.currentTarget; 267 Joomla.plgSystemWebauthnLogin(currentTarget.getAttribute('data-webauthn-form')); 268 }); 269 }); 270 } 271 })(Joomla, document); 272 273 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |