action_passkey 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +145 -0
  4. data/Rakefile +12 -0
  5. data/lib/action_passkey/engine.rb +10 -0
  6. data/lib/action_passkey/has_passkeys.rb +19 -0
  7. data/lib/action_passkey/version.rb +5 -0
  8. data/lib/action_passkey.rb +27 -0
  9. data/lib/generators/action_passkey/install/install_generator.rb +87 -0
  10. data/lib/generators/action_passkey/install/templates/action_passkey.rb +7 -0
  11. data/lib/generators/action_passkey/install/templates/create_passkeys.rb +14 -0
  12. data/lib/generators/action_passkey/install/templates/headers.js +5 -0
  13. data/lib/generators/action_passkey/install/templates/passkey.js +5 -0
  14. data/lib/generators/action_passkey/install/templates/passkey.rb +3 -0
  15. data/lib/generators/action_passkey/install/templates/passkey_authentication_controller.js +30 -0
  16. data/lib/generators/action_passkey/install/templates/passkey_registration_controller.js +30 -0
  17. data/lib/generators/action_passkey/install/templates/passkey_relying_party.rb +17 -0
  18. data/lib/generators/action_passkey/install/templates/passkey_sessions_controller.rb +27 -0
  19. data/lib/generators/action_passkey/install/templates/passkey_sessions_options_controller.rb +15 -0
  20. data/lib/generators/action_passkey/install/templates/passkeys_controller.rb +26 -0
  21. data/lib/generators/action_passkey/install/templates/passkeys_helper.rb +13 -0
  22. data/lib/generators/action_passkey/install/templates/passkeys_options_controller.rb +18 -0
  23. data/lib/generators/action_passkey/install/templates/post.js +17 -0
  24. data/lib/generators/action_passkey/install/templates/webauthn-json.js +3 -0
  25. data/sig/action_passkey.rbs +4 -0
  26. metadata +111 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a3f0887232a61ea08be40f10b67cd6b036cd0b05488489bd3f2fa14373361693
