fido_metadata 0.3.0 → 0.5.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: '08330439dce6050e6e099e11620382b947e17777a40744f72283a1be18a07c3e'
4
- data.tar.gz: 2377b8900e5593832e965d53c41cac920d23bc846eb0be698b42f8d499f0d976
3
+ metadata.gz: 1899edc776f8d77121b90f9487e5c4ed915aad1407899e32f28c6a209efcb287
4
+ data.tar.gz: ad903aaa648ad7591d69883cd1cf61dba63228c07f9256b02d29a6e9e0642b9d
5
5
  SHA512:
6
- metadata.gz: 1122f49d0fe46db1464763d37db667c09e7794b2acdac868effc6a5bac03c1ec9f38a6b2a4beb87b419f2f9028cd84021aaab6b858a8e645ff452c4c4b53f595
7
- data.tar.gz: c60c889a0e9c3088d27530be2fa9f3a97ead8dbbdf638d18909ed66d78431fc969548282b4b6a41e030b5160abd42f171860c455aabbf993ed4fa0faeaabe189
6
+ metadata.gz: 19da5080beafc9fefb641f15419f1753123254aaa947a2b70682e56d4a865e50f18eb42ab3df7f0b4c219355b142ef6d58d42d472399c833942679823e76472d
7
+ data.tar.gz: 3ca8419fb3cf241c63ec0e100e46559940b82efb54cbfa61369727e396b1bbf1d483193412fa2cb90ca97aa9c53fc98983efa6efa24d2f8d356c5510b4a0f8be
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on: push
4
+
5
+ jobs:
6
+ test:
7
+
8
+ runs-on: ubuntu-latest
9
+
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ ruby: ["2.5", "2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4"]
14
+ gemfile:
15
+ - jwt_2
16
+ - jwt_3
17
+
18
+ env:
19
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
20
+
21
+ steps:
22
+ - uses: actions/checkout@v5
23
+
24
+ - run: rm Gemfile.lock
25
+
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ bundler-cache: true # 'bundle install' and cache gems
30
+ ruby-version: ${{ matrix.ruby }}
31
+
32
+ - name: Run tests
33
+ run: bundle exec rspec
@@ -0,0 +1,18 @@
1
+ name: Lint
2
+
3
+ on: push
4
+
5
+ jobs:
6
+ lint:
7
+
8
+ runs-on: ubuntu-latest
9
+ name: Rubocop
10
+
11
+ steps:
12
+ - uses: actions/checkout@v5
13
+ - name: Set up Ruby
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ bundler-cache: true # 'bundle install' and cache gems
17
+ - name: Run Rubocop
18
+ run: bundle exec rubocop
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /gemfiles/*.gemfile.lock
data/.rubocop.yml CHANGED
@@ -7,6 +7,7 @@ AllCops:
7
7
  DisabledByDefault: true
8
8
  Exclude:
9
9
  - "gemfiles/**/*"
10
+ - "vendor/**/*"
10
11
 
11
12
  Bundler:
12
13
  Enabled: true
@@ -20,7 +21,7 @@ Layout:
20
21
  Lint:
21
22
  Enabled: true
22
23
 
23
- Metrics/LineLength:
24
+ Layout/LineLength:
24
25
  Max: 120
25
26
 
26
27
  Naming:
@@ -32,9 +33,6 @@ Security:
32
33
  Style/BlockComments:
33
34
  Enabled: true
34
35
 
35
- Style/BracesAroundHashParameters:
36
- Enabled: true
37
-
38
36
  Style/CaseEquality:
39
37
  Enabled: true
40
38
 
@@ -180,10 +178,10 @@ Style/TrailingMethodEndStatement:
180
178
  Style/TrivialAccessors:
181
179
  Enabled: true
182
180
 
183
- Style/UnneededInterpolation:
181
+ Style/RedundantInterpolation:
184
182
  Enabled: true
185
183
 
186
- Style/UnneededPercentQ:
184
+ Style/RedundantPercentQ:
187
185
  Enabled: true
188
186
 
