summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Steinmetz <richard@steinmetz.cloud>2024-05-02 18:01:12 +0200
committerGitHub <noreply@github.com>2024-05-02 18:01:12 +0200
commit197e6dcd86df6b520daa9713f9705bb90bbe0608 (patch)
tree475c43b3fb87bb31e4c6960e44ad0440aa24a0cf
parent321900d03238308029c503493594704275f0ea1a (diff)
parenta3490738d77fda5be12108c4e458922bd2450a69 (diff)
Merge pull request #45136 from nextcloud/feat/webauthn/submit-device-name
feat(webauthn): submit device name by pressing enter
-rw-r--r--apps/settings/src/components/WebAuthn/AddDevice.vue19
-rw-r--r--dist/settings-vue-settings-personal-webauthn.js4
-rw-r--r--dist/settings-vue-settings-personal-webauthn.js.map2
3 files changed, 14 insertions, 11 deletions
diff --git a/apps/settings/src/components/WebAuthn/AddDevice.vue b/apps/settings/src/components/WebAuthn/AddDevice.vue
index 72077003cdd..d8329eec676 100644
--- a/apps/settings/src/components/WebAuthn/AddDevice.vue
+++ b/apps/settings/src/components/WebAuthn/AddDevice.vue
@@ -2,6 +2,7 @@
- @copyright 2020, Roeland Jago Douma <roeland@famdouma.nl>
-
- @author Roeland Jago Douma <roeland@famdouma.nl>
+ - @author 2024 Richard Steinmetz <richard@steinmetz.cloud>
-
- @license GNU AGPL version 3 or any later version
-
@@ -39,14 +40,16 @@
<div v-else-if="step === RegistrationSteps.NAMING"
class="new-webauthn-device">
<span class="icon-loading-small webauthn-loading" />
- <NcTextField ref="nameInput"
- class="new-webauthn-device__name"
- :label="t('settings', 'Device name')"
- :value.sync="name"
- show-trailing-button
- :trailing-button-label="t('settings', 'Add')"
- trailing-button-icon="arrowRight"
- @trailing-button-click="submit" />
+ <form @submit.prevent="submit">
+ <NcTextField ref="nameInput"
+ class="new-webauthn-device__name"
+ :label="t('settings', 'Device name')"
+ :value.sync="name"
+ show-trailing-button
+ :trailing-button-label="t('settings', 'Add')"
+ trailing-button-icon="arrowRight"
+ @trailing-button-click="submit" />
+ </form>
</div>
<div v-else-if="step === RegistrationSteps.PERSIST"
diff --git a/dist/settings-vue-settings-personal-webauthn.js b/dist/settings-vue-settings-personal-webauthn.js
index 5638bdfffc2..99ee9250ff3 100644
--- a/dist/settings-vue-settings-personal-webauthn.js
+++ b/dist/settings-vue-settings-personal-webauthn.js
@@ -1,3 +1,3 @@
/*! For license information please see settings-vue-settings-personal-webauthn.js.LICENSE.txt */
-(()=>{var e,n,r,i={93477:(e,n,r)=>{"use strict";var i=r(85471),a=r(38613),o=r(96763);function s(t){const e=new Uint8Array(t);let n="";for(const t of e)n+=String.fromCharCode(t);return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function c(t){const e=t.replace(/-/g,"+").replace(/_/g,"/"),n=(4-e.length%4)%4,r=e.padEnd(e.length+n,"="),i=atob(r),a=new ArrayBuffer(i.length),o=new Uint8Array(a);for(let t=0;t<i.length;t++)o[t]=i.charCodeAt(t);return a}function l(){return void 0!==window?.PublicKeyCredential&&"function"==typeof window.PublicKeyCredential}function u(t){const{id:e}=t;return{...t,id:c(e),transports:t.transports}}class d extends Error{constructor({message:t,code:e,cause:n,name:r}){super(t,{cause:n}),this.name=r??n.name,this.code=e}}const p=new class{createNewAbortSignal(){if(this.controller){const t=new Error("Cancelling existing WebAuthn API call for new one");t.name="AbortError",this.controller.abort(t)}const t=new AbortController;return this.controller=t,t.signal}cancelCeremony(){if(this.controller){const t=new Error("Manually cancelling existing WebAuthn API call");t.name="AbortError",this.controller.abort(t),this.controller=void 0}}},h=["cross-platform","platform"];function f(t){if(t&&!(h.indexOf(t)<0))return t}function v(t,e){o.warn(`The browser extension that intercepted this WebAuthn API call incorrectly implemented ${t}. You should report this error to them.\n`,e)}var g=r(56760),m=r(48934),A=(r(51257),r(10854)),y=r.n(A),b=r(85168),w=r(9518),_=r(82182);const x=(0,r(53529).YK)().setApp("settings").detectUser().build();var R=r(53334),E=r(63814),C=r(28893),I=r(26287),W=r(96763);const O=t=>e=>(x.debug(t),e),N=Object.freeze({READY:1,REGISTRATION:2,NAMING:3,PERSIST:4}),S={name:"AddDevice",components:{NcButton:w.A,NcTextField:_.A},props:{httpWarning:Boolean,isHttps:{type:Boolean,default:!1},isLocalhost:{type:Boolean,default:!1}},setup:()=>({RegistrationSteps:N}),data:()=>({name:"",credential:{},step:N.READY}),watch:{step(){this.step===N.NAMING&&this.$nextTick((()=>{var t;return null===(t=this.$refs.nameInput)||void 0===t?void 0:t.focus()}))}},methods:{async start(){this.step=N.REGISTRATION,W.debug("Starting WebAuthn registration");try{await(0,g.C)(),this.credential=await async function(){const t=(0,E.Jv)("/settings/api/personal/webauthn/registration");try{x.debug("Fetching webauthn registration data");const{data:e}=await I.A.get(t);return x.debug("Start webauthn registration"),await async function(t){if(!l())throw new Error("WebAuthn is not supported in this browser");const e={publicKey:{...t,challenge:c(t.challenge),user:{...t.user,id:c(t.user.id)},excludeCredentials:t.excludeCredentials?.map(u)}};let n;e.signal=p.createNewAbortSignal();try{n=await navigator.credentials.create(e)}catch(t){throw function({error:t,options:e}){const{publicKey:n}=e;if(!n)throw Error("options was missing required publicKey property");if("AbortError"===t.name){if(e.signal instanceof AbortSignal)return new d({message:"Registration ceremony was sent an abort signal",code:"ERROR_CEREMONY_ABORTED",cause:t})}else if("ConstraintError"===t.name){if(!0===n.authenticatorSelection?.requireResidentKey)return new d({message:"Discoverable credentials were required but no available authenticator supported it",code:"ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT",cause:t});if("required"===n.authenticatorSelection?.userVerification)return new d({message:"User verification was required but no available authenticator supported it",code:"ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT",cause:t})}else{if("InvalidStateError"===t.name)return new d({message:"The authenticator was previously registered",code:"ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED",cause:t});if("NotAllowedError"===t.name)return new d({message:t.message,code:"ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY",cause:t});if("NotSupportedError"===t.name)return 0===n.pubKeyCredParams.filter((t=>"public-key"===t.type)).length?new d({message:'No entry in pubKeyCredParams was of type "public-key"',code:"ERROR_MALFORMED_PUBKEYCREDPARAMS",cause:t}):new d({message:"No available authenticator supported any of the specified pubKeyCredParams algorithms",code:"ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG",cause:t});if("SecurityError"===t.name){const e=window.location.hostname;if("localhost"!==(r=e)&&!/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(r))return new d({message:`${window.location.hostname} is an invalid domain`,code:"ERROR_INVALID_DOMAIN",cause:t});if(n.rp.id!==e)return new d({message:`The RP ID "${n.rp.id}" is invalid for this domain`,code:"ERROR_INVALID_RP_ID",cause:t})}else if("TypeError"===t.name){if(n.user.id.byteLength<1||n.user.id.byteLength>64)return new d({message:"User ID was not between 1 and 64 characters",code:"ERROR_INVALID_USER_ID_LENGTH",cause:t})}else if("UnknownError"===t.name)return new d({message:"The authenticator was unable to process the specified options, or could not create a new credential",code:"ERROR_AUTHENTICATOR_GENERAL_ERROR",cause:t})}var r;return t}({error:t,options:e})}if(!n)throw new Error("Registration was not completed");const{id:r,rawId:i,response:a,type:o}=n;let h,g,m,A;if("function"==typeof a.getTransports&&(h=a.getTransports()),"function"==typeof a.getPublicKeyAlgorithm)try{g=a.getPublicKeyAlgorithm()}catch(t){v("getPublicKeyAlgorithm()",t)}if("function"==typeof a.getPublicKey)try{const t=a.getPublicKey();null!==t&&(m=s(t))}catch(t){v("getPublicKey()",t)}if("function"==typeof a.getAuthenticatorData)try{A=s(a.getAuthenticatorData())}catch(t){v("getAuthenticatorData()",t)}return{id:r,rawId:s(i),response:{attestationObject:s(a.attestationObject),clientDataJSON:s(a.clientDataJSON),transports:h,publicKeyAlgorithm:g,publicKey:m,authenticatorData:A},type:o,clientExtensionResults:n.getClientExtensionResults(),authenticatorAttachment:f(n.authenticatorAttachment)}}(e)}catch(t){if(x.error(t),C.A.isAxiosError(t))throw new Error((0,R.Tl)("settings","Could not register device: Network error"));if("InvalidStateError"===t.name)throw new Error((0,R.Tl)("settings","Could not register device: Probably already registered"));throw new Error((0,R.Tl)("settings","Could not register device"))}}(),this.step=N.NAMING}catch(t){(0,b.Qg)(t),this.step=N.READY}},submit(){return this.step=N.PERSIST,(0,g.C)().then(O("confirmed password")).then(this.saveRegistrationData).then(O("registration data saved")).then((()=>this.reset())).then(O("app reset")).catch(W.error)},async saveRegistrationData(){try{const t=await async