A spec/webauthn/public_key_credential/creation_options_spec.cr => spec/webauthn/public_key_credential/creation_options_spec.cr +13 -0
@@ 0,0 1,13 @@
+require "../../spec_helper"
+
+describe WebAuthn::PublicKeyCredential::CreationOptions do
+ describe "#to_json" do
+ it "encodes to json" do
+ user = WebAuthn::PublicKeyCredential::User.new(id: "something", name: "the user", display_name: "User 1")
+ rp = WebAuthn::PublicKeyCredential::RPEntity.new(id: "something", name: "rep")
+ creation_options = WebAuthn::PublicKeyCredential::CreationOptions.new(rp: rp, user: user)
+
+ creation_options.to_json.should be_a(String)
+ end
+ end
+end
A spec/webauthn/public_key_credential/user_spec.cr => spec/webauthn/public_key_credential/user_spec.cr +25 -0
@@ 0,0 1,25 @@
+require "../../spec_helper"
+
+describe WebAuthn::PublicKeyCredential::User do
+ describe "#to_json" do
+ it "encodes to json" do
+ user = WebAuthn::PublicKeyCredential::User.new(id: "something",
+ name: "the user",
+ display_name: "User 1")
+
+ user.to_json.should be_a(String)
+ end
+ end
+
+ describe "#from_json" do
+ it "decodes a JSON payload" do
+ user_json = %({"name":"the user","id":"c29tZXRoaW5n","displayName":"User 1"})
+
+ user = WebAuthn::PublicKeyCredential::User.from_json(user_json)
+
+ user.id.should eq("something")
+ user.name.should eq("the user")
+ user.display_name.should eq("User 1")
+ end
+ end
+end
M spec/webauthn_spec.cr => spec/webauthn_spec.cr +9 -4
@@ 1,9 1,14 @@
require "./spec_helper"
-describe Webauthn do
- # TODO: Write tests
+describe WebAuthn do
+ describe "#generate_user_id" do
+ it "generates a spec-compliant user ID" do
+ user_id = WebAuthn.generate_user_id
- it "works" do
- false.should eq(true)
+ user_id.should be_a(String)
+
+ # As specified, the generate user id should not contain equals
+ user_id.should_not end_with("=")
+ end
end
end
M src/webauthn.cr => src/webauthn.cr +15 -3
@@ 1,6 1,18 @@
-# TODO: Write documentation for `Webauthn`
-module Webauthn
+require "io"
+require "json"
+require "random"
+
+require "./webauthn/**"
+
+# TODO: Write documentation for `WebAuthn`
+module WebAuthn
VERSION = "0.1.0"
- # TODO: Put your code here
+ # Generates a [WebAuthn User Handle][1] that follows the WebAuthn spec
+ # recommendations.
+ #
+ # [1]: https://www.w3.org/TR/webauthn-2/#user-handle
+ def self.generate_user_id : String
+ Random::Secure.urlsafe_base64(64, false)
+ end
end
A src/webauthn/base64.cr => src/webauthn/base64.cr +10 -0
@@ 0,0 1,10 @@
+class WebAuthn::Base64
+ def self.from_json(pull : JSON::PullParser)
+ string = pull.read_string
+ ::Base64.decode_string(string)
+ end
+
+ def self.to_json(value : String, json : JSON::Builder)
+ ::Base64.urlsafe_encode(value, false).to_json(json)
+ end
+end
A src/webauthn/credential.cr => src/webauthn/credential.cr +4 -0
@@ 0,0 1,4 @@
+module WebAuthn::Credential
+ def self.options_for_create
+ end
+end
A src/webauthn/public_key_credential/creation_options.cr => src/webauthn/public_key_credential/creation_options.cr +9 -0
@@ 0,0 1,9 @@
+class WebAuthn::PublicKeyCredential::CreationOptions
+ include JSON::Serializable
+
+ getter rp : WebAuthn::PublicKeyCredential::RPEntity
+ getter user : WebAuthn::PublicKeyCredential::User
+
+ def initialize(@rp, @user)
+ end
+end
A src/webauthn/public_key_credential/entity.cr => src/webauthn/public_key_credential/entity.cr +6 -0
@@ 0,0 1,6 @@
+class WebAuthn::PublicKeyCredential::Entity
+ include JSON::Serializable
+
+ @[JSON::Field(key: "name")]
+ getter name : String
+end
A src/webauthn/public_key_credential/options.cr => src/webauthn/public_key_credential/options.cr +10 -0
@@ 0,0 1,10 @@
+abstract class Options
+ CHALLENGE_LENGTH = 32
+
+ abstract def to_json : String
+ abstract def to_json(io : IO)
+
+ def challenge : String
+ @challenge ||= Random::Secure.urlsafe_base64(CHALLENGE_LENGTH, false)
+ end
+end
A src/webauthn/public_key_credential/relying_party.cr => src/webauthn/public_key_credential/relying_party.cr +2 -0
@@ 0,0 1,2 @@
+class WebAuthn::PublicKeyCredential::RelyingParty
+end
A src/webauthn/public_key_credential/rp_entity.cr => src/webauthn/public_key_credential/rp_entity.cr +8 -0
@@ 0,0 1,8 @@
+class WebAuthn::PublicKeyCredential::RPEntity < WebAuthn::PublicKeyCredential::Entity
+ include JSON::Serializable
+
+ getter id : String
+
+ def initialize(@name, @id)
+ end
+end
A src/webauthn/public_key_credential/user.cr => src/webauthn/public_key_credential/user.cr +12 -0
@@ 0,0 1,12 @@
+class WebAuthn::PublicKeyCredential::User < WebAuthn::PublicKeyCredential::Entity
+ include JSON::Serializable
+
+ @[JSON::Field(key: "id", converter: WebAuthn::Base64)]
+ getter id : String
+
+ @[JSON::Field(key: "displayName")]
+ getter display_name : String
+
+ def initialize(@id, @name, @display_name)
+ end
+end