passkeys-rails 0.2.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d6b32ba5bcfa9553687bb70a01ba4e1b9211ab50336e62f3f7eae7033c3f689
4
- data.tar.gz: e53cc11ffec79936ec74319fb1ec6d47cd74d67f4f56ff0c2d234abf8800b1f3
3
+ metadata.gz: afbb635c3ddfd36d60bccbf936e2a67e091a6bb15822683c9c1db050cdd49909
4
+ data.tar.gz: c9ef1cf6d9e9f5a760037efb831b856dbf706c0860fbf945eadd616c37cb297d
5
5
  SHA512:
6
- metadata.gz: 87cb708335cfae465b142633dc829c92ac16c4d9d958807cbb682caf455ca18e2b13a24ad30b1bb3020f3493b6dd924151269eb37ba2eaeb09508d5b350a9572
7
- data.tar.gz: 04fcd5259c6fe2b1d06f289254817fc1baee73e5d7c7d2aee3476a2155e02e2cb4c40c02deab4285a602bbe9c51806a3e90c5f15ed2b3de928ca9843b0f9fd14
6
+ metadata.gz: 92e7f2a72715c7c4b313d57f7dc1c928cf334375fcdd28fc104f86721562b45484220234e8e5924106fce344e94d95f9cb7e29d0d6879e4ac73451e7a1a17915
7
+ data.tar.gz: 686d6a95cec8274eaadd3fa1555a89f0e1554bc248c1f30eca1ac253933a158e8d12e08bcd74e53b42cbe33a9e0a1630ed14d1ce3a7205a2fe289366d3cbe2c3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ### 0.3.0
2
+
3
+ * Added debug_register endpoint.
4
+ * Fixed authenticatable_params for register enpoint.
5
+ * Added notifications to certain controller actions.
6
+ * Improved spec error helper.
7
+
8
+ ### 0.2.1
9
+
10
+ Added ability to pass either the auth token string or a request with one in the header to authenticate methods.
11
+
1
12
  ### 0.2.0
2
13
 
