module Darrrr::Provider
Constants
- MAX_RECOVERY_PROVIDER_CACHE_LENGTH
- RECOVERY_PROVIDER_CACHE_LENGTH
- REQUIRED_CRYPTO_OPS
Attributes
this[RW]
Public Class Methods
configure(&block)
click to toggle source
# File lib/darrrr/provider.rb, line 16 def configure(&block) raise ArgumentError, "Block required to configure #{self.name}" unless block_given? raise ProviderConfigError, "#{self.name} already configured" if self.this self.this = self.new.tap { |provider| provider.instance_eval(&block).freeze } self.this.privacy_policy = Darrrr.privacy_policy self.this.icon_152px = Darrrr.icon_152px self.this.issuer = Darrrr.authority end
included(base)
click to toggle source
# File lib/darrrr/provider.rb, line 10 def self.included(base) base.instance_eval do # this represents the account/recovery provider on this web app class << self attr_accessor :this def configure(&block) raise ArgumentError, "Block required to configure #{self.name}" unless block_given? raise ProviderConfigError, "#{self.name} already configured" if self.this self.this = self.new.tap { |provider| provider.instance_eval(&block).freeze } self.this.privacy_policy = Darrrr.privacy_policy self.this.icon_152px = Darrrr.icon_152px self.this.issuer = Darrrr.authority end end end end
new(provider_origin = nil, attrs: nil)
click to toggle source
# File lib/darrrr/provider.rb, line 28 def initialize(provider_origin = nil, attrs: nil) self.issuer = provider_origin load(attrs) if attrs end
Public Instance Methods
custom_encryptor=(encryptor)
click to toggle source
Overrides the global `encryptor` API to use
encryptor: a class/module that responds to all REQUIRED_CRYPTO_OPS
.
# File lib/darrrr/provider.rb, line 42 def custom_encryptor=(encryptor) if valid_encryptor?(encryptor) @encryptor = encryptor else raise ArgumentError, "custom encryption class must respond to all of #{REQUIRED_CRYPTO_OPS}" end end
encryptor()
click to toggle source
Returns the crypto API to be used. A thread local instance overrides the globally configured value which overrides the default encryptor.
# File lib/darrrr/provider.rb, line 35 def encryptor Thread.current[encryptor_key] || @encryptor || DefaultEncryptor end
load(attrs = nil)
click to toggle source
Lazily loads attributes if attrs is nil. It makes an http call to the recovery provider's well-known config location and caches the response if it's valid json.
attrs: optional way of building the provider without making an http call.
# File lib/darrrr/provider.rb, line 71 def load(attrs = nil) body = attrs || fetch_config! set_attrs!(body) self end
with_encryptor(encryptor) { || ... }
click to toggle source
# File lib/darrrr/provider.rb, line 50 def with_encryptor(encryptor) raise ArgumentError, "A block must be supplied" unless block_given? unless valid_encryptor?(encryptor) raise ArgumentError, "custom encryption class must respond to all of #{REQUIRED_CRYPTO_OPS}" end Thread.current[encryptor_key] = encryptor yield ensure Thread.current[encryptor_key] = nil end
Private Instance Methods
cache_config(response)
click to toggle source
# File lib/darrrr/provider.rb, line 87 def cache_config(response) match = /max-age=(\d+)/.match(response.headers["cache-control"]) cache_age = if match [match[1].to_i, MAX_RECOVERY_PROVIDER_CACHE_LENGTH].min else RECOVERY_PROVIDER_CACHE_LENGTH end Darrrr.cache.try(:set, cache_key, response.body, cache_age) end
cache_key()
click to toggle source
# File lib/darrrr/provider.rb, line 97 def cache_key "recovery_provider_config:#{self.origin}:configuration" end
errors()
click to toggle source
# File lib/darrrr/provider.rb, line 129 def errors errors = [] self.class::REQUIRED_FIELDS.each do |field| unless self.instance_variable_get("@#{field}") errors << "#{field} not set" end end self.class::URL_FIELDS.each do |field| begin uri = Addressable::URI.parse(self.instance_variable_get("@#{field}")) if !Darrrr.allow_unsafe_urls && uri.try(:scheme) != "https" errors << "#{field} must be an https URL" end rescue Addressable::URI::InvalidURIError errors << "#{field} must be a valid URL" end end if self.is_a? RecoveryProvider unless self.token_max_size.to_i > 0 errors << "token max size must be an integer" end end unless self.unseal_keys.try(:any?) errors << "No public key provided" end errors end
faraday()
click to toggle source
# File lib/darrrr/provider.rb, line 77 def faraday Faraday.new do |f| if Darrrr.faraday_config_callback Darrrr.faraday_config_callback.call(f) else f.adapter(Faraday.default_adapter) end end end
fetch_config!()
click to toggle source
# File lib/darrrr/provider.rb, line 101 def fetch_config! unless body = Darrrr.cache.try(:get, cache_key) response = faraday.get([self.origin, Darrrr::WELL_KNOWN_CONFIG_PATH].join("/")) if response.success? cache_config(response) else raise ProviderConfigError.new("Unable to retrieve recovery provider config for #{self.origin}: #{response.status}: #{response.body[0..100]}") end body = response.body end JSON.parse(body) rescue ::JSON::ParserError raise ProviderConfigError.new("Unable to parse recovery provider config for #{self.origin}:#{body[0..100]}") end
set_attrs!(context)
click to toggle source
# File lib/darrrr/provider.rb, line 118 def set_attrs!(context) self.class::REQUIRED_FIELDS.each do |attr| value = context[attr.to_s.tr("_", "-")] self.instance_variable_set("@#{attr}", value) end if errors.any? raise ProviderConfigError.new("Unable to parse recovery provider config for #{self.origin}: #{errors.join(", ")}") end end
valid_encryptor?(encryptor)
click to toggle source
# File lib/darrrr/provider.rb, line 62 def valid_encryptor?(encryptor) REQUIRED_CRYPTO_OPS.all? { |m| encryptor.respond_to?(m) } end