[passkeys] Fixes unhandled callback, double response errors & wrong return type - #3054
[passkeys] Fixes unhandled callback, double response errors & wrong return type#3054a2kolbasov wants to merge 6 commits into
Conversation
There was a problem hiding this comment.
Quickly tested this and noticed that when canceling the authentication request, the extension now immediately returns NotAllowedError. This goes against: https://www.w3.org/TR/webauthn-2/#sctn-assertion-privacy
Also explained at https://www.w3.org/TR/webauthn-2/#sctn-getAssertion step 18:
Return a DOMException whose name is "NotAllowedError". In order to prevent information leak that could identify the user without consent, this step MUST NOT be executed before lifetimeTimer has expired.
At first I thought it was very strange, because there is keepassxc-browser/keepassxc-browser/content/passkeys-inject.js Lines 36 to 42 in 379dfaf
On the other hand, in WebAuthn-3 privacy is implemented differently |
The latest released version is still 2. It's not recommended to implement changes from 3, because those might still change: https://www.w3.org/standards/types/#CR. I agree it will simplify a lot of things just to return an error immediately instead of waiting for the lifetimer. |
e64207e to
b459d5d
Compare
|
Okay, got it. I've made changes in a044542. |
|
When I was recording the video demonstration, I found another error. If the database is locked, the content script does not handle this situation, and the page script will never receive a response with an error. |
| * @param {number=} timeout | ||
| */ | ||
| const startTimer = function (timeout) { | ||
| let resolve, reject; |
There was a problem hiding this comment.
Why not use const instead of let inside the function?
There was a problem hiding this comment.
There was a problem hiding this comment.
let promise & let timerId can be replaced with const ...
| kpxcPasskeysUtils.sendPasskeysResponse(ret.response, ret.response?.errorCode, errorMessage); | ||
| stopTimer(lifetimeTimer); | ||
| // Any error not related to passkeys (no connection to KPXC, database not opened, unknown error, etc.) | ||
| if (ret === null) { |
There was a problem hiding this comment.
Here's a chance for a small refactor:
const errorCode = ret === null ? PASSKEYS_REQUEST_CANCELED : ret.response.errorCode;
And then just use the errorCode for checks and send message etc. This way we can keep the ret as const and the code stays a bit cleaner.
There was a problem hiding this comment.
Otherwise this seems to work great now!
Fixed errors in processing error messages when passkeys are missing or a request is rejected.
The
setTimeoutcallback was returning an error that was silently discarded. As a result, the page context never received the error, and thePromiseremained pending forever.When
kpxcPasskeysUtils.passkeysFallback === true,kpxcPasskeysUtils.sendPasskeysResponsewas being called (and sending a response) twice because of a missingreturn ;.According to the WebAuthn specification, cancelled or rejected operations always return errors, not
null. Some websites don’t expect this and throw a script error on the page, which also leads to an endless wait for UI updates. (https://www.w3.org/TR/webauthn-2/#sctn-getAssertion)Fix lost callback on DB connection failure
Screenshots or videos
Testing strategy
On https://webauthn.io/
Additional information, resources etc.
Promise.withResolversbrowser compatibility, Firefoxstrict_min_versionType of change