passkey-rs icon indicating copy to clipboard operation
passkey-rs copied to clipboard

Error deserializing `PublicKeyCredential` from JsValue

Open Ben-Lichtman opened this issue 1 year ago • 3 comments

Trying to implement webauthn on the browser, which includes deserializing the browser's response to the message into a passkey_types::webauthn::CreatedPublicKeyCredential / passkey_types::webauthn::PublicKeyCredential, however it seems that the raw_id field of PublicKeyCredential is allowed to be {} when returned from the browser, which causes the deserialization to return an error.

let promise = window()
  .navigator()
  .credentials()
  .create_with_options(&creation_options)
  .map_err(Error::JsError)?;

let cred_jsvalue = JsFuture::from(promise).await.map_err(Error::JsError)?;

let cred = web_sys::PublicKeyCredential::from(cred_jsvalue);

let cred = <JsValue as JsValueSerdeExt>::into_serde::<
passkey_types::webauthn::CreatedPublicKeyCredential,
>(&cred)
.unwrap();
panicked at app/src/webauthn.rs:82:6:
called `Result::unwrap()` on an `Err` value: Error("invalid type: map, expected A vector of bytes or a base46(url) encoded string", line: 1, column: 41)

Ben-Lichtman avatar Sep 22 '24 22:09 Ben-Lichtman

Hi @Ben-Lichtman, the issue here is the use of ArrayBuffer by the webauthn types which is readonly memory. When trying to serialize to JSON it will automatically "drop" the value and replace it with an empty object. To get around this you need to either re-map the array buffer to an array or a base64url string. OR remap it directly from the web_sys/js_sys types. Perhaps wasm_bindgen_serde could help with this but I haven't tested it.

I would like to one day build wasm dedicated library for the passkey crates, but thats a fairly heavy lift that I currently don't really have time for. We alway welcome contributions.

Progdrasil avatar Sep 23 '24 15:09 Progdrasil

@Progdrasil I'm a little confused - isn't the deserialization though JsValueSerdeExt (via gloo) designed to do exactly that (remap from the web_sys type into your PublicKeyCredential type)?

It would make sense to me that the answer would be to change the Deserialize implementation on Bytes to handle visit_map?

Please let me know if I'm misunderstanding.

Ben-Lichtman avatar Sep 29 '24 22:09 Ben-Lichtman

JsValueSerdeExt does not. It uses the JSON.stringify method internally which transforms it to an empty map. See this JSFiddle as an example. Implementing visit_map will not help since the value will be lost by stringifying the array buffer and that map will be empty.

Progdrasil avatar Oct 01 '24 14:10 Progdrasil