web_authn 0.0.1 → 0.0.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/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
|
+
[](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
|