module TwoFactorAuth

Constants

U2F_VERSION
VERSION

Public Class Methods

app_id_or_facet_list() click to toggle source

We send clients the facet domain (web origin) if there are no facets, (typical for local dev), otherwise the full facet list (prohibits http)

# File lib/two_factor_auth.rb, line 48
def self.app_id_or_facet_list
  if facets.empty?
    facet_domain
  else
    "#{facet_domain}/two_factor_auth/trusted_facets"
  end
end
decode_pubkey(raw) click to toggle source
# File lib/two_factor_auth.rb, line 89
def self.decode_pubkey raw
  bn = OpenSSL::BN.new(raw, 2)
  group = OpenSSL::PKey::EC::Group.new('prime256v1')
  point = OpenSSL::PKey::EC::Point.new(group, bn)
rescue OpenSSL::PKey::EC::Point::Error => e
  raise InvalidPublicKey, "Invalid public key: #{e.message}"
end
facet_domain() click to toggle source
# File lib/two_factor_auth.rb, line 31
def self.facet_domain
  @facet_domain
end
facet_domain=(facet_domain) click to toggle source
# File lib/two_factor_auth.rb, line 20
def self.facet_domain= facet_domain
  if facet_domain =~ /\.dev(:\d+)?\/?$/
    raise InvalidFacetDomain, "Facet domain needs a real TLD, not .dev. Edit /etc/hosts to make a custom hostname"
  end
  if facet_domain == "https://www.example.com"
    raise InvalidFacetDomain, "You need to cusomize the facet_domain in config/initializers/two_factor_auth.rb"
  end

  @facet_domain = facet_domain.sub(/\/$/, '')
end
facets() click to toggle source
# File lib/two_factor_auth.rb, line 67
def self.facets
  @facets ||= []
end
facets=(facets) click to toggle source
# File lib/two_factor_auth.rb, line 56
def self.facets= facets
  facets ||= []
  if !facets.empty? and facet_domain !~ /\Ahttps:/
    raise InvalidFacetDomain, "U2F requires HTTPS to use facet lists"
  end
  if facets.any? { |f| f !~ /\Ahttps:/ }
    raise InvalidFacetListDomain, "URLs in the facet list must all be HTTPS"
  end
  @facets = facets
end
pubkey_valid?(raw) click to toggle source
# File lib/two_factor_auth.rb, line 97
def self.pubkey_valid? raw
  pk = decode_pubkey raw
  pk.on_curve?
rescue InvalidPublicKey
  false
end
random_encoded_challenge() click to toggle source
# File lib/two_factor_auth.rb, line 82
def self.random_encoded_challenge
  random = OpenSSL::Random.pseudo_bytes(32)
  TwoFactorAuth::websafe_base64_encode(random)
rescue OpenSSL::Random::RandomError
  raise CantGenerateRandomNumbers, "Not enough entropy to generate secure challenges"
end
trusted_facet_list_url() click to toggle source
# File lib/two_factor_auth.rb, line 42
def self.trusted_facet_list_url
  @trusted_facet_list_url or app_id_or_facet_list
end
trusted_facet_list_url=(url) click to toggle source
# File lib/two_factor_auth.rb, line 35
def self.trusted_facet_list_url= url
  if url !~ /\Ahttps:/
    raise InvalidTrustedFacetListUrl, "U2F requires HTTPS for facet urls"
  end
  @trusted_facet_list_url = url
end
websafe_base64_decode(encoded) click to toggle source
# File lib/two_factor_auth.rb, line 76
def self.websafe_base64_decode encoded
  # pad back out to decode
  padded = encoded.ljust((encoded.length/4.0).ceil * 4, '=')
  Base64.urlsafe_decode64(padded)
end
websafe_base64_encode(str) click to toggle source
# File lib/two_factor_auth.rb, line 71
def self.websafe_base64_encode str
  # PHP code removes trailing =s, don't know why
  Base64.urlsafe_encode64(str).sub(/=+$/,'')
end