webauthn-rails 0.1.1 → 0.1.2

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: 20ded36acb2b7a3f4d67cdd4e860dc41e6f8490bb9143be6a0575117e1e7a84e
4
- data.tar.gz: 8b2d46393c0d24e340b82f7f5d908e34fdd7cedb30501b8e8ba9663f217c23b9
3
+ metadata.gz: a8425de86118ec096864312cfb7b4ef98947437da28d88cdc5f12b0a4191aea9
4
+ data.tar.gz: 43f56151976719e1bb00200b3134cdde63b6786f5afaf225c274982e324258fc
5
5
  SHA512:
6
- metadata.gz: 89c27f2bd69320aef0d3a36207788478ce85e7eea4b1f722950ec12749fa3fdcaa5a3eed1f322b77425d5d8b8e1d848cf912d84cd55c7872fa2142750626b345
7
- data.tar.gz: d125c6229d26da7d19794479091ec59b706e10166a70a5e3f228a4d3571906a5b3d3a3db23c81cfb2c735e56c91c9bdf1ee01f249689761641d46aad1319f8ff
6
+ metadata.gz: d44fa7ccb7a3adc9248a74ab73f2758e0b3fb3fd4b7b70e98cb8956fac70c9c84b3eec954f39e4f261f26d8a4e3112bc4e4a289cab19542b2c11bbe4d4462d99
7
+ data.tar.gz: 784af4bb7538eccd87f50c4ce61d57ee8e3d92b823586c0c08c3c24718405b21d4258de6f599eca3e33b143a24ba1384fbc1365ec8e357186483dd708ef7686b
@@ -10,9 +10,9 @@
10
10
  "webauthn-credentials-options-url-value": create_options_passkeys_path,
11
11
  }) do |form| %>
12
12
  <div class="field">
13
- <%%= form.label :nickname, 'Security Key nickname' %>
13
+ <%%= form.label :nickname, 'Passkey nickname' %>
14
14
  <%%= form.text_field :nickname, required: true %>
15
15
  </div>
16
16
  <%%= form.hidden_field :public_key_credential, data: { "webauthn-credentials-target": "credentialHiddenInput" } %>
17
- <%%= form.submit "Add Security Key", disabled: true, data: { "webauthn-credentials-target": "submitButton" } %>
17
+ <%%= form.submit "Add Passkey", disabled: true, data: { "webauthn-credentials-target": "submitButton" } %>
18
18
  <%% end %>
@@ -48,7 +48,7 @@ class PasskeysControllerTest < ActionDispatch::IntegrationTest
48
48
  end
49
49
 
50
50
  assert_redirected_to root_path
51
- assert_match (/Security Key registered successfully/), flash[:notice]
51
+ assert_match (/Passkey registered successfully/), flash[:notice]
52
52
  assert_nil session[:current_registration]
53
53
  end
54
54
 
@@ -5,8 +5,7 @@ class ManageWebauthnCredentialsTest < ApplicationSystemTestCase
5
5
  include VirtualAuthenticatorTestHelper
6
6
 
7
7
  def setup
8
- user = User.create!(email_address: "alice@example.com", password: "S3cr3tP@ssw0rd!")
9
- sign_in_as(user)
8
+ @user = User.create!(email_address: "alice@example.com", password: "S3cr3tP@ssw0rd!")
10
9
  @authenticator = add_virtual_authenticator
11
10
  end
12
11
 
@@ -14,63 +13,64 @@ class ManageWebauthnCredentialsTest < ApplicationSystemTestCase
14
13
  @authenticator.remove!
15
14
  end
16
15
 
17
- test "add credentials and sign in" do
18
- visit root_path
16
+ test "adding a passkey" do
17
+ sign_in_as(@user)
19
18
 
19
+ visit new_passkey_path
20
+ fill_in("Passkey nickname", with: "Touch ID")
20
21
  click_on "Add Passkey"
21
22
 
22
- fill_in("Security Key nickname", with: "Touch ID")
23
- click_on "Add Security Key"
24
-
25
- assert_current_path "/"
26
- assert_selector "div", text: "Security Key registered successfully"
27
- assert_selector "span", text: "Touch ID"
23
+ assert_current_path root_path
24
+ # Add custom assertions based on your application's behavior
25
+ # assert_text "Passkey registered successfully"
26
+ end
28
27
 
29
- click_on "Sign out"
30
- assert_selector("input[type=submit][value='Sign in']")
28
+ test "signing in with existing passkey" do
29
+ add_passkey_to_authenticator(@authenticator, @user)
31
30
 
31
+ visit new_session_path
32
32
  click_on "Sign In with Passkey"
33
33
 
34
- assert_current_path "/"
35
- assert_selector "h3", text: "Your Passkeys"
34
+ assert_current_path root_path
35
+ # Add custom assertions based on your application's behavior
36
36
  end
37
37
 
38
- test "sign in with 2FA WebAuthn credential" do
39
- visit root_path
40
-
41
- click_on "Add Second Factor Key"
38
+ test "adding a 2FA WebAuthn credential" do
39
+ sign_in_as(@user)
42
40
 
41
+ visit new_second_factor_webauthn_credential_path
43
42
  fill_in("Security Key nickname", with: "Touch ID")
44
43
  click_on "Add Security Key"
45
44
 
