From fae40c06e513146efdf859a578e914ec6183a281 Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Mon, 15 Apr 2024 19:01:59 +0100 Subject: [PATCH] MDL-81285 factor_webauthn: inform user on failed key registration. --- admin/tool/mfa/factor/webauthn/amd/build/register.min.js | 2 +- .../tool/mfa/factor/webauthn/amd/build/register.min.js.map | 2 +- admin/tool/mfa/factor/webauthn/amd/src/register.js | 6 +++--- admin/tool/mfa/factor/webauthn/lang/en/factor_webauthn.php | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/admin/tool/mfa/factor/webauthn/amd/build/register.min.js b/admin/tool/mfa/factor/webauthn/amd/build/register.min.js index a1dd0d602be78..50be72de86e19 100644 --- a/admin/tool/mfa/factor/webauthn/amd/build/register.min.js +++ b/admin/tool/mfa/factor/webauthn/amd/build/register.min.js @@ -6,6 +6,6 @@ * @author Alex Morris * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("factor_webauthn/register",["factor_webauthn/utils","core/log","core/prefetch","core/str","core/toast"],(function(utils,Log,Prefetch,Str,Toast){async function registerSecurityKey(createArgs){try{if(!navigator.credentials||!navigator.credentials.create)throw new Error("Browser not supported.");if(!1===createArgs.success)throw new Error(createArgs.msg||"unknown error occurred");utils.recursiveBase64StrToArrayBuffer(createArgs);const cred=await navigator.credentials.create(createArgs),authenticatorResponse={transports:cred.response.getTransports?cred.response.getTransports():null,clientDataJSON:cred.response.clientDataJSON?utils.arrayBufferToBase64(cred.response.clientDataJSON):null,attestationObject:cred.response.attestationObject?utils.arrayBufferToBase64(cred.response.attestationObject):null},registerSuccess=await Str.getString("registersuccess","factor_webauthn");await Toast.add(registerSuccess,{type:"success"}),document.getElementById("id_response_input").value=JSON.stringify(authenticatorResponse),document.getElementById("id_submitbutton").disabled=!1}catch(e){Log.debug("The request timed out or you have canceled the request. Please try again later.")}}return{init:function(createArgs){document.getElementById("id_submitbutton").disabled=!0,Prefetch.prefetchStrings("factor_webauthn",["registersuccess"]),createArgs=JSON.parse(createArgs),document.getElementById("factor_webauthn-register").addEventListener("click",(function(){registerSecurityKey(createArgs)})),document.getElementById("factor_webauthn-register").addEventListener("keypress",(function(){registerSecurityKey(createArgs)}))}}})); +define("factor_webauthn/register",["factor_webauthn/utils","core/prefetch","core/str","core/toast"],(function(utils,Prefetch,Str,Toast){async function registerSecurityKey(createArgs){try{if(!navigator.credentials||!navigator.credentials.create)throw new Error("Browser not supported.");if(!1===createArgs.success)throw new Error(createArgs.msg||"unknown error occurred");utils.recursiveBase64StrToArrayBuffer(createArgs);const cred=await navigator.credentials.create(createArgs),authenticatorResponse={transports:cred.response.getTransports?cred.response.getTransports():null,clientDataJSON:cred.response.clientDataJSON?utils.arrayBufferToBase64(cred.response.clientDataJSON):null,attestationObject:cred.response.attestationObject?utils.arrayBufferToBase64(cred.response.attestationObject):null},registerSuccess=await Str.getString("registersuccess","factor_webauthn");await Toast.add(registerSuccess,{type:"success"}),document.getElementById("id_response_input").value=JSON.stringify(authenticatorResponse),document.getElementById("id_submitbutton").disabled=!1}catch(e){const registerError=await Str.getString("registererror","factor_webauthn",e.message);await Toast.add(registerError,{type:"warning"})}}return{init:function(createArgs){document.getElementById("id_submitbutton").disabled=!0,Prefetch.prefetchStrings("factor_webauthn",["registersuccess","registererror"]),createArgs=JSON.parse(createArgs),document.getElementById("factor_webauthn-register").addEventListener("click",(function(){registerSecurityKey(createArgs)})),document.getElementById("factor_webauthn-register").addEventListener("keypress",(function(){registerSecurityKey(createArgs)}))}}})); //# sourceMappingURL=register.min.js.map \ No newline at end of file diff --git a/admin/tool/mfa/factor/webauthn/amd/build/register.min.js.map b/admin/tool/mfa/factor/webauthn/amd/build/register.min.js.map index c2a40cc4c9edb..70167554b4e8c 100644 --- a/admin/tool/mfa/factor/webauthn/amd/build/register.min.js.map +++ b/admin/tool/mfa/factor/webauthn/amd/build/register.min.js.map @@ -1 +1 @@ -{"version":3,"file":"register.min.js","sources":["../src/register.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * For collecting WebAuthn authenticator details on factor setup\n *\n * @module factor_webauthn/register\n * @copyright Catalyst IT\n * @author Alex Morris \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine([\n 'factor_webauthn/utils',\n 'core/log',\n 'core/prefetch',\n 'core/str',\n 'core/toast',\n], function(\n utils,\n Log,\n Prefetch,\n Str,\n Toast,\n) {\n\n /**\n * Register the security key.\n *\n * @param {*} createArgs\n */\n async function registerSecurityKey(createArgs) {\n try {\n if (!navigator.credentials || !navigator.credentials.create) {\n throw new Error('Browser not supported.');\n }\n\n if (createArgs.success === false) {\n throw new Error(createArgs.msg || 'unknown error occurred');\n }\n\n utils.recursiveBase64StrToArrayBuffer(createArgs);\n const cred = await navigator.credentials.create(createArgs);\n const authenticatorResponse = {\n transports: cred.response.getTransports ? cred.response.getTransports() : null,\n clientDataJSON: cred.response.clientDataJSON ?\n utils.arrayBufferToBase64(cred.response.clientDataJSON) : null,\n attestationObject: cred.response.attestationObject ?\n utils.arrayBufferToBase64(cred.response.attestationObject) : null,\n };\n\n const registerSuccess = await Str.getString('registersuccess', 'factor_webauthn');\n await Toast.add(registerSuccess, {type: 'success'});\n\n document.getElementById('id_response_input').value = JSON.stringify(authenticatorResponse);\n // Enable the submit button so that we can proceed.\n document.getElementById('id_submitbutton').disabled = false;\n } catch (e) {\n Log.debug('The request timed out or you have canceled the request. Please try again later.');\n }\n }\n\n return {\n init: function(createArgs) {\n // Disable the submit button until we have registered a security key.\n document.getElementById('id_submitbutton').disabled = true;\n\n Prefetch.prefetchStrings('factor_webauthn', [\n 'registersuccess',\n ]);\n\n // Register event listeners.\n createArgs = JSON.parse(createArgs);\n document.getElementById('factor_webauthn-register').addEventListener('click', function() {\n registerSecurityKey(createArgs);\n });\n document.getElementById('factor_webauthn-register').addEventListener('keypress', function() {\n registerSecurityKey(createArgs);\n });\n }\n };\n});\n"],"names":["define","utils","Log","Prefetch","Str","Toast","registerSecurityKey","createArgs","navigator","credentials","create","Error","success","msg","recursiveBase64StrToArrayBuffer","cred","authenticatorResponse","transports","response","getTransports","clientDataJSON","arrayBufferToBase64","attestationObject","registerSuccess","getString","add","type","document","getElementById","value","JSON","stringify","disabled","e","debug","init","prefetchStrings","parse","addEventListener"],"mappings":";;;;;;;;AAwBAA,kCAAO,CACH,wBACA,WACA,gBACA,WACA,eACD,SACCC,MACAC,IACAC,SACAC,IACAC,sBAQeC,oBAAoBC,oBAEtBC,UAAUC,cAAgBD,UAAUC,YAAYC,aAC3C,IAAIC,MAAM,8BAGO,IAAvBJ,WAAWK,cACL,IAAID,MAAMJ,WAAWM,KAAO,0BAGtCZ,MAAMa,gCAAgCP,kBAChCQ,WAAaP,UAAUC,YAAYC,OAAOH,YAC1CS,sBAAwB,CAC1BC,WAAYF,KAAKG,SAASC,cAAgBJ,KAAKG,SAASC,gBAAkB,KAC1EC,eAAgBL,KAAKG,SAASE,eAC1BnB,MAAMoB,oBAAoBN,KAAKG,SAASE,gBAAkB,KAC9DE,kBAAmBP,KAAKG,SAASI,kBAC7BrB,MAAMoB,oBAAoBN,KAAKG,SAASI,mBAAqB,MAG/DC,sBAAwBnB,IAAIoB,UAAU,kBAAmB,yBACzDnB,MAAMoB,IAAIF,gBAAiB,CAACG,KAAM,YAExCC,SAASC,eAAe,qBAAqBC,MAAQC,KAAKC,UAAUf,uBAEpEW,SAASC,eAAe,mBAAmBI,UAAW,EACxD,MAAOC,GACL/B,IAAIgC,MAAM,0FAIX,CACHC,KAAM,SAAS5B,YAEXoB,SAASC,eAAe,mBAAmBI,UAAW,EAEtD7B,SAASiC,gBAAgB,kBAAmB,CACxC,oBAIJ7B,WAAauB,KAAKO,MAAM9B,YACxBoB,SAASC,eAAe,4BAA4BU,iBAAiB,SAAS,WAC1EhC,oBAAoBC,eAExBoB,SAASC,eAAe,4BAA4BU,iBAAiB,YAAY,WAC7EhC,oBAAoBC"} \ No newline at end of file +{"version":3,"file":"register.min.js","sources":["../src/register.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * For collecting WebAuthn authenticator details on factor setup\n *\n * @module factor_webauthn/register\n * @copyright Catalyst IT\n * @author Alex Morris \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine([\n 'factor_webauthn/utils',\n 'core/prefetch',\n 'core/str',\n 'core/toast',\n], function(\n utils,\n Prefetch,\n Str,\n Toast,\n) {\n\n /**\n * Register the security key.\n *\n * @param {*} createArgs\n */\n async function registerSecurityKey(createArgs) {\n try {\n if (!navigator.credentials || !navigator.credentials.create) {\n throw new Error('Browser not supported.');\n }\n\n if (createArgs.success === false) {\n throw new Error(createArgs.msg || 'unknown error occurred');\n }\n\n utils.recursiveBase64StrToArrayBuffer(createArgs);\n const cred = await navigator.credentials.create(createArgs);\n const authenticatorResponse = {\n transports: cred.response.getTransports ? cred.response.getTransports() : null,\n clientDataJSON: cred.response.clientDataJSON ?\n utils.arrayBufferToBase64(cred.response.clientDataJSON) : null,\n attestationObject: cred.response.attestationObject ?\n utils.arrayBufferToBase64(cred.response.attestationObject) : null,\n };\n\n const registerSuccess = await Str.getString('registersuccess', 'factor_webauthn');\n await Toast.add(registerSuccess, {type: 'success'});\n\n document.getElementById('id_response_input').value = JSON.stringify(authenticatorResponse);\n // Enable the submit button so that we can proceed.\n document.getElementById('id_submitbutton').disabled = false;\n } catch (e) {\n const registerError = await Str.getString('registererror', 'factor_webauthn', e.message);\n await Toast.add(registerError, {type: 'warning'});\n }\n }\n\n return {\n init: function(createArgs) {\n // Disable the submit button until we have registered a security key.\n document.getElementById('id_submitbutton').disabled = true;\n\n Prefetch.prefetchStrings('factor_webauthn', [\n 'registersuccess',\n 'registererror',\n ]);\n\n // Register event listeners.\n createArgs = JSON.parse(createArgs);\n document.getElementById('factor_webauthn-register').addEventListener('click', function() {\n registerSecurityKey(createArgs);\n });\n document.getElementById('factor_webauthn-register').addEventListener('keypress', function() {\n registerSecurityKey(createArgs);\n });\n }\n };\n});\n"],"names":["define","utils","Prefetch","Str","Toast","registerSecurityKey","createArgs","navigator","credentials","create","Error","success","msg","recursiveBase64StrToArrayBuffer","cred","authenticatorResponse","transports","response","getTransports","clientDataJSON","arrayBufferToBase64","attestationObject","registerSuccess","getString","add","type","document","getElementById","value","JSON","stringify","disabled","e","registerError","message","init","prefetchStrings","parse","addEventListener"],"mappings":";;;;;;;;AAwBAA,kCAAO,CACH,wBACA,gBACA,WACA,eACD,SACCC,MACAC,SACAC,IACAC,sBAQeC,oBAAoBC,oBAEtBC,UAAUC,cAAgBD,UAAUC,YAAYC,aAC3C,IAAIC,MAAM,8BAGO,IAAvBJ,WAAWK,cACL,IAAID,MAAMJ,WAAWM,KAAO,0BAGtCX,MAAMY,gCAAgCP,kBAChCQ,WAAaP,UAAUC,YAAYC,OAAOH,YAC1CS,sBAAwB,CAC1BC,WAAYF,KAAKG,SAASC,cAAgBJ,KAAKG,SAASC,gBAAkB,KAC1EC,eAAgBL,KAAKG,SAASE,eAC1BlB,MAAMmB,oBAAoBN,KAAKG,SAASE,gBAAkB,KAC9DE,kBAAmBP,KAAKG,SAASI,kBAC7BpB,MAAMmB,oBAAoBN,KAAKG,SAASI,mBAAqB,MAG/DC,sBAAwBnB,IAAIoB,UAAU,kBAAmB,yBACzDnB,MAAMoB,IAAIF,gBAAiB,CAACG,KAAM,YAExCC,SAASC,eAAe,qBAAqBC,MAAQC,KAAKC,UAAUf,uBAEpEW,SAASC,eAAe,mBAAmBI,UAAW,EACxD,MAAOC,SACCC,oBAAsB9B,IAAIoB,UAAU,gBAAiB,kBAAmBS,EAAEE,eAC1E9B,MAAMoB,IAAIS,cAAe,CAACR,KAAM,mBAIvC,CACHU,KAAM,SAAS7B,YAEXoB,SAASC,eAAe,mBAAmBI,UAAW,EAEtD7B,SAASkC,gBAAgB,kBAAmB,CACxC,kBACA,kBAIJ9B,WAAauB,KAAKQ,MAAM/B,YACxBoB,SAASC,eAAe,4BAA4BW,iBAAiB,SAAS,WAC1EjC,oBAAoBC,eAExBoB,SAASC,eAAe,4BAA4BW,iBAAiB,YAAY,WAC7EjC,oBAAoBC"} \ No newline at end of file diff --git a/admin/tool/mfa/factor/webauthn/amd/src/register.js b/admin/tool/mfa/factor/webauthn/amd/src/register.js index 89e26913e8dcf..0eec027694a2e 100644 --- a/admin/tool/mfa/factor/webauthn/amd/src/register.js +++ b/admin/tool/mfa/factor/webauthn/amd/src/register.js @@ -24,13 +24,11 @@ define([ 'factor_webauthn/utils', - 'core/log', 'core/prefetch', 'core/str', 'core/toast', ], function( utils, - Log, Prefetch, Str, Toast, @@ -68,7 +66,8 @@ define([ // Enable the submit button so that we can proceed. document.getElementById('id_submitbutton').disabled = false; } catch (e) { - Log.debug('The request timed out or you have canceled the request. Please try again later.'); + const registerError = await Str.getString('registererror', 'factor_webauthn', e.message); + await Toast.add(registerError, {type: 'warning'}); } } @@ -79,6 +78,7 @@ define([ Prefetch.prefetchStrings('factor_webauthn', [ 'registersuccess', + 'registererror', ]); // Register event listeners. diff --git a/admin/tool/mfa/factor/webauthn/lang/en/factor_webauthn.php b/admin/tool/mfa/factor/webauthn/lang/en/factor_webauthn.php index b8f370f8942e0..3cedf58691a05 100644 --- a/admin/tool/mfa/factor/webauthn/lang/en/factor_webauthn.php +++ b/admin/tool/mfa/factor/webauthn/lang/en/factor_webauthn.php @@ -42,6 +42,7 @@ $string['pluginname'] = 'Security key'; $string['privacy:metadata'] = 'The Security key factor plugin does not store any personal data.'; $string['register'] = 'Register security key'; +$string['registererror'] = 'Couldn\'t register security key: {$a}'; $string['registersuccess'] = 'Registered security key'; $string['replacefactor'] = 'Replace security key'; $string['replacefactorconfirmation'] = 'Replace \'{$a}\' security key?';