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 +4 -4
- data/lib/generators/erb/webauthn_authentication/templates/app/views/passkeys/new.html.erb.tt +2 -2
- data/lib/generators/test_unit/webauthn_authentication/templates/test/controllers/passkeys_controller_test.rb +1 -1
- data/lib/generators/test_unit/webauthn_authentication/templates/test/system/manage_webauthn_credentials_test.rb +30 -30
- data/lib/generators/test_unit/webauthn_authentication/templates/test/test_helpers/virtual_authenticator_test_helper.rb +38 -0
- data/lib/generators/webauthn_authentication/templates/app/controllers/passkeys_controller.rb +2 -2
- data/lib/generators/webauthn_authentication/webauthn_authentication_generator.rb +1 -1
- data/lib/webauthn/rails/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8425de86118ec096864312cfb7b4ef98947437da28d88cdc5f12b0a4191aea9
|
4
|
+
data.tar.gz: 43f56151976719e1bb00200b3134cdde63b6786f5afaf225c274982e324258fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d44fa7ccb7a3adc9248a74ab73f2758e0b3fb3fd4b7b70e98cb8956fac70c9c84b3eec954f39e4f261f26d8a4e3112bc4e4a289cab19542b2c11bbe4d4462d99
|
7
|
+
data.tar.gz: 784af4bb7538eccd87f50c4ce61d57ee8e3d92b823586c0c08c3c24718405b21d4258de6f599eca3e33b143a24ba1384fbc1365ec8e357186483dd708ef7686b
|
data/lib/generators/erb/webauthn_authentication/templates/app/views/passkeys/new.html.erb.tt
CHANGED
@@ -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, '
|
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
|
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 (/
|
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 "
|
18
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
34
|
+
assert_current_path root_path
|
35
|
+
# Add custom assertions based on your application's behavior
|
36
36
|
end
|
37
37
|
|
38
|
-
test "
|
39
|
-
|
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
|
-
|
48
|
-
|
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
|
-
|
51
|
-
|
50
|
+
test "sign in with existing 2FA WebAuthn credential" do
|
51
|
+
add_security_key_to_authenticator(@authenticator, @user)
|
52
52
|
|
53
|
-
|
54
|
-
fill_in "
|
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
|
-
|
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
|
-
|
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
|
data/lib/generators/webauthn_authentication/templates/app/controllers/passkeys_controller.rb
CHANGED
@@ -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: "
|
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: "
|
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.
|
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?
|
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.
|
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-
|
11
|
+
date: 2025-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|