web_authn 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -3
- data/VERSION +1 -1
- data/lib/web_authn.rb +5 -0
- data/lib/web_authn/attestation_object.rb +2 -2
- data/lib/web_authn/attested_credential_data.rb +1 -1
- data/lib/web_authn/authenticator_data.rb +1 -1
- data/lib/web_authn/authenticator_data/flags.rb +7 -0
- data/lib/web_authn/context.rb +7 -3
- data/lib/web_authn/context/authentication.rb +6 -5
- data/samples/authentication_response.rb +3 -3
- data/samples/registration_response.rb +2 -2
- data/spec/authenticator_data/flags_spec.rb +45 -0
- data/spec/context/authentication_spec.rb +72 -0
- data/spec/context/registration_spec.rb +46 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/context_factory.rb +26 -0
- data/spec/web_authn_spec.rb +51 -2
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 648a6cc93f91835ee94c9c5d7efafd7ba788863d61a2e44efba388c4a45f066c
|
4
|
+
data.tar.gz: a0fa7c5a9848ec784ed62297131022223b6c6c43467532cb2ebb3fa71df706ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44f73a5564326062ce9614d3df2e3238fad34c0ce5ea8e4381a0ca81e541fb0a893670527f013c12f9698da077d946b140746972ad8718601fd1562bf7a99399
|
7
|
+
data.tar.gz: 1858d4cb4e878ba8ae0595689f307cb13a4b17e2b21e6baf1569f496d94b01cf0f486bf8758224c114a9c3052e1ac3e46210321718ea4ef9ed5c02db9b923e12
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# WebAuthn
|
2
2
|
|
3
|
-
|
3
|
+
W3C WebAuthn (a.k.a. FIDO2) RP library in Ruby
|
4
4
|
|
5
|
-
|
5
|
+
[![Build Status](https://secure.travis-ci.org/nov/web_authn.png)](http://travis-ci.org/nov/web_authn)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -22,7 +22,12 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
See samples for usage.
|
26
|
+
|
27
|
+
Currently, there are several restrictions.
|
28
|
+
* only `none` attestation format is supported.
|
29
|
+
* only EC key w/ `P-(256|384|521)` public key is supported.
|
30
|
+
* authenticator data w/ extensions aren't supported.
|
26
31
|
|
27
32
|
## Development
|
28
33
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/lib/web_authn.rb
CHANGED
@@ -6,6 +6,11 @@ require 'cose/key/ec2'
|
|
6
6
|
require 'json/jwt'
|
7
7
|
|
8
8
|
module WebAuthn
|
9
|
+
class Exception < StandardError; end
|
10
|
+
class InvalidContext < Exception; end
|
11
|
+
class InvalidAssertion < Exception; end
|
12
|
+
class NotImplementedError < NotImplementedError; end
|
13
|
+
|
9
14
|
module_function
|
10
15
|
|
11
16
|
def context_for(encoded_client_data_json, origin:, challenge:)
|
@@ -15,9 +15,9 @@ module WebAuthn
|
|
15
15
|
when 'none'
|
16
16
|
nil
|
17
17
|
when 'packed', 'tpm', 'android-key', 'android-safetynet', 'fido-u2f'
|
18
|
-
raise "Unsupported Attestation Format: #{attestation_object[:fmt]}"
|
18
|
+
raise NotImplementedError, "Unsupported Attestation Format: #{attestation_object[:fmt]}"
|
19
19
|
else
|
20
|
-
raise 'Unknown Attestation Format'
|
20
|
+
raise InvalidContext, 'Unknown Attestation Format'
|
21
21
|
end
|
22
22
|
self.authenticator_data = AuthenticatorData.decode attrs[:authData]
|
23
23
|
end
|
@@ -25,7 +25,7 @@ module WebAuthn
|
|
25
25
|
flags = Flags.decode(_flags_)
|
26
26
|
attested_credential_data = if flags.at?
|
27
27
|
if flags.ex?
|
28
|
-
raise 'Extension Data Not Supported Yet'
|
28
|
+
raise NotImplementedError, 'Extension Data Not Supported Yet'
|
29
29
|
else
|
30
30
|
AttestedCredentialData.decode auth_data.byteslice(37..-1)
|
31
31
|
end
|
data/lib/web_authn/context.rb
CHANGED
@@ -7,8 +7,12 @@ module WebAuthn
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def verify_session!(origin:, challenge:)
|
10
|
-
|
11
|
-
|
10
|
+
if client_data_json.origin != origin
|
11
|
+
raise InvalidContext, 'Invalid Origin'
|
12
|
+
end
|
13
|
+
if client_data_json.challenge != challenge
|
14
|
+
raise InvalidContext, 'Invalid Challenge'
|
15
|
+
end
|
12
16
|
self
|
13
17
|
end
|
14
18
|
|
@@ -30,7 +34,7 @@ module WebAuthn
|
|
30
34
|
when 'webauthn.get'
|
31
35
|
Authentication.new(client_data_json)
|
32
36
|
else
|
33
|
-
raise 'Unknown Client Data JSON Type'
|
37
|
+
raise InvalidContext, 'Unknown Client Data JSON Type'
|
34
38
|
end
|
35
39
|
|
36
40
|
context.verify_session!(origin: origin, challenge: challenge)
|
@@ -30,7 +30,7 @@ module WebAuthn
|
|
30
30
|
elsif before < current
|
31
31
|
self
|
32
32
|
else
|
33
|
-
raise 'Invalid Sign Count'
|
33
|
+
raise InvalidAssertion, 'Invalid Sign Count'
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -39,14 +39,15 @@ module WebAuthn
|
|
39
39
|
raw_authenticator_data,
|
40
40
|
OpenSSL::Digest::SHA256.digest(raw_client_data_json)
|
41
41
|
].join
|
42
|
-
result = public_key.
|
43
|
-
OpenSSL::Digest::SHA256.
|
44
|
-
Base64.urlsafe_decode64(signature)
|
42
|
+
result = public_key.verify(
|
43
|
+
OpenSSL::Digest::SHA256.new,
|
44
|
+
Base64.urlsafe_decode64(signature),
|
45
|
+
signature_base_string
|
45
46
|
)
|
46
47
|
if result
|
47
48
|
self
|
48
49
|
else
|
49
|
-
raise 'Invalid Signature'
|
50
|
+
raise InvalidAssertion, 'Invalid Signature'
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'web_authn'
|
2
2
|
|
3
|
-
authenticator_data = '
|
3
|
+
authenticator_data = 'MsuA3KzDw1JGLLAfO_4wLebzcS8w_SDs0Zw7pbhYlJUBAAAASg'
|
4
4
|
|
5
|
-
signature = '
|
6
|
-
sign_count =
|
5
|
+
signature = 'MEYCIQDmAVQcoMNRJiQZe9o5jJMnYvzza3nkDpnWdmdgKYBfwAIhAINDcFyIpIB8fql4QkllVXrQOkICfi595Gkn313gYG2r'
|
6
|
+
sign_count = 73
|
7
7
|
|
8
8
|
client_data_json = 'eyJjaGFsbGVuZ2UiOiJjbUZ1Wkc5dExYTjBjbWx1WnkxblpXNWxjbUYwWldRdFlua3RjbkF0YzJWeWRtVnkiLCJvcmlnaW4iOiJodHRwczovL3dlYi1hdXRobi5zZWxmLWlzc3VlZC5hcHAiLCJ0eXBlIjoid2ViYXV0aG4uZ2V0In0'
|
9
9
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'web_authn'
|
2
2
|
|
3
|
-
attestation_object = '
|
3
|
+
attestation_object = 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEMsuA3KzDw1JGLLAfO_4wLebzcS8w_SDs0Zw7pbhYlJVBAAAASQAAAAAAAAAAAAAAAAAAAAAAQA3sNJGmV3TJ2Y5pYDZP-DpZIku6rXhmhUZJ5kNNlaI3-4wwfhl296tAl52zStVDUsLVIm4_e4apQWUwl6eGnXalAQIDJiABIVggmQvMomjF0F3asbDWda13XeA1UbXdcS5j3Wg3G1LtgaMiWCBlNRc_WstNxVl56t6fVIJuVjMZqon1GpDp_UDDTXO7_g'
|
4
4
|
|
5
|
-
client_data_json = '
|
5
|
+
client_data_json = 'eyJjaGFsbGVuZ2UiOiJjbUZ1Wkc5dExYTjBjbWx1WnkxblpXNWxjbUYwWldRdFlua3RjbkF0YzJWeWRtVnkiLCJvcmlnaW4iOiJodHRwczovL3dlYi1hdXRobi5zZWxmLWlzc3VlZC5hcHAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0'
|
6
6
|
|
7
7
|
origin = 'https://web-authn.self-issued.app'
|
8
8
|
challenge = 'cmFuZG9tLXN0cmluZy1nZW5lcmF0ZWQtYnktcnAtc2VydmVy'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
RSpec.describe WebAuthn::AuthenticatorData::Flags do
|
2
|
+
describe '.decode' do
|
3
|
+
subject { described_class.decode [bits].pack('b*') }
|
4
|
+
|
5
|
+
describe 'when all false' do
|
6
|
+
let(:bits) { '00000000' }
|
7
|
+
its(:up?) { should == false }
|
8
|
+
its(:uv?) { should == false }
|
9
|
+
its(:at?) { should == false }
|
10
|
+
its(:ex?) { should == false }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'when up is on' do
|
14
|
+
let(:bits) { '10000000' }
|
15
|
+
its(:up?) { should == true }
|
16
|
+
its(:uv?) { should == false }
|
17
|
+
its(:at?) { should == false }
|
18
|
+
its(:ex?) { should == false }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'when uv is on' do
|
22
|
+
let(:bits) { '00100000' }
|
23
|
+
its(:up?) { should == false }
|
24
|
+
its(:uv?) { should == true }
|
25
|
+
its(:at?) { should == false }
|
26
|
+
its(:ex?) { should == false }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'when at is on' do
|
30
|
+
let(:bits) { '00000010' }
|
31
|
+
its(:up?) { should == false }
|
32
|
+
its(:uv?) { should == false }
|
33
|
+
its(:at?) { should == true }
|
34
|
+
its(:ex?) { should == false }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'when ex is on' do
|
38
|
+
let(:bits) { '00000001' }
|
39
|
+
its(:up?) { should == false }
|
40
|
+
its(:uv?) { should == false }
|
41
|
+
its(:at?) { should == false }
|
42
|
+
its(:ex?) { should == true }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
RSpec.describe WebAuthn::Context::Authentication do
|
2
|
+
let(:context_instance) do
|
3
|
+
WebAuthn.context_for(
|
4
|
+
client_data_json,
|
5
|
+
origin: origin,
|
6
|
+
challenge: challenge
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#verify!' do
|
11
|
+
let(:client_data_json) do
|
12
|
+
'eyJjaGFsbGVuZ2UiOiJjbUZ1Wkc5dExYTjBjbWx1WnkxblpXNWxjbUYwWldRdFlua3RjbkF0YzJWeWRtVnkiLCJvcmlnaW4iOiJodHRwczovL3dlYi1hdXRobi5zZWxmLWlzc3VlZC5hcHAiLCJ0eXBlIjoid2ViYXV0aG4uZ2V0In0'
|
13
|
+
end
|
14
|
+
let(:origin) { 'https://web-authn.self-issued.app' }
|
15
|
+
let(:challenge) { 'cmFuZG9tLXN0cmluZy1nZW5lcmF0ZWQtYnktcnAtc2VydmVy' }
|
16
|
+
let(:rp_id_hash) do
|
17
|
+
'MsuA3KzDw1JGLLAfO_4wLebzcS8w_SDs0Zw7pbhYlJU'
|
18
|
+
end
|
19
|
+
let(:flags) do
|
20
|
+
WebAuthn::AuthenticatorData::Flags.new(
|
21
|
+
up: true, uv: false, at: false, ex: false
|
22
|
+
)
|
23
|
+
end
|
24
|
+
let(:public_key) do
|
25
|
+
OpenSSL::PKey::EC.new <<~PEM
|
26
|
+
-----BEGIN PUBLIC KEY-----
|
27
|
+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMpNU/8TjYoyN8FlhZ+YsOMAvyfQ4
|
28
|
+
i6/JN0/DPXuZMoxLvdb1vjh7vPUt2Osw3Bq+0NZsx3U/8kmpFuwsZhTi9A==
|
29
|
+
-----END PUBLIC KEY-----
|
30
|
+
PEM
|
31
|
+
end
|
32
|
+
let(:sign_count) { 74 }
|
33
|
+
let(:signature) do
|
34
|
+
'MEYCIQDmAVQcoMNRJiQZe9o5jJMnYvzza3nkDpnWdmdgKYBfwAIhAINDcFyIpIB8fql4QkllVXrQOkICfi595Gkn313gYG2r'
|
35
|
+
end
|
36
|
+
let(:authenticator_data) do
|
37
|
+
'MsuA3KzDw1JGLLAfO_4wLebzcS8w_SDs0Zw7pbhYlJUBAAAASg'
|
38
|
+
end
|
39
|
+
subject do
|
40
|
+
context_instance.verify!(
|
41
|
+
authenticator_data,
|
42
|
+
public_key: public_key,
|
43
|
+
sign_count: sign_count - 1,
|
44
|
+
signature: signature
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
its(:rp_id_hash) { should == rp_id_hash }
|
49
|
+
its(:flags) { should == flags }
|
50
|
+
its(:sign_count) { should == sign_count }
|
51
|
+
|
52
|
+
context 'when sign count is invalid' do
|
53
|
+
let(:sign_count) { 75 }
|
54
|
+
it do
|
55
|
+
expect do
|
56
|
+
subject
|
57
|
+
end.to raise_error WebAuthn::InvalidAssertion, 'Invalid Sign Count'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when signature is invalid' do
|
62
|
+
let(:signature) do
|
63
|
+
'MEQCIB09d1yFCLxDUJdYIW3HwrZPsNqA1jwLqv_EqyN-xFpYAiAZ5h3RvpxCKvcbwQhqFdw2Chw5rmVD6aAZBNC9tJNmZw'
|
64
|
+
end
|
65
|
+
it do
|
66
|
+
expect do
|
67
|
+
subject
|
68
|
+
end.to raise_error WebAuthn::InvalidAssertion, 'Invalid Signature'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
RSpec.describe WebAuthn::Context::Registration do
|
2
|
+
let(:context) { registration_context }
|
3
|
+
let(:context_instance) do
|
4
|
+
WebAuthn.context_for(
|
5
|
+
client_data_json,
|
6
|
+
origin: context[:origin],
|
7
|
+
challenge: context[:challenge]
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#verify!' do
|
12
|
+
let(:credential_id) do
|
13
|
+
'Dew0kaZXdMnZjmlgNk_4OlkiS7qteGaFRknmQ02Vojf7jDB-GXb3q0CXnbNK1UNSwtUibj97hqlBZTCXp4addg'
|
14
|
+
end
|
15
|
+
let(:rp_id_hash) do
|
16
|
+
'MsuA3KzDw1JGLLAfO_4wLebzcS8w_SDs0Zw7pbhYlJU'
|
17
|
+
end
|
18
|
+
let(:flags) do
|
19
|
+
WebAuthn::AuthenticatorData::Flags.new(
|
20
|
+
up: true, uv: false, at: true, ex: false
|
21
|
+
)
|
22
|
+
end
|
23
|
+
let(:public_key_pem) do
|
24
|
+
<<~PEM
|
25
|
+
-----BEGIN PUBLIC KEY-----
|
26
|
+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmQvMomjF0F3asbDWda13XeA1UbXd
|
27
|
+
cS5j3Wg3G1LtgaNlNRc/WstNxVl56t6fVIJuVjMZqon1GpDp/UDDTXO7/g==
|
28
|
+
-----END PUBLIC KEY-----
|
29
|
+
PEM
|
30
|
+
end
|
31
|
+
let(:sign_count) { 73 }
|
32
|
+
let(:attestation_object) do
|
33
|
+
'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEMsuA3KzDw1JGLLAfO_4wLebzcS8w_SDs0Zw7pbhYlJVBAAAASQAAAAAAAAAAAAAAAAAAAAAAQA3sNJGmV3TJ2Y5pYDZP-DpZIku6rXhmhUZJ5kNNlaI3-4wwfhl296tAl52zStVDUsLVIm4_e4apQWUwl6eGnXalAQIDJiABIVggmQvMomjF0F3asbDWda13XeA1UbXdcS5j3Wg3G1LtgaMiWCBlNRc_WstNxVl56t6fVIJuVjMZqon1GpDp_UDDTXO7_g'
|
34
|
+
end
|
35
|
+
subject { context_instance.verify! attestation_object }
|
36
|
+
|
37
|
+
its(:credential_id) { should == credential_id }
|
38
|
+
its(:rp_id_hash) { should == rp_id_hash }
|
39
|
+
its(:flags) { should == flags }
|
40
|
+
its(:public_key) { should be_instance_of OpenSSL::PKey::EC }
|
41
|
+
its(:public_key_pem) do
|
42
|
+
subject.public_key.to_pem.should == public_key_pem
|
43
|
+
end
|
44
|
+
its(:sign_count) { should == sign_count }
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
module ContextFactory
|
2
|
+
extend RSpec::Core::SharedContext
|
3
|
+
|
4
|
+
let(:base_context) do
|
5
|
+
{
|
6
|
+
challenge: SecureRandom.hex(8),
|
7
|
+
origin: 'https://rp.example.com'
|
8
|
+
}
|
9
|
+
end
|
10
|
+
let(:registration_context) do
|
11
|
+
base_context.merge(type: 'webauthn.create')
|
12
|
+
end
|
13
|
+
let(:authentication_context) do
|
14
|
+
base_context.merge(type: 'webauthn.get')
|
15
|
+
end
|
16
|
+
let(:unknown_context) do
|
17
|
+
base_context
|
18
|
+
end
|
19
|
+
let(:client_data_json) do
|
20
|
+
Base64.urlsafe_encode64(context.to_json, padding: false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.include ContextFactory
|
26
|
+
end
|
data/spec/web_authn_spec.rb
CHANGED
@@ -1,5 +1,54 @@
|
|
1
1
|
RSpec.describe WebAuthn do
|
2
|
-
|
3
|
-
|
2
|
+
shared_examples_for :invalid_context do
|
3
|
+
it do
|
4
|
+
expect do
|
5
|
+
subject
|
6
|
+
end.to raise_error WebAuthn::InvalidContext
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
shared_examples_for :context_validator do
|
11
|
+
context 'when invalid origin' do
|
12
|
+
let(:origin) { 'https://other-rp.example.com' }
|
13
|
+
it_behaves_like :invalid_context
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when invalid challenge' do
|
17
|
+
let(:challenge) { SecureRandom.hex(8) }
|
18
|
+
it_behaves_like :invalid_context
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#context_for' do
|
23
|
+
let(:origin) { context[:origin] }
|
24
|
+
let(:challenge) { context[:challenge] }
|
25
|
+
subject do
|
26
|
+
described_class.context_for(
|
27
|
+
client_data_json,
|
28
|
+
origin: origin,
|
29
|
+
challenge: challenge,
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when registration context' do
|
34
|
+
let(:context) { registration_context }
|
35
|
+
it_behaves_like :context_validator
|
36
|
+
it { should be_instance_of WebAuthn::Context::Registration }
|
37
|
+
it { should be_registration }
|
38
|
+
it { should_not be_authentication }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when authentication context' do
|
42
|
+
let(:context) { authentication_context }
|
43
|
+
it_behaves_like :context_validator
|
44
|
+
it { should be_instance_of WebAuthn::Context::Authentication }
|
45
|
+
it { should_not be_registration }
|
46
|
+
it { should be_authentication }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when unknown context' do
|
50
|
+
let(:context) { unknown_context }
|
51
|
+
it_behaves_like :invalid_context
|
52
|
+
end
|
4
53
|
end
|
5
54
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web_authn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nov matake
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -149,7 +149,11 @@ files:
|
|
149
149
|
- samples/authentication_response.rb
|
150
150
|
- samples/concept.rb
|
151
151
|
- samples/registration_response.rb
|
152
|
+
- spec/authenticator_data/flags_spec.rb
|
153
|
+
- spec/context/authentication_spec.rb
|
154
|
+
- spec/context/registration_spec.rb
|
152
155
|
- spec/spec_helper.rb
|
156
|
+
- spec/support/context_factory.rb
|
153
157
|
- spec/web_authn_spec.rb
|
154
158
|
- web_authn.gemspec
|
155
159
|
homepage: https://github.com/nov/web_authn
|
@@ -177,5 +181,9 @@ signing_key:
|
|
177
181
|
specification_version: 4
|
178
182
|
summary: W3C WebAuthn (a.k.a. FIDO2) RP library in Ruby
|
179
183
|
test_files:
|
184
|
+
- spec/authenticator_data/flags_spec.rb
|
185
|
+
- spec/context/authentication_spec.rb
|
186
|
+
- spec/context/registration_spec.rb
|
180
187
|
- spec/spec_helper.rb
|
188
|
+
- spec/support/context_factory.rb
|
181
189
|
- spec/web_authn_spec.rb
|