4
+ data.tar.gz: efddff4cc664e2405b4c04970ab561f3c2298ee5595691582a3e1cc04facb853
5
+ SHA512:
6
+ metadata.gz: e5c063f5dd97440d5f9c80bee28b7ecf17a879fe1aad07c18d3e0704d772a7ebed6335c98d852839554962954b7db4ae325ff170acbb37c9f6a93f3dcd9e896f
7
+ data.tar.gz: 41248ad68052c38e8ab1332b3a77e8b90f466aa3d8275648b8bc30fd2d6531bf554bee18b19a0e816436592fa56aebf4ee011d626ce3df1315ad68f436e1462c
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Tomas Costantino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # ActionPasskey
2
+
3
+ ActionPasskey generates boilerplate code to easily set up passkey authentication in Rails apps. It generates the Rails models, migration, controllers, routes, helpers, and Stimulus controllers needed to register and authenticate with WebAuthn passkeys.
4
+
5
+ ## Requirements
6
+
7
+ - Rails 7.1 or newer
8
+ - Ruby 3.2 or newer
9
+ - Importmap and Stimulus
10
+ - `bin/rails generate authentication`
11
+ - An application `User` model
12
+
13
+ ## Installation
14
+
15
+ Add the gem to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem "action_passkey"
19
+ ```
20
+
21
+ Then install it:
22
+
23
+ ```bash
24
+ bundle install
25
+ bin/rails generate action_passkey:install
26
+ bin/rails db:migrate
27
+ ```
28
+
29
+ The generator creates passkey models, controllers, JavaScript files, importmap pins, and routes.
30
+
31
+ ## Configuration
32
+
33
+ The generator creates `config/initializers/action_passkey.rb`:
34
+
35
+ ```ruby
36
+ ActionPasskey.configure do |config|
37
+ config.origins = ["http://localhost:3000"]
38
+ config.name = "My Application"
39
+ end
40
+ ```
41
+
42
+ Set `origins` to the browser origins your app is served from. In production this should be your HTTPS origin, for example:
43
+
44
+ ```ruby
45
+ config.origins = ["https://example.com"]
46
+ ```
47
+
48
+ ## User Model
49
+
50
+ The generator adds this macro to `app/models/user.rb` when the file exists:
51
+
52
+ ```ruby
53
+ class User < ApplicationRecord
54
+ has_passkeys
55
+ end
56
+ ```
57
+
58
+ The macro defines:
59
+
60
+ ```ruby
61
+ has_many :passkeys, dependent: :destroy
62
+ ```
63
+
64
+ If the generator did not add it, add `has_passkeys` manually.
65
+
66
+ ## Routes
67
+
68
+ The generator adds these routes to `config/routes.rb`:
69
+
70
+ ```ruby
71
+ resources :passkeys, only: :create
72
+ resource :passkey_session, only: :create
73
+
74
+ namespace :passkeys do
75
+ resource :options, only: :create
76
+ end
77
+
78
+ namespace :passkey_sessions do
79
+ resource :options, only: :create
80
+ end
81
+ ```
82
+
83
+ ## View Helpers
84
+
85
+ Use the generated helpers in your views:
86
+
87
+ ```erb
88
+ <%= add_passkey_button %>
89
+ ```
90
+
91
+ ```erb
92
+ <%= sign_in_with_passkey_button %>
93
+ ```
94
+
95
+ `add_passkey_button` starts passkey registration for the current user.
96
+
97
+ `sign_in_with_passkey_button` starts passkey authentication.
98
+
99
+ ## Generated Files
100
+
101
+ The install generator creates:
102
+
103
+ ```text
104
+ app/models/passkey.rb
105
+ app/controllers/concerns/passkey_relying_party.rb
106
+ app/controllers/passkeys_controller.rb
107
+ app/controllers/passkeys/options_controller.rb
108
+ app/controllers/passkey_sessions_controller.rb
109
+ app/controllers/passkey_sessions/options_controller.rb
110
+ app/helpers/passkeys_helper.rb
111
+ app/javascript/controllers/passkey_registration_controller.js
112
+ app/javascript/controllers/passkey_authentication_controller.js
113
+ app/javascript/helpers/passkey.js
114
+ app/javascript/helpers/post.js
115
+ app/javascript/helpers/headers.js
116
+ config/initializers/action_passkey.rb
117
+ vendor/javascript/webauthn-json.js
118
+ ```
119
+
120
+ It also creates a `create_passkeys` migration and updates `config/importmap.rb`.
121
+
122
+ ## Development
123
+
124
+ After checking out the repo, install dependencies:
125
+
126
+ ```bash
127
+ bin/setup
128
+ ```
129
+
130
+ Run tests and linting:
131
+
132
+ ```bash
133
+ bundle exec rake test
134
+ bundle exec rubocop
135
+ ```
136
+
137
+ Build the gem locally:
138
+
139
+ ```bash
140
+ gem build action_passkey.gemspec
141
+ ```
142
+
143
+ ## License
144
+
145
+ The gem is available as open source under the terms of the MIT License.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+ require "action_dispatch"
5
+ require "rails/engine"
6
+
7
+ module ActionPasskey
8
+ class Engine < Rails::Engine
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module ActionPasskey
6
+ module HasPasskeys
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def has_passkeys
11
+ has_many :passkeys, dependent: :destroy
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ ActiveSupport.on_load(:active_record) do
18
+ include ActionPasskey::HasPasskeys
19
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionPasskey
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "action_passkey/version"
4
+ require_relative "action_passkey/engine"
5
+ require_relative "action_passkey/has_passkeys"
6
+
7
+ module ActionPasskey
8
+ class Error < StandardError; end
9
+
10
+ class << self
11
+ attr_accessor :configuration
12
+
13
+ def configure
14
+ self.configuration ||= Configuration.new
15
+ yield configuration
16
+ end
17
+ end
18
+
19
+ class Configuration
20
+ attr_accessor :origins, :name
21
+
22
+ def initialize
23
+ @origins = []
24
+ @name = "My Application"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module ActionPasskey
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include Rails::Generators::Migration
10
+
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ def copy_initializer
14
+ template "action_passkey.rb", "config/initializers/action_passkey.rb"
15
+ end
16
+
17
+ def copy_passkey_model
18
+ template "passkey.rb", "app/models/passkey.rb"
19
+ end
20
+
21
+ def copy_controller_files
22
+ copy_file "passkey_relying_party.rb", "app/controllers/concerns/passkey_relying_party.rb"
23
+ copy_file "passkeys_controller.rb", "app/controllers/passkeys_controller.rb"
24
+ copy_file "passkeys_options_controller.rb", "app/controllers/passkeys/options_controller.rb"
25
+ copy_file "passkey_sessions_controller.rb", "app/controllers/passkey_sessions_controller.rb"
26
+ copy_file "passkey_sessions_options_controller.rb", "app/controllers/passkey_sessions/options_controller.rb"
27
+ end
28
+
29
+ def copy_helper_file
30
+ copy_file "passkeys_helper.rb", "app/helpers/passkeys_helper.rb"
31
+ end
32
+
33
+ def copy_javascript_files
34
+ copy_file "passkey_registration_controller.js", "app/javascript/controllers/passkey_registration_controller.js"
35
+ copy_file "passkey_authentication_controller.js",
36
+ "app/javascript/controllers/passkey_authentication_controller.js"
37
+ copy_file "passkey.js", "app/javascript/helpers/passkey.js"
38
+ copy_file "post.js", "app/javascript/helpers/post.js"
39
+ copy_file "headers.js", "app/javascript/helpers/headers.js"
40
+ copy_file "webauthn-json.js", "vendor/javascript/webauthn-json.js"
41
+ end
42
+
43
+ def configure_importmap
44
+ return unless File.exist?(File.join(destination_root, "config/importmap.rb"))
45
+
46
+ append_to_file "config/importmap.rb", <<~RUBY
47
+
48
+ pin_all_from "app/javascript/helpers", under: "helpers"
49
+ pin "@github/webauthn-json", to: "webauthn-json.js"
50
+ RUBY
51
+ end
52
+
53
+ def copy_passkey_migration
54
+ migration_template "create_passkeys.rb", "db/migrate/create_passkeys.rb"
55
+ end
56
+
57
+ def add_has_passkeys_to_user_model
58
+ return unless File.exist?(File.join(destination_root, "app/models/user.rb"))
59
+
60
+ inject_into_class "app/models/user.rb", "User", " has_passkeys\n"
61
+ end
62
+
63
+ def add_routes
64
+ route <<~RUBY
65
+ resources :passkeys, only: :create
66
+ resource :passkey_session, only: :create
67
+
68
+ namespace :passkeys do
69
+ resource :options, only: :create
70
+ end
71
+
72
+ namespace :passkey_sessions do
73
+ resource :options, only: :create
74
+ end
75
+ RUBY
76
+ end
77
+
78
+ def migration_version
79
+ "[#{ActiveRecord::Migration.current_version}]"
80
+ end
81
+
82
+ def self.next_migration_number(dirname)
83
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,7 @@
1
+ ActionPasskey.configure do |config|
2
+ # The origins of your application (must match the browser URL)
3
+ config.origins = ["http://localhost:3000"]
4
+
5
+ # The display name for your relying party
6
+ config.name = "My Application"
7
+ end
@@ -0,0 +1,14 @@
1
+ class CreatePasskeys < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :passkeys do |t|
4
+ t.references :user, null: false, foreign_key: true
5
+ t.string :external_id, null: false
6
+ t.text :public_key, null: false
7
+ t.integer :sign_count, null: false, default: 0
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :passkeys, :external_id, unique: true
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ export default {
2
+ "Content-Type": "application/json",
3
+ "Accept": "application/json",
4
+ "X-CSRF-Token": document.querySelector("meta[name='csrf-token']").content
5
+ }
@@ -0,0 +1,5 @@
1
+ export function assertPasskeySupported() {
2
+ if (!window.PublicKeyCredential) {
3
+ throw new Error("This browser does not support passkeys.")
4
+ }
5
+ }
@@ -0,0 +1,3 @@
1
+ class Passkey < ApplicationRecord
2
+ belongs_to :user
3
+ end
@@ -0,0 +1,30 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { get } from "@github/webauthn-json"
3
+ import { assertPasskeySupported } from "helpers/passkey"
4
+ import post from "helpers/post"
5
+
6
+ export default class extends Controller {
7
+ async authenticate() {
8
+ try {
9
+ assertPasskeySupported()
10
+
11
+ const passkeyOptions = await this.#createPasskeyOptions()
12
+ const credential = await get({ publicKey: passkeyOptions })
13
+ const result = await this.#createSession(credential)
14
+
15
+ window.location.href = result.location
16
+ } catch (error) {
17
+ window.alert(`Could not sign in with passkey: ${error.message}`)
18
+ }
19
+ }
20
+
21
+ async #createPasskeyOptions() {
22
+ const response = await post("/passkey_sessions/options")
23
+ return response.json()
24
+ }
25
+
26
+ async #createSession(credential) {
27
+ const response = await post("/passkey_session", { credential })
28
+ return response.json()
29
+ }
30
+ }
@@ -0,0 +1,30 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { create } from "@github/webauthn-json"
3
+ import { assertPasskeySupported } from "helpers/passkey"
4
+ import post from "helpers/post"
5
+
6
+ export default class extends Controller {
7
+ async register() {
8
+ try {
9
+ assertPasskeySupported()
10
+
11
+ const passkeyOptions = await this.#createPasskeyOptions()
12
+ const credential = await create({ publicKey: passkeyOptions })
13
+
14
+ await this.#createPasskey(credential)
15
+
16
+ window.alert("Passkey added")
17
+ } catch (error) {
18
+ window.alert(`Could not add passkey: ${error.message}`)
19
+ }
20
+ }
21
+
22
+ async #createPasskeyOptions() {
23
+ const response = await post("/passkeys/options")
24
+ return response.json()
25
+ }
26
+
27
+ async #createPasskey(credential) {
28
+ await post("/passkeys", { credential })
29
+ }
30
+ }
@@ -0,0 +1,17 @@
1
+ require "uri"
2
+ require "webauthn"
3
+
4
+ module PasskeyRelyingParty
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def passkey_relying_party
10
+ @passkey_relying_party ||= WebAuthn::RelyingParty.new(
11
+ allowed_origins: ActionPasskey.configuration.origins,
12
+ id: URI(ActionPasskey.configuration.origins.first).host,
13
+ name: ActionPasskey.configuration.name,
14
+ verify_attestation_statement: false
15
+ )
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ class PasskeySessionsController < ApplicationController
2
+ include PasskeyRelyingParty
3
+
4
+ allow_unauthenticated_access
5
+
6
+ def create
7
+ credential, passkey = passkey_relying_party.verify_authentication(
8
+ passkey_params.to_h,
9
+ session.delete(:passkey_authentication_challenge)
10
+ ) do |webauthn_credential|
11
+ Passkey.find_by!(external_id: webauthn_credential.id)
12
+ end
13
+
14
+ passkey.update!(sign_count: credential.sign_count)
15
+ start_new_session_for passkey.user
16
+
17
+ render json: { location: after_authentication_url }, status: :created
18
+ end
19
+
20
+ private
21
+ def passkey_params
22
+ params.require(:credential).permit(
23
+ :id, :rawId, :type,
24
+ response: [ :clientDataJSON, :authenticatorData, :signature, :userHandle ]
25
+ )
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ class PasskeySessions::OptionsController < ApplicationController
2
+ include PasskeyRelyingParty
3
+
4
+ allow_unauthenticated_access
5
+
6
+ def create
7
+ options = passkey_relying_party.options_for_authentication(
8
+ allow: Passkey.pluck(:external_id)
9
+ )
10
+
11
+ session[:passkey_authentication_challenge] = options.challenge
12
+
13
+ render json: options
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ class PasskeysController < ApplicationController
2
+ include PasskeyRelyingParty
3
+
4
+ def create
5
+ credential = passkey_relying_party.verify_registration(
6
+ passkey_params.to_h,
7
+ session.delete(:passkey_registration_challenge)
8
+ )
9
+
10
+ Current.user.passkeys.create!(
11
+ external_id: credential.id,
12
+ public_key: credential.public_key,
13
+ sign_count: credential.sign_count
14
+ )
15
+
16
+ render json: { status: "created" }, status: :created
17
+ end
18
+
19
+ private
20
+ def passkey_params
21
+ params.require(:credential).permit(
22
+ :id, :rawId, :type,
23
+ response: [ :clientDataJSON, :attestationObject ]
24
+ )
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module PasskeysHelper
2
+ def add_passkey_button
3
+ content_tag(:div, data: { controller: "passkey-registration" }) do
4
+ tag.button("Add passkey", type: "button", data: { action: "passkey-registration#register" })
5
+ end
6
+ end
7
+
8
+ def sign_in_with_passkey_button
9
+ content_tag(:div, data: { controller: "passkey-authentication" }) do
10
+ tag.button("Sign in with passkey", type: "button", data: { action: "passkey-authentication#authenticate" })
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ class Passkeys::OptionsController < ApplicationController
2
+ include PasskeyRelyingParty
3
+
4
+ def create
5
+ options = passkey_relying_party.options_for_registration(
6
+ user: {
7
+ id: WebAuthn.standard_encoder.encode(Current.user.id.to_s),
8
+ name: Current.user.email_address,
9
+ display_name: Current.user.email_address
10
+ },
11
+ exclude: Current.user.passkeys.pluck(:external_id)
12
+ )
13
+
14
+ session[:passkey_registration_challenge] = options.challenge
15
+
16
+ render json: options
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ import headers from "helpers/headers"
2
+
3
+ export default async function post(path, body) {
4
+ const options = { method: "POST", headers }
5
+
6
+ if (body !== undefined) {
7
+ options.body = JSON.stringify(body)
8
+ }
9
+
10
+ const response = await fetch(path, options)
11
+
12
+ if (!response.ok) {
13
+ throw new Error(`POST ${path} failed`)
14
+ }
15
+
16
+ return response
17
+ }
@@ -0,0 +1,3 @@
1
+ /* esm.sh - @github/webauthn-json@2.1.1 */
2
+ function p(e){let i="==".slice(0,(4-e.length%4)%4),a=e.replace(/-/g,"+").replace(/_/g,"/")+i,c=atob(a),s=new ArrayBuffer(c.length),l=new Uint8Array(s);for(let u=0;u<c.length;u++)l[u]=c.charCodeAt(u);return s}function g(e){let i=new Uint8Array(e),a="";for(let l of i)a+=String.fromCharCode(l);return btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}var t="copy",o="convert";function d(e,i,a){if(i===t)return a;if(i===o)return e(a);if(i instanceof Array)return a.map(c=>d(e,i[0],c));if(i instanceof Object){let c={};for(let[s,l]of Object.entries(i)){if(l.derive){let u=l.derive(a);u!==void 0&&(a[s]=u)}if(!(s in a)){if(l.required)throw new Error(`Missing key: ${s}`);continue}if(a[s]==null){c[s]=null;continue}c[s]=d(e,l.schema,a[s])}return c}}function f(e,i){return{required:!0,schema:e,derive:i}}function r(e){return{required:!0,schema:e}}function n(e){return{required:!1,schema:e}}var v={type:r(t),id:r(o),transports:n(t)},y={appid:n(t),appidExclude:n(t),credProps:n(t)},b={appid:n(t),appidExclude:n(t),credProps:n(t)},h={publicKey:r({rp:r(t),user:r({id:r(o),name:r(t),displayName:r(t)}),challenge:r(o),pubKeyCredParams:r(t),timeout:n(t),excludeCredentials:n([v]),authenticatorSelection:n(t),attestation:n(t),extensions:n(y)}),signal:n(t)},m={type:r(t),id:r(t),rawId:r(o),authenticatorAttachment:n(t),response:r({clientDataJSON:r(o),attestationObject:r(o),transports:f(t,e=>{var i;return((i=e.getTransports)==null?void 0:i.call(e))||[]})}),clientExtensionResults:f(b,e=>e.getClientExtensionResults())},C={mediation:n(t),publicKey:r({challenge:r(o),timeout:n(t),rpId:n(t),allowCredentials:n([v]),userVerification:n(t),extensions:n(y)}),signal:n(t)},S={type:r(t),id:r(t),rawId:r(o),authenticatorAttachment:n(t),response:r({clientDataJSON:r(o),authenticatorData:r(o),signature:r(o),userHandle:r(o)}),clientExtensionResults:f(b,e=>e.getClientExtensionResults())},A={credentialCreationOptions:h,publicKeyCredentialWithAttestation:m,credentialRequestOptions:C,publicKeyCredentialWithAssertion:S};function w(e){return d(p,h,e)}function x(e){return d(g,m,e)}async function E(e){let i=await navigator.credentials.create(w(e));return x(i)}function O(e){return d(p,C,e)}function R(e){return d(g,S,e)}async function q(e){let i=await navigator.credentials.get(O(e));return R(i)}function K(){return!!(navigator.credentials&&navigator.credentials.create&&navigator.credentials.get&&window.PublicKeyCredential)}export{E as create,q as get,A as schema,K as supported};
3
+ //# sourceMappingURL=webauthn-json.mjs.map
@@ -0,0 +1,4 @@
1
+ module ActionPasskey
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_passkey
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tomas Costantino
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: railties
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: webauthn
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.4'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.4'
54
+ description: ActionPasskey generates boilerplate code to easily set up passkey authentication
55
+ in Rails apps
56
+ email:
57
+ - tomascostantino.au@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE.txt
63
+ - README.md
64
+ - Rakefile
65
+ - lib/action_passkey.rb
66
+ - lib/action_passkey/engine.rb
67
+ - lib/action_passkey/has_passkeys.rb
68
+ - lib/action_passkey/version.rb
69
+ - lib/generators/action_passkey/install/install_generator.rb
70
+ - lib/generators/action_passkey/install/templates/action_passkey.rb
71
+ - lib/generators/action_passkey/install/templates/create_passkeys.rb
72
+ - lib/generators/action_passkey/install/templates/headers.js
73
+ - lib/generators/action_passkey/install/templates/passkey.js
74
+ - lib/generators/action_passkey/install/templates/passkey.rb
75
+ - lib/generators/action_passkey/install/templates/passkey_authentication_controller.js
76
+ - lib/generators/action_passkey/install/templates/passkey_registration_controller.js
77
+ - lib/generators/action_passkey/install/templates/passkey_relying_party.rb
78
+ - lib/generators/action_passkey/install/templates/passkey_sessions_controller.rb
79
+ - lib/generators/action_passkey/install/templates/passkey_sessions_options_controller.rb
80
+ - lib/generators/action_passkey/install/templates/passkeys_controller.rb
81
+ - lib/generators/action_passkey/install/templates/passkeys_helper.rb
82
+ - lib/generators/action_passkey/install/templates/passkeys_options_controller.rb
83
+ - lib/generators/action_passkey/install/templates/post.js
84
+ - lib/generators/action_passkey/install/templates/webauthn-json.js
85
+ - sig/action_passkey.rbs
86
+ homepage: https://github.com/tomycostantino/action_passkey
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ allowed_push_host: https://rubygems.org
91
+ homepage_uri: https://github.com/tomycostantino/action_passkey
92
+ source_code_uri: https://github.com/tomycostantino/action_passkey
93
+ rubygems_mfa_required: 'true'
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 3.2.0
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubygems_version: 4.0.10
109
+ specification_version: 4
110
+ summary: Passkey generator for Rails.
111
+ test_files: []