Fix DataCloneError when credentialRequestOptions is relayed by password-manager extensions - #1042
Fix DataCloneError when credentialRequestOptions is relayed by password-manager extensions#1042Be-Mann wants to merge 1 commit into
Conversation
…rd-manager extensions Fixes nextcloud#995 `credentialRequestOptions` comes from the Pinia store, so nested values (e.g. `allowCredentials[i].transports`) are still Vue-reactive `Proxy` objects when passed to `startAuthentication()`. The native `navigator.credentials.get()` handles that fine via WebIDL conversion, but password-manager extensions that intercept the call and relay it via `window.postMessage()` (structured clone) choke on the Proxies with `DataCloneError: ... could not be cloned.` — confirmed with both Bitwarden and Enpass. This unwraps the options into a plain, serializable object before handing them to `startAuthentication()`. `JSON.parse(JSON.stringify(...))` is used instead of `structuredClone()` because `structuredClone()` fails on reactive Proxies for the same reason. The options are pure JSON (base64url strings), so the round-trip is lossless. Root cause analysis and manual verification by @tschuegy and @Rumbelstilzchen in nextcloud#995. Signed-off-by: Be-Mann <25839760+Be-Mann@users.noreply.github.com>
|
Thanks a lot, good finding 👍 I think it should also work, and if I would prefer that version, to flag the object as not reactive. Could you please give the following patch a test? Index: src/components/Challenge.vue
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/components/Challenge.vue b/src/components/Challenge.vue
--- a/src/components/Challenge.vue (revision 1ef69d077f361d17126dec3c295d86107e1fff1f)
+++ b/src/components/Challenge.vue (date 1787519209471)
@@ -94,7 +94,7 @@
let authResponse
try {
authResponse = await startAuthentication({
- optionsJSON: JSON.parse(JSON.stringify(this.credentialRequestOptions)),
+ optionsJSON: this.credentialRequestOptions,
})
} catch (error) {
switch (error.name) {
Index: src/main-challenge.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main-challenge.js b/src/main-challenge.js
--- a/src/main-challenge.js (revision 1ef69d077f361d17126dec3c295d86107e1fff1f)
+++ b/src/main-challenge.js (date 1787519368239)
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { createApp } from 'vue'
+import { createApp, markRaw } from 'vue'
import { createPinia } from 'pinia'
import Nextcloud from './mixins/Nextcloud.js'
import Challenge from './components/Challenge.vue'
@@ -14,9 +14,7 @@
const credentialRequestOptions = loadState('twofactor_webauthn', 'credential-request-options')
const mainStore = useMainStore(pinia)
-mainStore.$patch({
- credentialRequestOptions,
-})
+mainStore.credentialRequestOptions = markRaw(credentialRequestOptions)
const app = createApp(Challenge)
app.mixin(Nextcloud) |
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
Fixes #995
credentialRequestOptionscomes from the Pinia store, so nested values (e.g.allowCredentials[i].transports) are still Vue-reactiveProxyobjects when passed tostartAuthentication(). The nativenavigator.credentials.get()handles that fine via WebIDL conversion, but password-manager extensions that intercept the call and relay it viawindow.postMessage()(structured clone) choke on the Proxies withDataCloneError: ... could not be cloned.— confirmed with both Bitwarden and Enpass.This unwraps the options into a plain, serializable object before handing them to
startAuthentication().JSON.parse(JSON.stringify(...))is used instead ofstructuredClone()becausestructuredClone()fails on reactive Proxies for the same reason. The options are pure JSON (base64url strings), so the round-trip is lossless.Root cause analysis and manual verification by @tschuegy and @Rumbelstilzchen in #995.
🤖 AI (if applicable)