-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
469 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# frozen_string_literal: true | ||
|
||
module WebAuthn | ||
module Metadata | ||
module Attributes | ||
def underscore_name(name) | ||
name | ||
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') | ||
.gsub(/([a-z\d])([A-Z])/, '\1_\2') | ||
.downcase | ||
.to_sym | ||
end | ||
private :underscore_name | ||
|
||
def json_accessor(name, coercer = nil) | ||
underscored_name = underscore_name(name) | ||
attr_accessor underscored_name | ||
|
||
if coercer | ||
define_method(:"#{underscored_name}=") do |value| | ||
coerced_value = coercer.coerce(value) | ||
instance_variable_set(:"@#{underscored_name}", coerced_value) | ||
end | ||
end | ||
end | ||
|
||
def from_json(hash = {}) | ||
instance = new | ||
hash.each do |k, v| | ||
method_name = :"#{underscore_name(k)}=" | ||
instance.public_send(method_name, v) if instance.respond_to?(method_name) | ||
end | ||
|
||
instance | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/attributes" | ||
require "webauthn/metadata/coercer/date" | ||
|
||
module WebAuthn | ||
module Metadata | ||
class BiometricStatusReport | ||
extend Attributes | ||
|
||
json_accessor("certLevel") | ||
json_accessor("modality") | ||
json_accessor("effectiveDate", Coercer::Date) | ||
json_accessor("certificationDescriptor") | ||
json_accessor("certificateNumber") | ||
json_accessor("certificationPolicyVersion") | ||
json_accessor("certificationRequirementsVersion") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/biometric_status_report" | ||
|
||
module WebAuthn | ||
module Metadata | ||
module Coercer | ||
module BiometricStatusReports | ||
def self.coerce(values) | ||
return unless values.is_a?(Array) | ||
return values if values.all? { |value| value.is_a?(WebAuthn::Metadata::BiometricStatusReport) } | ||
|
||
values.map { |value| WebAuthn::Metadata::BiometricStatusReport.from_json(value) } | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# frozen_string_literal: true | ||
|
||
module WebAuthn | ||
module Metadata | ||
module Coercer | ||
module Date | ||
def self.coerce(value) | ||
return value if value.is_a?(::Date) | ||
|
||
::Date.iso8601(value) if value | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/entry" | ||
|
||
module WebAuthn | ||
module Metadata | ||
module Coercer | ||
module Entries | ||
def self.coerce(values) | ||
return unless values.is_a?(Array) | ||
return values if values.all? { |value| value.is_a?(WebAuthn::Metadata::Entry) } | ||
|
||
values.map { |value| WebAuthn::Metadata::Entry.from_json(value) } | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# frozen_string_literal: true | ||
|
||
require "uri" | ||
|
||
module WebAuthn | ||
module Metadata | ||
module Coercer | ||
module EscapedURI | ||
# The character # is a reserved character and not allowed in URLs, it is replaced by its hex value %x23. | ||
# https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-metadata-service-v2.0-rd-20180702.html#idl-def-MetadataTOCPayloadEntry | ||
def self.coerce(value) | ||
return value if value.is_a?(URI) | ||
|
||
URI(value.gsub(/%x23/, '#')) if value | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/status_report" | ||
|
||
module WebAuthn | ||
module Metadata | ||
module Coercer | ||
module StatusReports | ||
def self.coerce(values) | ||
return unless values.is_a?(Array) | ||
return values if values.all? { |value| value.is_a?(WebAuthn::Metadata::StatusReport) } | ||
|
||
values.map { |value| WebAuthn::Metadata::StatusReport.from_json(value) } | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/attributes" | ||
require "webauthn/metadata/coercer/biometric_status_reports" | ||
require "webauthn/metadata/coercer/date" | ||
require "webauthn/metadata/coercer/escaped_uri" | ||
require "webauthn/metadata/coercer/status_reports" | ||
|
||
module WebAuthn | ||
module Metadata | ||
class Entry | ||
extend Attributes | ||
|
||
json_accessor("aaid") | ||
json_accessor("aaguid") | ||
json_accessor("attestationCertificateKeyIdentifiers") | ||
json_accessor("hash") | ||
json_accessor("url", Coercer::EscapedURI) | ||
json_accessor("biometricStatusReports", Coercer::BiometricStatusReports) | ||
json_accessor("statusReports", Coercer::StatusReports) | ||
json_accessor("timeOfLastStatusChange", Coercer::Date) | ||
json_accessor("rogueListURL", Coercer::EscapedURI) | ||
json_accessor("rogueListHash") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/attributes" | ||
require "webauthn/metadata/coercer/date" | ||
require "webauthn/metadata/coercer/escaped_uri" | ||
|
||
module WebAuthn | ||
module Metadata | ||
class StatusReport | ||
extend Attributes | ||
|
||
json_accessor("status") | ||
json_accessor("effectiveDate", Coercer::Date) | ||
json_accessor("certificate") | ||
json_accessor("url", Coercer::EscapedURI) | ||
json_accessor("certificationDescriptor") | ||
json_accessor("certificateNumber") | ||
json_accessor("certificationPolicyVersion") | ||
json_accessor("certificationRequirementsVersion") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# frozen_string_literal: true | ||
|
||
module WebAuthn | ||
module Metadata | ||
class Store | ||
def self.find_authenticator(aaguid) | ||
|
||
end | ||
|
||
def self.table_of_contents | ||
stored_toc = WebAuthn.configuration.metadata_storage.read("webauthn_toc") | ||
return stored_toc if stored_toc&.not_expired? | ||
|
||
json = WebAuthn::Metadata::Client.download_toc(WebAuthn.configuration.metadata_toc_uri) | ||
fresh_toc = WebAuthn::Metadata::TableOfContents.from_json(json) | ||
WebAuthn.configuration.metadata_storage.write("webauthn_toc", fresh_toc) | ||
fresh_toc | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# frozen_string_literal: true | ||
|
||
require "webauthn/metadata/attributes" | ||
require "webauthn/metadata/coercer/date" | ||
require "webauthn/metadata/coercer/entries" | ||
|
||
module WebAuthn | ||
module Metadata | ||
class TableOfContents | ||
extend Attributes | ||
|
||
json_accessor("legalHeader") | ||
json_accessor("nextUpdate", Coercer::Date) | ||
json_accessor("entries", Coercer::Entries) | ||
json_accessor("no") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
require "webauthn/metadata/attributes" | ||
|
||
RSpec.describe WebAuthn::Metadata::Attributes do | ||
subject do | ||
double = Class.new(Object) | ||
double.extend WebAuthn::Metadata::Attributes | ||
double | ||
end | ||
|
||
context ".json_accessor" do | ||
it "generates snake cased accessor methods for camel cased keys" do | ||
subject.public_send(:json_accessor, "fooBarBaz") | ||
|
||
expect(subject.new).to respond_to(:foo_bar_baz, :foo_bar_baz=) | ||
end | ||
|
||
it "keeps accessor methods snake cased if they already were so" do | ||
subject.public_send(:json_accessor, "snake_case") | ||
|
||
expect(subject.new).to respond_to(:snake_case, :snake_case=) | ||
end | ||
|
||
it "generates a setter method that sends 'coerce' to the specified class or module" do | ||
coercer = instance_spy("Coercer") | ||
subject.public_send(:json_accessor, "quxQuz", coercer) | ||
|
||
instance = subject.new | ||
instance.qux_quz = "testing" | ||
|
||
expect(coercer).to have_received(:coerce).with("testing") | ||
end | ||
end | ||
|
||
context ".from_json" do | ||
before(:each) { subject.public_send(:json_accessor, "fooBar") } | ||
|
||
it "sends messages to snake cased setter methods from camel case keyed hashes" do | ||
instance = subject.from_json({"fooBar" => 123}) | ||
|
||
expect(instance).to have_attributes(foo_bar: 123) | ||
end | ||
|
||
it "sends messages to snake cased setter methods from snake case keyed hashes" do | ||
instance = subject.from_json({"foo_bar" => 123}) | ||
|
||
expect(instance).to have_attributes(foo_bar: 123) | ||
end | ||
|
||
it "does not send messages if the instance does not respond to it" do | ||
subject.from_json({"shouldBeSafe" => 123}) | ||
end | ||
end | ||
end |
32 changes: 32 additions & 0 deletions
32
spec/webauthn/metadata/coercer/biometric_status_reports_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
require "webauthn/metadata/coercer/biometric_status_reports" | ||
|
||
RSpec.describe WebAuthn::Metadata::Coercer::BiometricStatusReports do | ||
subject { described_class.coerce(value) } | ||
|
||
context "when the value is an array of BiometricStatusReport" do | ||
let(:value) { [WebAuthn::Metadata::BiometricStatusReport.new] } | ||
|
||
it "returns the same value" do | ||
expect(subject).to eq(value) | ||
end | ||
end | ||
|
||
context "when the value is nil" do | ||
let(:value) { nil } | ||
|
||
specify do | ||
expect(subject).to be_nil | ||
end | ||
end | ||
|
||
context "when the value is an array of Hash" do | ||
let(:value) { [{ "certLevel" => 1, "modality" => 2 }] } | ||
|
||
it "returns a BiometricStatusReport" do | ||
expect(subject).to all(be_a(WebAuthn::Metadata::BiometricStatusReport)) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
require "webauthn/metadata/coercer/date" | ||
|
||
RSpec.describe WebAuthn::Metadata::Coercer::Date do | ||
subject { described_class.coerce(value) } | ||
|
||
context "when the value is a Date" do | ||
let(:value) { Date.new(2019, 5, 20) } | ||
|
||
it "returns the same value" do | ||
expect(subject).to eq(value) | ||
end | ||
end | ||
|
||
context "when the value is nil" do | ||
let(:value) { nil } | ||
|
||
specify do | ||
expect(subject).to be_nil | ||
end | ||
end | ||
|
||
context "when the value is a String" do | ||
context "containing a valid ISO-8601 value" do | ||
let(:value) { "2019-05-20" } | ||
|
||
specify do | ||
expect(subject).to be_a(Date) | ||
end | ||
end | ||
|
||
context "not containing an invalid ISO-8601 value" do | ||
let(:value) { "2019-20-05" } | ||
|
||
specify do | ||
expect { subject }.to raise_error(ArgumentError) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.