Ios support - #1
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Nice work! |
Empty string was serialized as Some("") by Tauri, bypassing the None
guard in auth_start and sending a 0-byte salt to the authenticator.
Pass null explicitly so Rust receives None.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CTAP2/WebAuthn requires PRF salts to be exactly 32 bytes. Return a clear error message rather than passing an invalid-length salt to the authenticator, which would produce an opaque platform error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Salt fields now show '32 bytes, base64url' as placeholder text. Gen buttons use crypto.getRandomValues to populate each field with a cryptographically random 32-byte salt in base64url format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ASAuthorizationController.delegate is a weak reference. Without storing a strong reference to the controller, PasskeyHandler could be deallocated before the delegate callback fires, causing a hung continuation. Mirrors the existing iOS PasskeyHandler implementation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
creds_ptr safety relies on Swift copying the pointer before async dispatch. PRF clientExtensionResults are not covered by the authenticator signature per the WebAuthn spec — document this for future readers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WebauthnPlugin now stores the active handler as a property and exposes a cancel plugin command. The Rust mobile authenticator overrides cancel() to invoke it. Previously cancel() was dead code — no stored reference existed to call it on. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add cancel() to macOS PasskeyHandler (mirrors iOS). Store the active handler in a module-level MainActor variable in Exports.swift and expose webauthn_cancel as a C function. The Rust macos authenticator overrides cancel() to call it via FFI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
hey guys (@fendent @Profiidev) I'm working on PRF extension support based off of this branch. Do you think the current ios support is mergable both here and then (with the macos support) into the main project? |
|
For me it looks good but I can't merge this here |
|
Seems good on my end but I haven't tested it. My MacOS portion is done, happy to merge this if you're good to go with it. Though, I might request a squash first. :) |
I'm good with merging if you are. and then we can see how @Profiidev feels about the combined merge in the main project
lol - i do like lots of mini commits. wanna just do the squash on merge option here? |
Sounds good to me. I'll get this squashed and merged then! Thanks so much for the effort! |
|
@dkackman Actually, just thinking about it, if I do the squash, I think it'll attribute the commit authorship to me. Better you do it, I think, if you don't mind. That way you can write a commit message better describing your work than I would. 😄 |
I may have needed to to a force push instead of a merge but take a look. My git skills tail off pretty qucikly past the basics. :) |
|
@fendent i think i fixed that up. i can do a new PR if you would prefer. im also good with you doing the squash on merge |
The iOS plugin called PasskeyHandler.register/authenticate with PRF
parameters the iOS handler never declared, so the iOS target did not
compile. Add the parameters and the PRF request/response handling,
mirroring the macOS bridge (PRF APIs are iOS 18+).
The iOS extension decoders keyed on snake_case, but webauthn-rs-proto
serializes RequestRegistrationExtensions/RequestAuthenticationExtensions
with rename_all = "camelCase", so PRF was never enabled and salts were
never extracted. Drop the CodingKeys overrides.
PRF salts and outputs are key-derivation secrets and were written
verbatim to the debug log via {args:?} and {result:?}. Log rp_id and
completion only.
Three panics were reachable from webview-supplied input:
- PRF salts were forced into [u8; 32] with unwrap(), so any salt that
was not exactly 32 bytes panicked while holding the manager mutex,
poisoning it for the rest of the process. Return an error instead.
- assertion.credentials is legitimately None when a single discoverable
credential matches; unwrap() panicked on that normal path.
- The status conversions ended in unreachable!() despite StatusUpdate
and StatusPinUv having unmatched variants (PinIsTooShort,
PinIsTooLong, PinNotSet, InteractiveManagement). Hitting one panicked
the status thread, after which no PIN prompt reached the UI and the
ceremony hung. Map the PIN variants through to new PinEvent cases and
skip InteractiveManagement.
Also drop unwrap() on the state-callback channel send/recv so a dropped
peer surfaces as an error rather than a panic.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR based on macos code
cc: @Profiidev
iOS Suppport
The main addition is iOS support which includes a detailed readme on how to get setup. The generated outputs of
tauri ios initcontain my team id and bundle id's etc. Can be overwritten with the setup-dev script descibed belowI also added some quality of life changes to the example app to help with my own testin. These may be of value, but if not can also be excluded without losing the ios addition.
Example App changes
apple account setup
setup-dev.shscript to populate the necessary bundle id's and entitlements etc for an individual developer. Only needs to be run oncemacos local dev
build-macos-dev.sh- sincepnpm tauri devwon't work on macos with restricted APIsz, this automates the building, bundling and signing requirements so the app can be iterated on more easily. it digs the necessary signing data points out of the respective config files. Needs to be run to test any new code.backend
ui