A spec/webauthn/public_key_credential/options_spec.cr => spec/webauthn/public_key_credential/options_spec.cr +27 -0
@@ 0,0 1,27 @@
+require "../../spec_helper"
+
+describe WebAuthn::PublicKeyCredential::Options do
+ describe "#challenge" do
+ it "creates a challenge of at least 16 bytes" do
+ challenge = TestOptions.new.challenge
+
+ challenge.bytesize.should be >= 16
+ end
+
+ it "crates a random challenge each time it's instanciated" do
+ ch1 = TestOptions.new.challenge
+ ch2 = TestOptions.new.challenge
+
+ ch1.should_not eq(ch2)
+ end
+
+ it "an instance always returns the same challenge" do
+ opt = TestOptions.new
+
+ opt.challenge.should eq(opt.challenge)
+ end
+ end
+end
+
+class TestOptions < WebAuthn::PublicKeyCredential::Options
+end
M src/webauthn/public_key_credential/creation_options.cr => src/webauthn/public_key_credential/creation_options.cr +11 -5
@@ 1,9 1,15 @@
-class WebAuthn::PublicKeyCredential::CreationOptions
- include JSON::Serializable
+require "./options"
- getter rp : WebAuthn::PublicKeyCredential::RPEntity
- getter user : WebAuthn::PublicKeyCredential::User
+module WebAuthn
+ module PublicKeyCredential
+ class CreationOptions < Options
+ include JSON::Serializable
- def initialize(@rp, @user)
+ getter rp : WebAuthn::PublicKeyCredential::RPEntity
+ getter user : WebAuthn::PublicKeyCredential::User
+
+ def initialize(@rp, @user)
+ end
+ end
end
end
M src/webauthn/public_key_credential/entity.cr => src/webauthn/public_key_credential/entity.cr +8 -4
@@ 1,6 1,10 @@
-class WebAuthn::PublicKeyCredential::Entity
- include JSON::Serializable
+module WebAuthn
+ module PublicKeyCredential
+ class Entity
+ include JSON::Serializable
- @[JSON::Field(key: "name")]
- getter name : String
+ @[JSON::Field(key: "name")]
+ getter name : String
+ end
+ end
end
M src/webauthn/public_key_credential/options.cr => src/webauthn/public_key_credential/options.cr +15 -6
@@ 1,10 1,19 @@
-abstract class Options
- CHALLENGE_LENGTH = 32
+module WebAuthn
+ module PublicKeyCredential
+ abstract class Options
+ CHALLENGE_LENGTH = 32
- abstract def to_json : String
- abstract def to_json(io : IO)
+ abstract def to_json
+ abstract def to_json(io : IO)
- def challenge : String
- @challenge ||= Random::Secure.urlsafe_base64(CHALLENGE_LENGTH, false)
+ # The challenge is a secure-random string used to avoid reply attacks.
+ # This vlaue should be stored for the duration of the auth session and
+ # verified by the server.
+ #
+ # See: https://www.w3.org/TR/webauthn/#cryptographic-challenges
+ def challenge : String
+ @challenge ||= Random::Secure.urlsafe_base64(CHALLENGE_LENGTH, false)
+ end
+ end
end
end
D src/webauthn/public_key_credential/relying_party.cr => src/webauthn/public_key_credential/relying_party.cr +0 -2
@@ 1,2 0,0 @@
-class WebAuthn::PublicKeyCredential::RelyingParty
-end
M src/webauthn/public_key_credential/rp_entity.cr => src/webauthn/public_key_credential/rp_entity.cr +7 -5
@@ 1,8 1,10 @@
-class WebAuthn::PublicKeyCredential::RPEntity < WebAuthn::PublicKeyCredential::Entity
- include JSON::Serializable
+module WebAuthn
+ module PublicKeyCredential
+ class RPEntity < Entity
+ getter id : String
- getter id : String
-
- def initialize(@name, @id)
+ def initialize(@name, @id)
+ end
+ end
end
end
M src/webauthn/public_key_credential/user.cr => src/webauthn/public_key_credential/user.cr +10 -8
@@ 1,12 1,14 @@
-class WebAuthn::PublicKeyCredential::User < WebAuthn::PublicKeyCredential::Entity
- include JSON::Serializable
+module WebAuthn
+ module PublicKeyCredential
+ class User < Entity
+ @[JSON::Field(key: "id", converter: WebAuthn::Base64)]
+ getter id : String
- @[JSON::Field(key: "id", converter: WebAuthn::Base64)]
- getter id : String
+ @[JSON::Field(key: "displayName")]
+ getter display_name : String
- @[JSON::Field(key: "displayName")]
- getter display_name : String
-
- def initialize(@id, @name, @display_name)
+ def initialize(@id, @name, @display_name)
+ end
+ end
end
end