Commit Graph

21 Commits

Author SHA1 Message Date
Stanko K.R. 54cb1a140f Add a purpose to challanges 2026-03-25 17:57:37 +01:00
Stanko K.R. 5d0f52b57c Update as_json to return string keys 2026-03-25 17:26:50 +01:00
Stanko K.R. 693415bc71 Rename request options to authentication options 2026-03-25 17:26:49 +01:00
Stanko K.R. 1983014be6 Rely solely on the challange signature for verification
The cookie approach seems like the more secure aproach because it ties the authentication or registration attempt to the user's browser session, but it doesn't work reliably on Chrome for Windows. Also, a simila problem pops up on Chrome for Linux if the session is used instead of a separate cookie. It looks like the browser doesn't propagate the state change through fast enough which results in some requests contaiining the new/updated cookie, and others don't, which results in sporadic failures. Since we use a signed and expiring challange we still get protection from replay attacks and tampering which enables us to omit the cookie entierly and rely on the challange's signature to prove expiration and authenticity. The only thing we lose is the ability to tie and attemp to a single browser session.

See: https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-challengeURL which proposes to add the same challange fetching logic as part of the standard

See: https://github.com/w3c/webauthn/issues/1856 which discusses issues that arise from having expiring challanges (which the spec recommends)

See: https://github.com/OneUptime/oneuptime/security/advisories/GHSA-gjjc-pcwp-c74m which is an explot that can happen if the server isn't able to verify the authenticity of challanges that are sent outside of a cookie
2026-03-25 17:26:49 +01:00
Stanko K.R. 1cf1f598e1 Require resident keys by default 2026-03-18 12:14:17 +01:00
Stanko K.R. 017bcc9ce1 Polish up Passkey interface
- Fix indentation
- Split awkward initializer into separate methods
- Rename credentials to passkeys
- Simplify authenticator registry loading
- Flatten nested errors under ActionPack::WebAuthn
- Set passkey current params only requests that use it
- Inline anemic methods
- Replace custom validation with ActiveModel::Validation
- Rename identity to holder in Passkey
- Rename credentials to passkeys in JS
- Extract framework library out of controllers
- Pass params hashes down to ActionPack
- Attempt to simplify public interface
- Push data decoding down to the classes representing the data
- Introduce has_passkeys
- Add CBOR bigint support
- Rename ActionPack::WebAuthn::Passkey to ActionPack::Passkey
- Add create_passkey_button helper
- Rename public-key to creation-options
- Add sign_in_with_passkey_button helper
- Dispatch events for the whole Passkey lifecycle
- Add ED25519 support
- Prevent crash on missing meta tag
- Validate resident key options
- Don't clobber existing ActionPack config options
- Validate cryptographic params
- Move CurrentWebAuthnRequest into ActionPack::Passkey
- Use ActiveModel::Attributes for Options objects
- Implement expiring challanges
- Add lifecycle events
- Extract param helpers into Request
- Add passkey_creation_options and passkey_request_options helpers
- Add create_passkey_challenge to make it easier to override the create method if needed
- Prefix all view helpers with passkey_
- Auto-include ActionPack::Passkey::Holder
- Make the passkey challange url configurable
- Add a reminder about Passkeys to the magic link email
2026-03-18 11:51:10 +01:00
Stanko K.R. fbe9252db1 Auto-suggest name for new Passkeys
- Use plain client data json everywhere
- Expose AAGUID and backed_up on Credentials
- Make attestation verifiers configurable
- Auto-suggest names for passkeys and show icons
2026-03-18 11:49:59 +01:00
Stanko K.R. da69039476 Implement Passkey authentication 2026-03-18 11:49:23 +01:00
Stanko K.R. 6c58fd9bdd Implement Passkey registration
- Create Identity credentials
- Add management UI and registration flow
2026-03-18 11:48:52 +01:00
Stanko K.R. 4bb0a2929c Implement WebAuthn protocol
- Add a CBOR decoder
- Add public key credential options
- Add COSE key decoder
- Add authenticator attestation and assertion
- Add credentials
- Add exclude_credentials
2026-03-18 11:47:48 +01:00
Mike Dalessio b6ea558de8 Move TrackTrueClientIp middleware into saas engine (#2677)
The True-Client-IP header is set by Cloudflare and is only trustworthy
when behind a Cloudflare proxy. In non-Cloudflare deployments, this
header is attacker-controlled and can be used to spoof IP addresses.

Moving the middleware into the saas engine ensures it only loads for our
Cloudflare-fronted production deployment, not for self-hosted OSS
instances.

GHSA-cpch-9qg2-x8fq
2026-03-09 15:14:17 -04:00
Joseph Hale c61f49cce9 Extract detached-blob guard into its own file
Separate the attachment existence check from the broadcast suppression
override so each file has a single responsibility. The guard now lives
in ActiveStorageAnalyzeJobSkipDetached with its own documentation
explaining the upload-then-delete race condition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:38:19 -07:00
Joseph Hale 143508fc22 Skip AnalyzeJob when blob has no attachments
Upload-then-delete races cause AnalyzeJob to hit S3 after PurgeJob has
already removed the object, producing Aws::S3::Errors::NoSuchKey noise
in solid_queue_failed_executions. Since PurgeOnLastAttachment destroys
the attachment row before enqueueing PurgeJob, checking
blob.attachments.exists? catches this — a fast DB query that avoids the
S3 round-trip entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:13:00 -07:00
Rosa Gutierrez 1a0d8e2501 Fix notification click URL by using correct data property
The web push payload sends the URL in data.url but the service
worker was looking for data.path, resulting in undefined URLs.

Also fix WebPush::Notification test to use url instead of path

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-25 19:31:13 +01:00
Kevin McConnell 23fe40fa81 Correctly initialise WebPush connection (#2417)
The `ipaddr` arg here is being interpreted as a positional arg (since
the keyword arg doesn't exist), which results in an invalid connection
object. This was causing push notifications to silently fail.

We should initialise the property on the object instead.
2026-01-22 12:03:02 -08:00
Mike Dalessio b2e3c7b1c7 Drop the "max previewable file size" limit
which was originally introduced to work around timing issues causing
us to try (and fail) to generate previews on sqlite read replicas.
2025-11-21 10:55:20 -05:00
Donal McBreen a8412449e3 Don't cast and extract normalization
We are not trying to handle user input so `cast` can be a no-op. Also
extract the base36 normalization logic, let the binary class handle the
serialize encoding and add some tests.
2025-11-17 09:12:36 -05:00
Mike Dalessio 8538c21d4e Copy Cloudflare's True-Client-IP header to X-Forwarded-For
ref: https://3.basecamp.com/2914079/buckets/37331921/todos/9243121525
2025-11-03 14:22:33 -05:00
Mike Dalessio a711975904 Turn off attachment previews on large files
ref: https://fizzy.37signals.com/5986089/collections/7/cards/1302
2025-08-19 12:16:24 -04:00
Stanko K.R. c95e8678a9 Extract #all_emoji? to a Rails ext 2025-08-13 15:14:12 +02:00
Mike Dalessio 0a92fc3a16 Port over Jeremy's fix for slow uploads
ref: https://fizzy.37signals.com/5986089/collections/7/cards/944
2025-07-20 13:19:53 -04:00