189
187
  Style/UnpackFirst:
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.5
data/Appraisals ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise "jwt_2" do
4
+ gem "jwt", "~> 2"
5
+ end
6
+
7
+ appraise "jwt_3" do
8
+ gem "jwt", "~> 3"
9
+ end
data/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.0] - 2025-09-12
10
+ ### Added
11
+ - Add support for FIDO MDS v3. ([#10](https://github.com/cedarcode/fido_metadata/pull/10))
12
+ - Follow HTTP 302 redirects when downloading CRLs. ([#14](https://github.com/cedarcode/fido_metadata/pull/14))
13
+
14
+ ### Changed
15
+ - Update `jwt` dependency to support both v2 and v3. ([#23](https://github.com/cedarcode/fido_metadata/pull/23))
16
+
17
+ ## [0.4.0] - 2019-12-28
18
+ ### Added
19
+ - Set `expires_in` and `race_condition_ttl` options during caching.
20
+
9
21
  ## [0.3.0] - 2019-11-24
10
22
  ### Changed
11
23
  - Made `FidoMetada::TestCacheStore` available for gem users. It is not required by default.
@@ -25,7 +37,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
25
37
  ### Added
26
38
  - Extracted from [webauthn-ruby PR 208](https://github.com/cedarcode/webauthn-ruby/pull/208) after discussion with the maintainers. Thanks for the feedback @grzuy and @brauliomartinezlm!
27
39
 
28
- [Unreleased]: https://github.com/bdewater/fido_metadata/compare/v0.2.0...HEAD
29
- [0.3.0]: https://github.com/bdewater/fido_metadata/compare/v0.2.0...v0.3.0
30
- [0.2.0]: https://github.com/bdewater/fido_metadata/compare/v0.1.0...v0.2.0
31
- [0.1.0]: https://github.com/bdewater/fido_metadata/releases/tag/v0.1.0
40
+ [Unreleased]: https://github.com/cedarcode/fido_metadata/compare/v0.5.0...HEAD
41
+ [0.5.0]: https://github.com/cedarcode/fido_metadata/compare/v0.4.0...v0.5.0
42
+ [0.4.0]: https://github.com/cedarcode/fido_metadata/compare/v0.3.0...v0.4.0
43
+ [0.3.0]: https://github.com/cedarcode/fido_metadata/compare/v0.2.0...v0.3.0
44
+ [0.2.0]: https://github.com/cedarcode/fido_metadata/compare/v0.1.0...v0.2.0
45
+ [0.1.0]: https://github.com/cedarcode/fido_metadata/releases/tag/v0.1.0
data/Gemfile CHANGED
@@ -6,3 +6,9 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
7
  # Specify your gem's dependencies in fido_metadata.gemspec
8
8
  gemspec
9
+
10
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
11
+ gem "rubocop", "~> 1.80", require: false
12
+ end
13
+
14
+ gem "appraisal", "~> 2.5"
data/Gemfile.lock CHANGED
@@ -1,61 +1,77 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fido_metadata (0.3.0)
5
- jwt (~> 2.0)
4
+ fido_metadata (0.5.0)
5
+ base64 (>= 0.1.0)
6
+ jwt (>= 2.0, < 4)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
- addressable (2.7.0)
11
- public_suffix (>= 2.0.2, < 5.0)
12
- ast (2.4.0)
13
- byebug (11.0.1)
14
- coderay (1.1.2)
15
- crack (0.4.3)
16
- safe_yaml (~> 1.0.0)
17
- diff-lcs (1.3)
18
- hashdiff (1.0.0)
19
- jaro_winkler (1.5.4)
20
- jwt (2.2.1)
21
- method_source (0.9.2)
22
- parallel (1.18.0)
23
- parser (2.6.5.0)
24
- ast (~> 2.4.0)
25
- pry (0.12.2)
26
- coderay (~> 1.1.0)
27
- method_source (~> 0.9.0)
28
- pry-byebug (3.7.0)
29
- byebug (~> 11.0)
30
- pry (~> 0.10)
31
- public_suffix (4.0.1)
32
- rainbow (3.0.0)
33
- rake (10.5.0)
34
- rspec (3.9.0)
35
- rspec-core (~> 3.9.0)
36
- rspec-expectations (~> 3.9.0)
37
- rspec-mocks (~> 3.9.0)
38
- rspec-core (3.9.0)
39
- rspec-support (~> 3.9.0)
40
- rspec-expectations (3.9.0)
11
+ addressable (2.8.7)
12
+ public_suffix (>= 2.0.2, < 7.0)
13
+ appraisal (2.5.0)
14
+ bundler
15
+ rake
16
+ thor (>= 0.14.0)
17
+ ast (2.4.3)
18
+ base64 (0.3.0)
19
+ bigdecimal (3.2.2)
20
+ crack (1.0.0)
21
+ bigdecimal
22
+ rexml
23
+ diff-lcs (1.6.2)
24
+ hashdiff (1.2.0)
25
+ json (2.13.2)
26
+ jwt (3.1.2)
27
+ base64
28
+ language_server-protocol (3.17.0.5)
29
+ lint_roller (1.1.0)
30
+ parallel (1.27.0)
31
+ parser (3.3.9.0)
32
+ ast (~> 2.4.1)
33
+ racc
34
+ prism (1.4.0)
35
+ public_suffix (6.0.2)
36
+ racc (1.8.1)
37
+ rainbow (3.1.1)
38
+ rake (13.3.0)
39
+ regexp_parser (2.11.2)
40
+ rexml (3.4.2)
41
+ rspec (3.13.1)
42
+ rspec-core (~> 3.13.0)
43
+ rspec-expectations (~> 3.13.0)
44
+ rspec-mocks (~> 3.13.0)
45
+ rspec-core (3.13.5)
46
+ rspec-support (~> 3.13.0)
47
+ rspec-expectations (3.13.5)
41
48
  diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.9.0)
43
- rspec-mocks (3.9.0)
49
+ rspec-support (~> 3.13.0)
50
+ rspec-mocks (3.13.5)
44
51
  diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.9.0)
46
- rspec-support (3.9.0)
47
- rubocop (0.75.0)
48
- jaro_winkler (~> 1.5.1)
52
+ rspec-support (~> 3.13.0)
53
+ rspec-support (3.13.5)
54
+ rubocop (1.80.1)
55
+ json (~> 2.3)
56
+ language_server-protocol (~> 3.17.0.2)
57
+ lint_roller (~> 1.1.0)
49
58
  parallel (~> 1.10)
50
- parser (>= 2.6)
59
+ parser (>= 3.3.0.2)
51
60
  rainbow (>= 2.2.2, < 4.0)
61
+ regexp_parser (>= 2.9.3, < 3.0)
62
+ rubocop-ast (>= 1.46.0, < 2.0)
52
63
  ruby-progressbar (~> 1.7)
53
- unicode-display_width (>= 1.4.0, < 1.7)
54
- ruby-progressbar (1.10.1)
55
- safe_yaml (1.0.5)
56
- unicode-display_width (1.6.0)
57
- webmock (3.7.6)
58
- addressable (>= 2.3.6)
64
+ unicode-display_width (>= 2.4.0, < 4.0)
65
+ rubocop-ast (1.46.0)
66
+ parser (>= 3.3.7.2)
67
+ prism (~> 1.4)
68
+ ruby-progressbar (1.13.0)
69
+ thor (1.4.0)
70
+ unicode-display_width (3.1.5)
71
+ unicode-emoji (~> 4.0, >= 4.0.4)
72
+ unicode-emoji (4.0.4)
73
+ webmock (3.25.1)
74
+ addressable (>= 2.8.0)
59
75
  crack (>= 0.3.2)
60
76
  hashdiff (>= 0.4.0, < 2.0.0)
61
77
 
@@ -63,13 +79,12 @@ PLATFORMS
63
79
  ruby
64
80
 
65
81
  DEPENDENCIES
66
- bundler (~> 1.17)
82
+ appraisal (~> 2.5)
67
83
  fido_metadata!
68
- pry-byebug
69
- rake (~> 10.0)
84
+ rake (~> 13.0)
70
85
  rspec (~> 3.8)
71
- rubocop (= 0.75.0)
86
+ rubocop (~> 1.80)
72
87
  webmock (~> 3.6)
73
88
 
74
89
  BUNDLED WITH
75
- 1.17.3
90
+ 2.7.1
data/README.md CHANGED
@@ -26,7 +26,6 @@ First, you need to [register for an access token](https://mds2.fidoalliance.org/
26
26
  The cache interface is compatible with Rails' [`ActiveSupport::Cache::Store`](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html), which means you can configure the gem to use your existing cache or a separate one:
27
27
  ```ruby
28
28
  FidoMetadata.configure do |config|
29
- config.metadata_token = "your token"
30
29
  config.cache_backend = Rails.cache # or something like `ActiveSupport::Cache::FileStore.new(...)`
31
30
  end
32
31
  ```
data/Rakefile CHANGED
@@ -1,12 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- require "rake/testtask"
4
+ require "rspec/core/rake_task"
5
5
 
6
- Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
10
- end
6
+ RSpec::Core::RakeTask.new(:spec)
11
7
 
12
- task default: :test
8
+ task default: :spec
data/bin/console CHANGED
@@ -7,18 +7,10 @@ require "fido_metadata"
7
7
  # Configure in-memory cache
8
8
  require "fido_metadata/test_cache_store"
9
9
  FidoMetadata.configure do |config|
10
- config.metadata_token = ENV["MDS_TOKEN"]
11
10
  config.cache_backend = FidoMetadata::TestCacheStore.new
12
11
  end
13
12
 
14
- unless FidoMetadata.configuration.metadata_token
15
- puts <<~TOKEN_HINT
16
- No MDS token configured via the MDS_TOKEN environment variable.
17
- Set one for this session: FidoMetadata.configuration.metadata_token = 'your token'
18
- TOKEN_HINT
19
- end
20
13
  puts "Reset the cache via: FidoMetadata.configuration.cache_backend.clear"
21
14
 
22
15
  # Start REPL
23
- require "pry-byebug"
24
16
  Pry.start
@@ -31,11 +31,9 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.required_ruby_version = ">= 2.3"
33
33
 
34
- spec.add_dependency "jwt", "~> 2.0"
35
- spec.add_development_dependency "bundler", "~> 1.17"
36
- spec.add_development_dependency "pry-byebug"
37
- spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_dependency "base64", ">= 0.1.0"
35
+ spec.add_dependency "jwt", ">= 2.0", "< 4"
36
+ spec.add_development_dependency "rake", "~> 13.0"
38
37
  spec.add_development_dependency "rspec", "~> 3.8"
39
- spec.add_development_dependency "rubocop", "0.75.0"
40
38
  spec.add_development_dependency "webmock", "~> 3.6"
41
39
  end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.5"
6
+ gem "jwt", "~> 2"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.5"
6
+ gem "jwt", "~> 3"
7
+
8
+ gemspec path: "../"
data/lib/Root.cer CHANGED
@@ -1,15 +1,21 @@
1
1
  -----BEGIN CERTIFICATE-----
2
- MIICQzCCAcigAwIBAgIORqmxkzowRM99NQZJurcwCgYIKoZIzj0EAwMwUzELMAkG
3
- A1UEBhMCVVMxFjAUBgNVBAoTDUZJRE8gQWxsaWFuY2UxHTAbBgNVBAsTFE1ldGFk
4
- YXRhIFRPQyBTaWduaW5nMQ0wCwYDVQQDEwRSb290MB4XDTE1MDYxNzAwMDAwMFoX
5
- DTQ1MDYxNzAwMDAwMFowUzELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUZJRE8gQWxs
6
- aWFuY2UxHTAbBgNVBAsTFE1ldGFkYXRhIFRPQyBTaWduaW5nMQ0wCwYDVQQDEwRS
7
- b290MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEFEoo+6jdxg6oUuOloqPjK/nVGyY+
8
- AXCFz1i5JR4OPeFJs+my143ai0p34EX4R1Xxm9xGi9n8F+RxLjLNPHtlkB3X4ims
9
- rfIx7QcEImx1cMTgu5zUiwxLX1ookVhIRSoso2MwYTAOBgNVHQ8BAf8EBAMCAQYw
10
- DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU0qUfC6f2YshA1Ni9udeO0VS7vEYw
11
- HwYDVR0jBBgwFoAU0qUfC6f2YshA1Ni9udeO0VS7vEYwCgYIKoZIzj0EAwMDaQAw
12
- ZgIxAKulGbSFkDSZusGjbNkAhAkqTkLWo3GrN5nRBNNk2Q4BlG+AvM5q9wa5WciW
13
- DcMdeQIxAMOEzOFsxX9Bo0h4LOFE5y5H8bdPFYW+l5gy1tQiJv+5NUyM2IBB55XU
14
- YjdBz56jSA==
2
+ MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
3
+ A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
4
+ Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
5
+ MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
6
+ A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
7
+ hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
8
+ RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
9
+ gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
10
+ KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
11
+ QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
12
+ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
13
+ DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
14
+ LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
15
+ RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
16
+ jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
17
+ 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
18
+ mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
19
+ Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
20
+ WD9f
15
21
  -----END CERTIFICATE-----
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fido_metadata/attributes"
4
+
5
+ module FidoMetadata
6
+ class AuthenticatorGetInfo
7
+ extend Attributes
8
+
9
+ json_accessor("versions")
10
+ json_accessor("extensions")
11
+ json_accessor("aaguid")
12
+ json_accessor("options")
13
+ json_accessor("maxMsgSize")
14
+ json_accessor("pinUvAuthProtocols")
15
+ json_accessor("maxCredentialCountInList")
16
+ json_accessor("maxCredentialIdLength")
17
+ json_accessor("transports")
18
+ json_accessor("algorithms")
19
+ json_accessor("maxSerializedLargeBlobArray")
20
+ json_accessor("forcePINChange")
21
+ json_accessor("minPINLength")
22
+ json_accessor("firmwareVersion")
23
+ json_accessor("maxCredBlobLength")
24
+ json_accessor("maxRPIDsForSetMinPINLength")
25
+ json_accessor("preferredPlatformUvAttempts")
26
+ json_accessor("uvModality")
27
+ json_accessor("certifications")
28
+ json_accessor("remainingDiscoverableCredentials")
29
+ json_accessor("vendorPrototypeConfigCommands")
30
+ end
31
+ end
@@ -23,13 +23,9 @@ module FidoMetadata
23
23
  File.read(File.join(__dir__, "..", "Root.cer"))
24
24
  )].freeze
25
25
 
26
- def initialize(token)
27
- @token = token
28
- end
29
-
30
- def download_toc(uri, trusted_certs: FIDO_ROOT_CERTIFICATES)
31
- response = get_with_token(uri)
32
- payload, _ = JWT.decode(response, nil, true, algorithms: ["ES256"]) do |headers|
26
+ def download_toc(uri, algorithms: ["RS256"], trusted_certs: FIDO_ROOT_CERTIFICATES)
27
+ response = get(uri)
28
+ payload, _ = JWT.decode(response, nil, true, algorithms: algorithms) do |headers|
33
29
  jwt_certificates = headers["x5c"].map do |encoded|
34
30
  OpenSSL::X509::Certificate.new(Base64.strict_decode64(encoded))
35
31
  end
@@ -44,43 +40,26 @@ module FidoMetadata
44
40
  payload
45
41
  end
46
42
 
47
- def download_entry(uri, expected_hash:)
48
- response = get_with_token(uri)
49
- decoded_hash = Base64.urlsafe_decode64(expected_hash)
50
- unless OpenSSL.fixed_length_secure_compare(OpenSSL::Digest::SHA256.digest(response), decoded_hash)
51
- raise(InvalidHashError)
52
- end
53
-
54
- decoded_body = Base64.urlsafe_decode64(response)
55
- JSON.parse(decoded_body)
56
- end
57
-
58
43
  private
59
44
 
60
- def get_with_token(uri)
61
- if @token && !@token.empty?
62
- uri.path += "/" unless uri.path.end_with?("/")
63
- uri.query = "token=#{@token}"
64
- end
65
- get(uri)
66
- end
67
-
68
45
  def get(uri)
69
46
  get = Net::HTTP::Get.new(uri, DEFAULT_HEADERS)
70
47
  response = http(uri).request(get)
71
48
  response.value
72
49
  response.body
50
+ rescue Net::HTTPRetriableError => e
51
+ if e.response.is_a? Net::HTTPResponse
52
+ get(URI(e.response["location"]))
53
+ end
73
54
  end
74
55
 
75
56
  def http(uri)
76
- @http ||= begin
77
- http = Net::HTTP.new(uri.host, uri.port)
78
- http.use_ssl = uri.port == 443
79
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
80
- http.open_timeout = 5
81
- http.read_timeout = 5
82
- http
83
- end
57
+ http = Net::HTTP.new(uri.host, uri.port)
58
+ http.use_ssl = uri.port == 443
59
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
60
+ http.open_timeout = 5
61
+ http.read_timeout = 5
62
+ http
84
63
  end
85
64
 
86
65
  def download_crls(certificates)
@@ -89,7 +68,7 @@ module FidoMetadata
89
68
  crls = uris.compact.uniq.map do |uri|
90
69
  begin
91
70
  get(uri)
92
- rescue Net::ProtoServerError
71
+ rescue Net::ProtocolError
93
72
  # TODO: figure out why test endpoint specifies a missing and unused CRL in the cert chain, and see if this
94
73
  # rescue can be removed. If the CRL is used, OpenSSL error 3 (unable to get certificate CRL) will raise.
95
74
  nil
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fido_metadata/authenticator_get_info"
4
+
5
+ module FidoMetadata
6
+ module Coercer
7
+ module AuthenticatorGetInfo
8
+ def self.coerce(value)
9
+ return value if value.is_a?(FidoMetadata::AuthenticatorGetInfo)
10
+
11
+ FidoMetadata::AuthenticatorGetInfo.from_json(value) if value
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fido_metadata/statement"
4
+
5
+ module FidoMetadata
6
+ module Coercer
7
+ module Statement
8
+ def self.coerce(value)
9
+ return value if value.is_a?(FidoMetadata::Statement)
10
+
11
+ FidoMetadata::Statement.from_json(value) if value
12
+ end
13
+ end
14
+ end
15
+ end
@@ -6,6 +6,7 @@ require "fido_metadata/status_report"
6
6
  require "fido_metadata/coercer/date"
7
7
  require "fido_metadata/coercer/escaped_uri"
8
8
  require "fido_metadata/coercer/objects"
9
+ require "fido_metadata/coercer/statement"
9
10
 
10
11
  module FidoMetadata
11
12
  class Entry
@@ -21,5 +22,6 @@ module FidoMetadata
21
22
  json_accessor("timeOfLastStatusChange", Coercer::Date)
22
23
  json_accessor("rogueListURL", Coercer::EscapedURI)
23
24
  json_accessor("rogueListHash")
25
+ json_accessor("metadataStatement", Coercer::Statement)
24
26
  end
25
27
  end
@@ -7,7 +7,7 @@ module FidoMetadata
7
7
  module FixedLengthSecureCompare
8
8
  unless OpenSSL.singleton_class.method_defined?(:fixed_length_secure_compare)
9
9
  refine OpenSSL.singleton_class do
10
- def fixed_length_secure_compare(a, b) # rubocop:disable Naming/UncommunicativeMethodParamName
10
+ def fixed_length_secure_compare(a, b) # rubocop:disable Naming/MethodParameterName
11
11
  raise ArgumentError, "inputs must be of equal length" unless a.bytesize == b.bytesize
12
12
 
13
13
  # borrowed from Rack::Utils
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fido_metadata/attributes"
4
- require "fido_metadata/constants"
5
4
  require "fido_metadata/verification_method_descriptor"
6
5
  require "fido_metadata/coercer/assumed_value"
7
6
  require "fido_metadata/coercer/bit_field"
8
7
  require "fido_metadata/coercer/certificates"
9
8
  require "fido_metadata/coercer/magic_number"
10
9
  require "fido_metadata/coercer/user_verification_details"
10
+ require "fido_metadata/coercer/authenticator_get_info"
11
11
 
12
12
  module FidoMetadata
13
13
  class Statement
@@ -22,31 +22,25 @@ module FidoMetadata
22
22
  json_accessor("authenticatorVersion")
23
23
  json_accessor("protocolFamily", Coercer::AssumedValue.new("uaf"))
24
24
  json_accessor("upv")
25
- json_accessor("assertionScheme")
26
- json_accessor("authenticationAlgorithm", Coercer::MagicNumber.new(Constants::AUTHENTICATION_ALGORITHMS))
27
- json_accessor("authenticationAlgorithms",
28
- Coercer::MagicNumber.new(Constants::AUTHENTICATION_ALGORITHMS, array: true))
29
- json_accessor("publicKeyAlgAndEncoding", Coercer::MagicNumber.new(Constants::PUBLIC_KEY_FORMATS))
30
- json_accessor("publicKeyAlgAndEncodings",
31
- Coercer::MagicNumber.new(Constants::PUBLIC_KEY_FORMATS, array: true))
32
- json_accessor("attestationTypes", Coercer::MagicNumber.new(Constants::ATTESTATION_TYPES, array: true))
25
+ json_accessor("authenticationAlgorithms")
26
+ json_accessor("publicKeyAlgAndEncodings")
27
+ json_accessor("attestationTypes")
33
28
  json_accessor("userVerificationDetails", Coercer::UserVerificationDetails)
34
- json_accessor("keyProtection", Coercer::BitField.new(Constants::KEY_PROTECTION_TYPES))
29
+ json_accessor("keyProtection")
35
30
  json_accessor("isKeyRestricted", Coercer::AssumedValue.new(true))
36
31
  json_accessor("isFreshUserVerificationRequired", Coercer::AssumedValue.new(true))
37
- json_accessor("matcherProtection",
38
- Coercer::BitField.new(Constants::MATCHER_PROTECTION_TYPES, single_value: true))
32
+ json_accessor("matcherProtection")
39
33
  json_accessor("cryptoStrength")
40
- json_accessor("operatingEnv")
41
- json_accessor("attachmentHint", Coercer::BitField.new(Constants::ATTACHMENT_HINTS))
42
- json_accessor("isSecondFactorOnly")
43
- json_accessor("tcDisplay", Coercer::BitField.new(Constants::TRANSACTION_CONFIRMATION_DISPLAY_TYPES))
34
+ json_accessor("attachmentHint")
35
+ json_accessor("tcDisplay")
44
36
  json_accessor("tcDisplayContentType")
45
37
  json_accessor("tcDisplayPNGCharacteristics")
46
38
  json_accessor("attestationRootCertificates")
47
39
  json_accessor("ecdaaTrustAnchors")
48
40
  json_accessor("icon")
49
41
  json_accessor("supportedExtensions")
42
+ json_accessor("schema")
43
+ json_accessor("authenticatorGetInfo", Coercer::AuthenticatorGetInfo)
50
44
 
51
45
  # Lazy load certificates for compatibility ActiveSupport::Cache. Can be removed once we require a version of
52
46
  # OpenSSL which includes https://github.com/ruby/openssl/pull/281
@@ -6,17 +6,19 @@ require "fido_metadata/statement"
6
6
 
7
7
  module FidoMetadata
8
8
  class Store
9
- METADATA_ENDPOINT = URI("https://mds2.fidoalliance.org/")
9
+ METADATA_ENDPOINT = URI("https://mds.fidoalliance.org/")
10
+ TOC_CACHE_KEY = "metadata_toc"
11
+ STATEMENT_CACHE_KEY = "statement_%s"
10
12
 
11
13
  def table_of_contents
12
14
  @table_of_contents ||= begin
13
- key = "metadata_toc"
15
+ key = TOC_CACHE_KEY
14
16
  toc = cache_backend.read(key)
15
17
  return toc if toc
16
18
 
17
19
  json = client.download_toc(METADATA_ENDPOINT)
18
20
  toc = FidoMetadata::TableOfContents.from_json(json)
19
- cache_backend.write(key, toc)
21
+ cache_backend.write(key, toc, expires_in: toc.expires_in, race_condition_ttl: race_condition_ttl)
20
22
  toc
21
23
  end
22
24
  end
@@ -38,7 +40,7 @@ module FidoMetadata
38
40
  def fetch_statement(aaguid: nil, attestation_certificate_key_id: nil)
39
41
  verify_arguments(aaguid: aaguid, attestation_certificate_key_id: attestation_certificate_key_id)
40
42
 
41
- key = "statement_#{aaguid || attestation_certificate_key_id}"
43
+ key = STATEMENT_CACHE_KEY % (aaguid || attestation_certificate_key_id)
42
44
  statement = cache_backend.read(key)
43
45
  return statement if statement
44
46
 
@@ -49,9 +51,13 @@ module FidoMetadata
49
51
  end
50
52
  return unless entry
51
53
 
52
- json = client.download_entry(entry.url, expected_hash: entry.hash)
53
- statement = FidoMetadata::Statement.from_json(json)
54
- cache_backend.write(key, statement)
54
+ statement = entry.metadata_statement
55
+ cache_backend.write(
56
+ key,
57
+ statement,
58
+ expires_in: table_of_contents.expires_in,
59
+ race_condition_ttl: race_condition_ttl
60
+ )
55
61
  statement
56
62
  end
57
63
 
@@ -71,12 +77,12 @@ module FidoMetadata
71
77
  FidoMetadata.configuration.cache_backend || raise("no cache_backend configured")
72
78
  end
73
79
 
74
- def metadata_token
75
- FidoMetadata.configuration.metadata_token || raise("no metadata_token configured")
80
+ def race_condition_ttl
81
+ FidoMetadata.configuration.race_condition_ttl
76
82
  end
77
83
 
78
84
  def client
79
- @client ||= FidoMetadata::Client.new(metadata_token)
85
+ @client ||= FidoMetadata::Client.new
80
86
  end
81
87
  end
82
88
  end
@@ -13,5 +13,9 @@ module FidoMetadata
13
13
  json_accessor("nextUpdate", Coercer::Date)
14
14
  json_accessor("entries", Coercer::Objects.new(Entry))
15
15
  json_accessor("no")
16
+
17
+ def expires_in
18
+ next_update.to_time.to_i - Time.now.to_i
19
+ end
16
20
  end
17
21
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "fido_metadata/attributes"
4
4
  require "fido_metadata/biometric_accuracy_descriptor"
5
- require "fido_metadata/constants"
6
5
  require "fido_metadata/code_accuracy_descriptor"
7
6
  require "fido_metadata/pattern_accuracy_descriptor"
8
7
  require "fido_metadata/coercer/magic_number"
@@ -12,7 +11,7 @@ module FidoMetadata
12
11
  class VerificationMethodDescriptor
13
12
  extend Attributes
14
13
 
15
- json_accessor("userVerification", Coercer::MagicNumber.new(Constants::USER_VERIFICATION_METHODS))
14
+ json_accessor("userVerificationMethod")
16
15
  json_accessor("caDesc")
17
16
  json_accessor("baDesc")
18
17
  json_accessor("paDesc")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FidoMetadata
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/fido_metadata.rb CHANGED
@@ -5,7 +5,11 @@ require "fido_metadata/version"
5
5
 
6
6
  module FidoMetadata
7
7
  def self.configuration
8
- @configuration ||= Configuration.new
8
+ @configuration ||= begin
9
+ c = Configuration.new
10
+ c.race_condition_ttl = 1
11
+ c
12
+ end
9
13
  end
10
14
 
11
15
  def self.configure
@@ -13,7 +17,7 @@ module FidoMetadata
13
17
  end
14
18
 
15
19
  class Configuration
16
- attr_accessor :metadata_token
17
20
  attr_accessor :cache_backend
21
+ attr_accessor :race_condition_ttl
18
22
  end
19
23
  end
metadata CHANGED
@@ -1,71 +1,63 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fido_metadata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart de Water
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-24 00:00:00.000000000 Z
11
+ date: 2025-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: jwt
14
+ name: base64
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: 0.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.17'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
24
+ - - ">="
39
25
  - !ruby/object:Gem::Version
40
- version: '1.17'
26
+ version: 0.1.0
41
27
  - !ruby/object:Gem::Dependency
42
- name: pry-byebug
28
+ name: jwt
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
46
32
  - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
33
+ version: '2.0'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '4'
37
+ type: :runtime
49
38
  prerelease: false
50
39
  version_requirements: !ruby/object:Gem::Requirement
51
40
  requirements:
52
41
  - - ">="
53
42
  - !ruby/object:Gem::Version
54
- version: '0'
43
+ version: '2.0'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '4'
55
47
  - !ruby/object:Gem::Dependency
56
48
  name: rake
57
49
  requirement: !ruby/object:Gem::Requirement
58
50
  requirements:
59
51
  - - "~>"
60
52
  - !ruby/object:Gem::Version
61
- version: '10.0'
53
+ version: '13.0'
62
54
  type: :development
63
55
  prerelease: false
64
56
  version_requirements: !ruby/object:Gem::Requirement
65
57
  requirements:
66
58
  - - "~>"
67
59
  - !ruby/object:Gem::Version
68
- version: '10.0'
60
+ version: '13.0'
69
61
  - !ruby/object:Gem::Dependency
70
62
  name: rspec
71
63
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +72,6 @@ dependencies:
80
72
  - - "~>"
81
73
  - !ruby/object:Gem::Version
82
74
  version: '3.8'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - '='
88
- - !ruby/object:Gem::Version
89
- version: 0.75.0
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - '='
95
- - !ruby/object:Gem::Version
96
- version: 0.75.0
97
75
  - !ruby/object:Gem::Dependency
98
76
  name: webmock
99
77
  requirement: !ruby/object:Gem::Requirement
@@ -110,14 +88,18 @@ dependencies:
110
88
  version: '3.6'
111
89
  description: Client for looking up metadata about FIDO authenticators, for use by
112
90
  WebAuthn relying parties
113
- email:
91
+ email:
114
92
  executables: []
115
93
  extensions: []
116
94
  extra_rdoc_files: []
117
95
  files:
96
+ - ".github/dependabot.yml"
97
+ - ".github/workflows/ci.yml"
98
+ - ".github/workflows/lint.yml"
118
99
  - ".gitignore"
119
100
  - ".rubocop.yml"
120
- - ".travis.yml"
101
+ - ".ruby-version"
102
+ - Appraisals
121
103
  - CHANGELOG.md
122
104
  - CODE_OF_CONDUCT.md
123
105
  - Gemfile
@@ -130,22 +112,26 @@ files:
130
112
  - bin/rubocop
131
113
  - bin/setup
132
114
  - fido_metadata.gemspec
115
+ - gemfiles/jwt_2.gemfile
116
+ - gemfiles/jwt_3.gemfile
133
117
  - lib/Root.cer
134
118
  - lib/fido_metadata.rb
135
119
  - lib/fido_metadata/attributes.rb
120
+ - lib/fido_metadata/authenticator_get_info.rb
136
121
  - lib/fido_metadata/biometric_accuracy_descriptor.rb
137
122
  - lib/fido_metadata/biometric_status_report.rb
138
123
  - lib/fido_metadata/client.rb
139
124
  - lib/fido_metadata/code_accuracy_descriptor.rb
140
125
  - lib/fido_metadata/coercer/assumed_value.rb
126
+ - lib/fido_metadata/coercer/authenticator_get_info.rb
141
127
  - lib/fido_metadata/coercer/bit_field.rb
142
128
  - lib/fido_metadata/coercer/certificates.rb
143
129
  - lib/fido_metadata/coercer/date.rb
144
130
  - lib/fido_metadata/coercer/escaped_uri.rb
145
131
  - lib/fido_metadata/coercer/magic_number.rb
146
132
  - lib/fido_metadata/coercer/objects.rb
133
+ - lib/fido_metadata/coercer/statement.rb
147
134
  - lib/fido_metadata/coercer/user_verification_details.rb
148
- - lib/fido_metadata/constants.rb
149
135
  - lib/fido_metadata/entry.rb
150
136
  - lib/fido_metadata/pattern_accuracy_descriptor.rb
151
137
  - lib/fido_metadata/refinement/fixed_length_secure_compare.rb
@@ -164,7 +150,7 @@ metadata:
164
150
  homepage_uri: https://github.com/bdewater/fido_metadata
165
151
  source_code_uri: https://github.com/bdewater/fido_metadata
166
152
  changelog_uri: https://github.com/bdewater/fido_metadata/blob/master/CHANGELOG.md
167
- post_install_message:
153
+ post_install_message:
168
154
  rdoc_options: []
169
155
  require_paths:
170
156
  - lib
@@ -179,8 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
165
  - !ruby/object:Gem::Version
180
166
  version: '0'
181
167
  requirements: []
182
- rubygems_version: 3.0.3
183
- signing_key:
168
+ rubygems_version: 3.2.1
169
+ signing_key:
184
170
  specification_version: 4
185
171
  summary: FIDO Alliance Metadata Service client
186
172
  test_files: []
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.5
7
- before_install: gem install bundler -v 1.17.3
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FidoMetadata
4
- module Constants
5
- # https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-registry-v2.0-rd-20180702.html
6
-
7
- ATTACHMENT_HINTS = {
8
- 0x0001 => "INTERNAL",
9
- 0x0002 => "EXTERNAL",
10
- 0x0004 => "WIRED",
11
- 0x0008 => "WIRELESS",
12
- 0x0010 => "NFC",
13
- 0x0020 => "BLUETOOTH",
14
- 0x0040 => "NETWORK",
15
- 0x0080 => "READY",
16
- 0x0100 => "WIFI_DIRECT",
17
- }.freeze
18
-
19
- ATTESTATION_TYPES = {
20
- 0x3E07 => "BASIC_FULL", # 'Basic' in WebAuthn
21
- 0x3E08 => "BASIC_SURROGATE", # 'Self' in WebAuthn
22
- 0x3E09 => "ECDAA",
23
- 0x3E0A => "ATTCA",
24
- }.freeze
25
-
26
- AUTHENTICATION_ALGORITHMS = {
27
- 0x0001 => "SECP256R1_ECDSA_SHA256_RAW",
28
- 0x0002 => "SECP256R1_ECDSA_SHA256_DER",
29
- 0x0003 => "RSASSA_PSS_SHA256_RAW",
30
- 0x0004 => "RSASSA_PSS_SHA256_DER",
31
- 0x0005 => "SECP256K1_ECDSA_SHA256_RAW",
32
- 0x0006 => "SECP256K1_ECDSA_SHA256_DER",
33
- 0x0007 => "SM2_SM3_RAW",
34
- 0x0008 => "RSA_EMSA_PKCS1_SHA256_RAW",
35
- 0x0009 => "RSA_EMSA_PKCS1_SHA256_DER",
36
- 0x000A => "RSASSA_PSS_SHA384_RAW",
37
- 0x000B => "RSASSA_PSS_SHA512_RAW",
38
- 0x000C => "RSASSA_PKCSV15_SHA256_RAW",
39
- 0x000D => "RSASSA_PKCSV15_SHA384_RAW",
40
- 0x000E => "RSASSA_PKCSV15_SHA512_RAW",
41
- 0x000F => "RSASSA_PKCSV15_SHA1_RAW",
42
- 0x0010 => "SECP384R1_ECDSA_SHA384_RAW",
43
- 0x0011 => "SECP521R1_ECDSA_SHA512_RAW",
44
- 0x0012 => "ED25519_EDDSA_SHA256_RAW",
45
- }.freeze
46
-
47
- KEY_PROTECTION_TYPES = {
48
- 0x0001 => "SOFTWARE",
49
- 0x0002 => "HARDWARE",
50
- 0x0004 => "TEE",
51
- 0x0008 => "SECURE_ELEMENT",
52
- 0x0010 => "REMOTE_HANDLE",
53
- }.freeze
54
-
55
- MATCHER_PROTECTION_TYPES = {
56
- 0x0001 => "SOFTWARE",
57
- 0x0002 => "TEE",
58
- 0x0004 => "ON_CHIP",
59
- }.freeze
60
-
61
- PUBLIC_KEY_FORMATS = {
62
- 0x0100 => "ECC_X962_RAW",
63
- 0x0101 => "ECC_X962_DER",
64
- 0x0102 => "RSA_2048_RAW",
65
- 0x0103 => "RSA_2048_DER",
66
- 0x0104 => "COSE",
67
- }.freeze
68
-
69
- TRANSACTION_CONFIRMATION_DISPLAY_TYPES = {
70
- 0x0001 => "ANY",
71
- 0x0002 => "PRIVILEGED_SOFTWARE",
72
- 0x0004 => "TEE",
73
- 0x0008 => "HARDWARE",
74
- 0x0010 => "REMOTE",
75
- }.freeze
76
-
77
- USER_VERIFICATION_METHODS = {
78
- 0x00000001 => "PRESENCE",
79
- 0x00000002 => "FINGERPRINT",
80
- 0x00000004 => "PASSCODE",
81
- 0x00000008 => "VOICEPRINT",
82
- 0x00000010 => "FACEPRINT",
83
- 0x00000020 => "LOCATION",
84
- 0x00000040 => "EYEPRINT",
85
- 0x00000080 => "PATTERN",
86
- 0x00000100 => "HANDPRINT",
87
- 0x00000200 => "NONE",
88
- 0x00000400 => "ALL",
89
- }.freeze
90
- end
91
- end