3
14
  * Added passkeys/debug_login functionality.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Gem Version](https://badge.fury.io/rb/passkeys-rails.svg?cachebust=7)](https://badge.fury.io/rb/passkeys-rails)
1
+ [![Gem Version](https://badge.fury.io/rb/passkeys-rails.svg?cachebust=0.2.1)](https://badge.fury.io/rb/passkeys-rails)
2
2
  [![Build Status](https://app.travis-ci.com/alliedcode/passkeys-rails.svg?branch=main)](https://travis-ci.org/alliedcode/passkeys-rails)
3
3
  [![codecov](https://codecov.io/gh/alliedcode/passkeys-rails/branch/main/graph/badge.svg?token=UHSNJDUL21)](https://codecov.io/gh/alliedcode/passkeys-rails)
4
4
 
@@ -56,7 +56,7 @@ Finally, execute:
56
56
  $ rails generate passkeys_rails:install
57
57
  ```
58
58
 
59
- This will add the `passkeys_rails.rb` configuration file, passkeys routes, and a couple of database migrations to your project.
59
+ This will add the `config/initializers/passkeys_rails.rb` configuration file, passkeys routes, and a couple of database migrations to your project.
60
60
 
61
61
  ### Adding to an standard rails project
62
62
 
@@ -113,6 +113,41 @@ This will add the `passkeys_rails.rb` configuration file, passkeys routes, and a
113
113
 
114
114
  To access the currently authenticated entity, use `current_agent`. If you associated the registration of the agent with one of your own models, use `current_agent.authenticatable`. For example, if you associated the `User` class with the registration, `current_agent.authenticatable` will be a User object.
115
115
 
116
+ ### Notifications
117
+
118
+ Certain actions trigger notifications that can be subscribed. See `subscribe` in `passkeys_rails.rb`.
119
+
120
+ #### Events
121
+
122
+ - `:did_register ` - a new agent has registered
123
+
124
+ - `:did_authenticate` - an agent has been authenticated
125
+
126
+ - `:did_refresh` - an agent's auth token has been refreshed
127
+
128
+ A convenient place to set these up in is in `passkeys_rails.rb`
129
+
130
+ ```ruby
131
+ PasskeysRails.config do |c|
132
+ c.subscribe(:did_register) do |event, agent, request|
133
+ # do something with the agent and/or request
134
+ end
135
+
136
+ c.subscribe(:did_authenticate) do |event, agent, request|
137
+ # do something with the agent and/or request
138
+ end
139
+ end
140
+ ```
141
+
142
+ Subscriptions can also be done elsewhere as subscribe is a PasskeysRails class method.
143
+
144
+ ```ruby
145
+ PasskeysRails.subscribe(:did_register) do |event, agent, request|
146
+ # do something with the agent and/or request
147
+ end
148
+ ```
149
+
150
+
116
151
  ### Authentication Failure
117
152
 
118
153
  1. In the event of authentication failure, PasskeysRails returns an error code and message.
@@ -1,10 +1,15 @@
1
1
  module PasskeysRails
2
2
  class ApplicationController < ActionController::Base
3
+ rescue_from StandardError, with: :handle_standard_error
3
4
  rescue_from ::Interactor::Failure, with: :handle_interactor_failure
4
5
  rescue_from ActionController::ParameterMissing, with: :handle_missing_parameter
5
6
 
6
7
  protected
7
8
 
9
+ def handle_standard_error(error)
10
+ render_error(:authentication, 'error', error.message.truncate(512), status: 500)
11
+ end
12
+
8
13
  def handle_missing_parameter(error)
9
14
  render_error(:authentication, 'missing_parameter', error.message)
10
15
  end
@@ -1,5 +1,8 @@
1
1
  module PasskeysRails
2
2
  class PasskeysController < ApplicationController
3
+ skip_before_action :verify_authenticity_token
4
+ wrap_parameters false
5
+
3
6
  def challenge
4
7
  result = PasskeysRails::BeginChallenge.call!(username: challenge_params[:username])
5
8
 
@@ -11,23 +14,30 @@ module PasskeysRails
11
14
 
12
15
  def register
13
16
  result = PasskeysRails::FinishRegistration.call!(credential: attestation_credential_params.to_h,
14
- authenticatable_info: authenticatable_info&.to_h,
17
+ authenticatable_info: authenticatable_params&.to_h,
15
18
  username: session.dig(:passkeys_rails, :username),
16
19
  challenge: session.dig(:passkeys_rails, :challenge))
17
20
 
18
- render json: { username: result.username, auth_token: result.auth_token }
21
+ broadcast(:did_register, agent: result.agent)
22
+
23
+ render json: auth_response(result)
19
24
  end
20
25
 
21
26
  def authenticate
22
27
  result = PasskeysRails::FinishAuthentication.call!(credential: authentication_params.to_h,
23
28
  challenge: session.dig(:passkeys_rails, :challenge))
24
29
 
25
- render json: { username: result.username, auth_token: result.auth_token }
30
+ broadcast(:did_authenticate, agent: result.agent)
31
+
32
+ render json: auth_response(result)
26
33
  end
27
34
 
28
35
  def refresh
29
36
  result = PasskeysRails::RefreshToken.call!(token: refresh_params[:auth_token])
30
- render json: { username: result.username, auth_token: result.auth_token }
37
+
38
+ broadcast(:did_refresh, agent: result.agent)
39
+
40
+ render json: auth_response(result)
31
41
  end
32
42
 
33
43
  # This action exists to allow easier mobile app debugging as it may not
@@ -36,11 +46,31 @@ module PasskeysRails
36
46
  # CAUTION: It is very insecure to set DEBUG_LOGIN_REGEX in a production environment.
37
47
  def debug_login
38
48
  result = PasskeysRails::DebugLogin.call!(username: debug_login_params[:username])
39
- render json: { username: result.username, auth_token: result.auth_token }
49
+
50
+ broadcast(:did_authenticate, agent: result.agent)
51
+
52
+ render json: auth_response(result)
53
+ end
54
+
55
+ # This action exists to allow easier mobile app debugging as it may not
56
+ # be possible to acess Passkey functionality in mobile simulators.
57
+ # It is only routable if DEBUG_LOGIN_REGEX is set in the server environment.
58
+ # CAUTION: It is very insecure to set DEBUG_LOGIN_REGEX in a production environment.
59
+ def debug_register
60
+ result = PasskeysRails::DebugRegister.call!(username: debug_login_params[:username],
61
+ authenticatable_info: authenticatable_params&.to_h)
62
+
63
+ broadcast(:did_register, agent: result.agent)
64
+
65
+ render json: auth_response(result)
40
66
  end
41
67
 
42
68
  protected
43
69
 
70
+ def auth_response(result)
71
+ { username: result.username, auth_token: result.auth_token }
72
+ end
73
+
44
74
  def challenge_params
45
75
  params.permit(:username)
46
76
  end
@@ -52,8 +82,8 @@ module PasskeysRails
52
82
  credential.permit(:id, :rawId, :type, { response: %i[attestationObject clientDataJSON] })
53
83
  end
54
84
 
55
- def authenticatable_info
56
- params.require[:authenticatable].permit(:class, :params) if params[:authenticatable].present?
85
+ def authenticatable_params
86
+ params.require(:authenticatable).permit(:class, params: {}) if params[:authenticatable].present?
57
87
  end
58
88
 
59
89
  def authentication_params
@@ -71,5 +101,9 @@ module PasskeysRails
71
101
  params.require(:username)
72
102
  params.permit(:username)
73
103
  end
104
+
105
+ def broadcast(event_name, agent:)
106
+ ActiveSupport::Notifications.instrument("passkeys_rails.#{event_name}", { agent:, request: })
107
+ end
74
108
  end
75
109
  end
@@ -5,6 +5,7 @@
5
5
  module PasskeysRails
6
6
  class DebugLogin
7
7
  include Interactor
8
+ include Debuggable
8
9
 
9
10
  delegate :username, to: :context
10
11
 
@@ -12,6 +13,7 @@ module PasskeysRails
12
13
  ensure_debug_mode
13
14
  ensure_regex_match
14
15
 
16
+ context.agent = agent
15
17
  context.username = agent.username
16
18
  context.auth_token = GenerateAuthToken.call!(agent:).auth_token
17
19
  rescue Interactor::Failure => e
@@ -20,18 +22,6 @@ module PasskeysRails
20
22
 
21
23
  private
22
24
 
23
- def ensure_debug_mode
24
- context.fail!(code: :not_allowed, message: 'Action not allowed') if username_regex.blank?
25
- end
26
-
27
- def ensure_regex_match
28
- context.fail!(code: :not_allowed, message: 'Invalid username') unless username&.match?(username_regex)
29
- end
30
-
31
- def username_regex
32
- PasskeysRails.debug_login_regex
33
- end
34
-
35
25
  def agent
36
26
  @agent ||= begin
37
27
  agent = Agent.find_by(username:)
@@ -0,0 +1,44 @@
1
+ # This functionality exists to allow easier mobile app debugging as it may not
2
+ # be possible to acess Passkey functionality in mobile simulators.
3
+ # It is only operational if DEBUG_LOGIN_REGEX is set in the server environment.
4
+ # CAUTION: It is very insecure to set DEBUG_LOGIN_REGEX in a production environment.
5
+ module PasskeysRails
6
+ class DebugRegister
7
+ include Interactor
8
+ include Debuggable
9
+ include AuthenticatableCreator
10
+
11
+ delegate :username, :authenticatable_info, to: :context
12
+
13
+ def call
14
+ ensure_debug_mode
15
+ ensure_regex_match
16
+
17
+ ActiveRecord::Base.transaction do
18
+ create_authenticatable! if aux_class_name.present?
19
+ end
20
+
21
+ context.agent = agent
22
+ context.username = agent.username
23
+ context.auth_token = GenerateAuthToken.call!(agent:).auth_token
24
+ rescue Interactor::Failure => e
25
+ context.fail! code: e.context.code, message: e.context.message
26
+ end
27
+
28
+ private
29
+
30
+ def agent
31
+ @agent ||= begin
32
+ result = BeginRegistration.call(username:)
33
+ context.fail!(code: result.code, message: result.message) if result.failure?
34
+
35
+ agent = Agent.find_by(username:)
36
+ context.fail!(code: :agent_not_found, message: "No agent found with that username") if agent.blank?
37
+
38
+ agent.update! registered_at: Time.current
39
+
40
+ agent
41
+ end
42
+ end
43
+ end
44
+ end
@@ -8,6 +8,7 @@ module PasskeysRails
8
8
  def call
9
9
  verify_credential!
10
10
 
11
+ context.agent = agent
11
12
  context.username = agent.username
12
13
  context.auth_token = GenerateAuthToken.call!(agent:).auth_token
13
14
  rescue Interactor::Failure => e
@@ -2,13 +2,19 @@
2
2
  module PasskeysRails
3
3
  class FinishRegistration
4
4
  include Interactor
5
+ include AuthenticatableCreator
5
6
 
6
7
  delegate :credential, :username, :challenge, :authenticatable_info, to: :context
7
8
 
8
9
  def call
9
10
  verify_credential!
10
- store_passkey_and_register_agent!
11
11
 
12
+ agent.transaction do
13
+ store_passkey_and_register_agent!
14
+ create_authenticatable! if aux_class_name.present?
15
+ end
16
+
17
+ context.agent = agent
12
18
  context.username = agent.username
13
19
  context.auth_token = GenerateAuthToken.call!(agent:).auth_token
14
20
  rescue Interactor::Failure => e
@@ -26,66 +32,16 @@ module PasskeysRails
26
32
  end
27
33
 
28
34
  def store_passkey_and_register_agent!
29
- agent.transaction do
30
- begin
31
- # Store Credential ID, Credential Public Key and Sign Count for future authentications
32
- agent.passkeys.create!(
33
- identifier: webauthn_credential.id,
34
- public_key: webauthn_credential.public_key,
35
- sign_count: webauthn_credential.sign_count
36
- )
37
-
38
- agent.update! registered_at: Time.current
39
- rescue StandardError => e
40
- context.fail! code: :passkey_error, message: e.message
41
- end
42
-
43
- create_authenticatable! if aux_class_name.present?
44
- end
45
- end
46
-
47
- def authenticatable_class
48
- authenticatable_info && authenticatable_info[:class]
49
- end
50
-
51
- def authenticatable_params
52
- authenticatable_info && authenticatable_info[:params]
53
- end
54
-
55
- def aux_class_name
56
- @aux_class_name ||= authenticatable_class || PasskeysRails.default_class
57
- end
58
-
59
- def aux_class
60
- whitelist = PasskeysRails.class_whitelist
61
-
62
- @aux_class ||= begin
63
- if whitelist.is_a?(Array)
64
- unless whitelist.include?(aux_class_name)
65
- context.fail!(code: :invalid_authenticatable_class, message: "authenticatable_class (#{aux_class_name}) is not in the whitelist")
66
- end
67
- elsif whitelist.present?
68
- context.fail!(code: :invalid_class_whitelist,
69
- message: "class_whitelist is invalid. It should be nil or an array of zero or more class names.")
70
- end
71
-
72
- begin
73
- aux_class_name.constantize
74
- rescue StandardError
75
- context.fail!(code: :invalid_authenticatable_class, message: "authenticatable_class (#{aux_class_name}) is not defined")
76
- end
77
- end
78
- end
79
-
80
- def create_authenticatable!
81
- authenticatable = aux_class.create! do |obj|
82
- obj.agent = agent if obj.respond_to?(:agent=)
83
- obj.registering_with(authenticatable_params) if obj.respond_to?(:registering_with)
84
- end
85
-
86
- agent.update!(authenticatable:)
87
- rescue ActiveRecord::RecordInvalid => e
88
- context.fail!(code: :record_invalid, message: e.message)
35
+ # Store Credential ID, Credential Public Key and Sign Count for future authentications
36
+ agent.passkeys.create!(
37
+ identifier: webauthn_credential.id,
38
+ public_key: webauthn_credential.public_key,
39
+ sign_count: webauthn_credential.sign_count
40
+ )
41
+
42
+ agent.update! registered_at: Time.current
43
+ rescue StandardError => e
44
+ context.fail! code: :passkey_error, message: e.message
89
45
  end
90
46
 
91
47
  def webauthn_credential
@@ -8,6 +8,7 @@ module PasskeysRails
8
8
  def call
9
9
  agent = ValidateAuthToken.call!(auth_token: token).agent
10
10
 
11
+ context.agent = agent
11
12
  context.username = agent.username
12
13
  context.auth_token = GenerateAuthToken.call!(agent:).auth_token
13
14
  rescue Interactor::Failure => e
@@ -7,6 +7,7 @@ module PasskeysRails
7
7
  included do
8
8
  has_one :agent, as: :authenticatable, class_name: "PasskeysRails::Agent"
9
9
 
10
+ delegate :username, to: :agent, allow_nil: true
10
11
  delegate :registered?, to: :agent, allow_nil: true
11
12
 
12
13
  def registering_with(_params)
@@ -0,0 +1,53 @@
1
+ module PasskeysRails
2
+ module AuthenticatableCreator
3
+ extend ActiveSupport::Concern
4
+
5
+ protected
6
+
7
+ def create_authenticatable!
8
+ authenticatable = aux_class.new
9
+ authenticatable.agent = agent if authenticatable.respond_to?(:agent=)
10
+ authenticatable.registering_with(authenticatable_params) if authenticatable.respond_to?(:registering_with)
11
+ authenticatable.save!
12
+
13
+ agent.update!(authenticatable:)
14
+ rescue ActiveRecord::RecordInvalid => e
15
+ context.fail!(code: :record_invalid, message: e.message)
16
+ end
17
+
18
+ def aux_class_name
19
+ @aux_class_name ||= authenticatable_class || PasskeysRails.default_class
20
+ end
21
+
22
+ private
23
+
24
+ def authenticatable_class
25
+ authenticatable_info && authenticatable_info[:class]
26
+ end
27
+
28
+ def authenticatable_params
29
+ authenticatable_info && authenticatable_info[:params]
30
+ end
31
+
32
+ def aux_class
33
+ whitelist = PasskeysRails.class_whitelist
34
+
35
+ @aux_class ||= begin
36
+ if whitelist.is_a?(Array)
37
+ unless whitelist.include?(aux_class_name)
38
+ context.fail!(code: :invalid_authenticatable_class, message: "authenticatable_class (#{aux_class_name}) is not in the whitelist")
39
+ end
40
+ elsif whitelist.present?
41
+ context.fail!(code: :invalid_class_whitelist,
42
+ message: "class_whitelist is invalid. It should be nil or an array of zero or more class names.")
43
+ end
44
+
45
+ begin
46
+ aux_class_name.constantize
47
+ rescue StandardError
48
+ context.fail!(code: :invalid_authenticatable_class, message: "authenticatable_class (#{aux_class_name}) is not defined")
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module PasskeysRails
2
+ module Debuggable
3
+ extend ActiveSupport::Concern
4
+
5
+ protected
6
+
7
+ def ensure_debug_mode
8
+ context.fail!(code: :not_allowed, message: 'Action not allowed') if username_regex.blank?
9
+ end
10
+
11
+ def ensure_regex_match
12
+ context.fail!(code: :not_allowed, message: 'Invalid username') unless username&.match?(username_regex)
13
+ end
14
+
15
+ def username_regex
16
+ PasskeysRails.debug_login_regex
17
+ end
18
+ end
19
+ end
data/config/routes.rb CHANGED
@@ -1,13 +1,14 @@
1
1
  PasskeysRails::Engine.routes.draw do
2
- post 'passkeys/challenge'
3
- post 'passkeys/register'
4
- post 'passkeys/authenticate'
5
- post 'passkeys/refresh'
2
+ post 'challenge', to: 'passkeys#challenge'
3
+ post 'register', to: 'passkeys#register'
4
+ post 'authenticate', to: 'passkeys#authenticate'
5
+ post 'refresh', to: 'passkeys#refresh'
6
6
 
7
- # This route exists to allow easier mobile app debugging as it may not
7
+ # These routes exist to allow easier mobile app debugging as it may not
8
8
  # be possible to acess Passkey functionality in mobile simulators.
9
9
  # CAUTION: It is very insecure to set DEBUG_LOGIN_REGEX in a production environment.
10
10
  constraints(->(_request) { PasskeysRails.debug_login_regex.present? }) do
11
- post 'passkeys/debug_login'
11
+ post 'debug_login', to: 'passkeys#debug_login'
12
+ post 'debug_register', to: 'passkeys#debug_register'
12
13
  end
13
14
  end
@@ -45,4 +45,19 @@ PasskeysRails.config do |c|
45
45
  # for example: %w[User AdminUser]
46
46
  #
47
47
  # c.class_whitelist = nil
48
+
49
+ # To subscribe to various events in PasskeysRails, use the subscribe method.
50
+ # It can be called multiple times to subscribe to more than one event.
51
+ #
52
+ # Valid events:
53
+ # :did_register
54
+ # :did_authenticate
55
+ # :did_refresh
56
+ #
57
+ # Each event will include the event name, current agent and http request.
58
+ #
59
+ # For example:
60
+ # c.subscribe(:did_register) do |event, agent, request|
61
+ # puts("#{event} | #{agent.id} | #{request.headers}")
62
+ # end
48
63
  end
@@ -45,6 +45,26 @@ module PasskeysRails
45
45
  # for example: %w[User AdminUser]
46
46
  mattr_accessor :class_whitelist, default: nil
47
47
 
48
+ # Convenience method to subscribe to various events in PasskeysRails.
49
+ #
50
+ # Valid events:
51
+ # :did_register
52
+ # :did_authenticate
53
+ # :did_refresh
54
+ #
55
+ # Each event will include the event name, current agent and http request.
56
+ # For example:
57
+ #
58
+ # subscribe(:did_register) do |event, agent, request|
59
+ # # do something with the agent and/or request
60
+ # end
61
+ #
62
+ def self.subscribe(event_name)
63
+ ActiveSupport::Notifications.subscribe("passkeys_rails.#{event_name}") do |name, _start, _finish, _id, payload|
64
+ yield(name.gsub(/^passkeys_rails\./, ''), payload[:agent], payload[:request]) if block_given?
65
+ end
66
+ end
67
+
48
68
  # This is only used by the debug_login endpoint.
49
69
  # CAUTION: It is very insecure to set DEBUG_LOGIN_REGEX in a production environment.
50
70
  def self.debug_login_regex
@@ -53,6 +73,8 @@ module PasskeysRails
53
73
 
54
74
  # Returns an Interactor::Context that indicates if the request is authentic.
55
75
  #
76
+ # `request` can be a String on an Http Request
77
+ #
56
78
  # .success? is true if authentic
57
79
  # .agent is the Passkey::Agent on success
58
80
  #
@@ -60,10 +82,19 @@ module PasskeysRails
60
82
  # .code is the error code on failure
61
83
  # .message is the human readable error message on failure
62
84
  def self.authenticate(request)
63
- PasskeysRails::ValidateAuthToken.call(auth_token: request.headers['X-Auth'])
85
+ auth_token = if request.is_a?(String)
86
+ request
87
+ elsif request.respond_to?(:headers)
88
+ request.headers['X-Auth']
89
+ else
90
+ ""
91
+ end
92
+
93
+ PasskeysRails::ValidateAuthToken.call(auth_token:)
64
94
  end
65
95
 
66
96
  # Raises a PasskeysRails::Error exception if the request is not authentic.
97
+ # `request` can be a String on an Http Request
67
98
  def self.authenticate!(request)
68
99
  auth = authenticate(request)
69
100
  return if auth.success?
@@ -1,3 +1,3 @@
1
1
  module PasskeysRails
2
- VERSION = "0.2.0".freeze
2
+ VERSION = "0.3.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passkeys-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Troy Anderson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-28 00:00:00.000000000 Z
11
+ date: 2023-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -358,12 +358,15 @@ files:
358
358
  - app/interactors/passkeys_rails/begin_challenge.rb
359
359
  - app/interactors/passkeys_rails/begin_registration.rb
360
360
  - app/interactors/passkeys_rails/debug_login.rb
361
+ - app/interactors/passkeys_rails/debug_register.rb
361
362
  - app/interactors/passkeys_rails/finish_authentication.rb
362
363
  - app/interactors/passkeys_rails/finish_registration.rb
363
364
  - app/interactors/passkeys_rails/generate_auth_token.rb
364
365
  - app/interactors/passkeys_rails/refresh_token.rb
365
366
  - app/interactors/passkeys_rails/validate_auth_token.rb
366
367
  - app/models/concerns/passkeys_rails/authenticatable.rb
368
+ - app/models/concerns/passkeys_rails/authenticatable_creator.rb
369
+ - app/models/concerns/passkeys_rails/debuggable.rb
367
370
  - app/models/passkeys_rails/agent.rb
368
371
  - app/models/passkeys_rails/application_record.rb
369
372
  - app/models/passkeys_rails/error.rb