46
- assert_current_path "/"
47
- assert_selector "div", text: "Security Key registered successfully"
48
- assert_selector "span", text: "Touch ID"
45
+ assert_current_path root_path
46
+ # Add custom assertions based on your application's behavior
47
+ # assert_text "Security Key registered successfully"
48
+ end
49
49
 
50
- click_on "Sign out"
51
- assert_selector("input[type=submit][value='Sign in']")
50
+ test "sign in with existing 2FA WebAuthn credential" do
51
+ add_security_key_to_authenticator(@authenticator, @user)
52
52
 
53
- fill_in "email_address", with: "alice@example.com"
54
- fill_in "password", with: "S3cr3tP@ssw0rd!"
53
+ visit new_session_path
54
+ fill_in "email_address", with: @user.email_address
55
+ fill_in "password", with: @user.password
55
56
  click_on "Sign in"
56
57
 
58
+ assert_current_path new_second_factor_authentication_path
57
59
  assert_selector "h3", text: "Two-factor authentication"
58
60
  click_on "Use Security Key"
59
61
 
60
- assert_current_path "/"
61
- assert_selector "h3", text: "Your Passkeys"
62
+ assert_current_path root_path
63
+ # Add custom assertions based on your application's behavior
62
64
  end
63
65
 
64
66
  private
65
67
 
66
68
  def sign_in_as(user)
67
69
  visit new_session_path
68
-
69
70
  fill_in "email_address", with: user.email_address
70
71
  fill_in "password", with: user.password
71
-
72
72
  click_on "Sign in"
73
73
 
74
- assert_selector "h3", text: "Your Passkeys"
74
+ assert_current_path root_path
75
75
  end
76
76
  end
@@ -6,4 +6,42 @@ module VirtualAuthenticatorTestHelper
6
6
  options.resident_key = true
7
7
  page.driver.browser.add_virtual_authenticator(options)
8
8
  end
9
+
10
+ def add_passkey_to_authenticator(authenticator, user)
11
+ add_credential_to_authenticator(authenticator, user, passkey: true)
12
+ end
13
+
14
+ def add_security_key_to_authenticator(authenticator, user)
15
+ add_credential_to_authenticator(authenticator, user, passkey: false)
16
+ end
17
+
18
+ def add_credential_to_authenticator(authenticator, user, passkey:)
19
+ credential_id = SecureRandom.random_bytes(16)
20
+ encoded_credential_id = Base64.urlsafe_encode64(credential_id)
21
+ key = OpenSSL::PKey.generate_key("ED25519")
22
+ encoded_private_key = Base64.urlsafe_encode64(key.private_to_der)
23
+
24
+ cose_public_key = COSE::Key::OKP.from_pkey(OpenSSL::PKey.read(key.public_to_der))
25
+ cose_public_key.alg = -8
26
+ encoded_cose_public_key = Base64.urlsafe_encode64(cose_public_key.serialize)
27
+
28
+ credential_json = {
29
+ "credentialId" => encoded_credential_id,
30
+ "isResidentCredential" => passkey,
31
+ "rpId" => "localhost",
32
+ "privateKey" => encoded_private_key,
33
+ "signCount" => 0
34
+ }
35
+ credential_json["userHandle"] = user.webauthn_id if passkey
36
+
37
+ authenticator.add_credential(credential_json)
38
+
39
+ user.webauthn_credentials.create!(
40
+ nickname: "My Credential",
41
+ external_id: Base64.urlsafe_encode64(credential_id, padding: false),
42
+ public_key: encoded_cose_public_key,
43
+ sign_count: 0,
44
+ authentication_factor: passkey ? :first_factor : :second_factor
45
+ )
46
+ end
9
47
  end
@@ -35,7 +35,7 @@ class PasskeysController < ApplicationController
35
35
  public_key: webauthn_credential.public_key,
36
36
  sign_count: webauthn_credential.sign_count
37
37
  )
38
- redirect_to root_path, notice: "Security Key registered successfully"
38
+ redirect_to root_path, notice: "Passkey registered successfully"
39
39
  else
40
40
  flash[:alert] = "Error registering credential"
41
41
  render :new
@@ -50,7 +50,7 @@ class PasskeysController < ApplicationController
50
50
  def destroy
51
51
  Current.user.passkeys.destroy(params[:id])
52
52
 
53
- redirect_to root_path, notice: "Security Key deleted successfully"
53
+ redirect_to root_path, notice: "Passkey deleted successfully"
54
54
  end
55
55
 
56
56
  private
@@ -32,7 +32,7 @@ class WebauthnAuthenticationGenerator < ::Rails::Generators::Base
32
32
  if File.exist?(File.join(destination_root, "app/controllers/sessions_controller.rb"))
33
33
  gsub_file "app/controllers/sessions_controller.rb",
34
34
  /^ def create.*?^ end/m,
35
- <<~RUBY.strip_heredoc.indent(2)
35
+ <<~RUBY.chomp.indent(2)
36
36
  def create
37
37
  if user = User.authenticate_by(params.permit(:email_address, :password))
38
38
  if user.second_factor_enabled?
@@ -1,5 +1,5 @@
1
1
  module Webauthn
2
2
  module Rails
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webauthn-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cedarcode
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-01 00:00:00.000000000 Z
11
+ date: 2025-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties