require 'openssl' require 'path-builder' require 'active_support/core_ext/string/inflections' module SecondStep def self.register_orm_adapter(**opts) if @registered_orm_adapters @registered_orm_adapters.merge! opts else @registered_orm_adapters = opts end end SecondStep.register_orm_adapter active_record: 'second_step/active_record_adapter', memory: 'second_step/memory_adapter' def self.use_orm(orm) return :none if orm == :none include @registered_orm_adapters[orm].to_s.camelcase.constantize end class Config def initialize(&block) self.instance_eval(&block) end class<< self private # A dry way of specifing config options. def config_option(name, default_value=nil, setter: nil, before_set: nil, after_set: nil, getter: nil, &default) instance_eval { define_method name do |new_value=nil| var = "@#{name}" value = if new_value new_value = instance_exec(new_value, &setter) if setter instance_exec new_value, &before_set if before_set new_value = instance_variable_set var, new_value instance_exec new_value, &after_set if after_set new_value else instance_variable_get var end value ||= default ? instance_eval(&default) : instance_variable_set(var, default_value) # For some reason, removing instance_eval on Ruby 2.3.0 causes a segfault when api_path is accessed. (value && getter) ? getter.call(value) : value end } end end def path(*args) PathBuilder.new(*args) end config_option :secondstep_uri, 'https://getsecondstep.com/', after_set: -> (uri) { @base_path = nil } config_option :secondstep_aud, "SecondStep Authentication - Env: production - Host: https://getsecondstep.com - Tech Edge Advisors, LLC." config_option(:api_path, setter: -> (path) { path.save! }, getter: -> (path) { path.new }, after_set: -> (uri) { @base_path = nil }){ path.api(:version).save![version] } config_option :application_id config_option :client_id config_option :client_secret config_option :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob' config_option :version, 'v1' config_option :rsa_key config_option :orm_adapter, before_set: -> (orm) { raise ORMAlreadySetError if @orm_adapter }, after_set: -> (orm) { SecondStep.use_orm orm } config_option :secret_string_length config_option :word_list_path, '/usr/share/dict/words', after_set: -> (_) { @word_list_count = nil @phrase_possibility_count = nil @phrase_entropy = nil } config_option :phrase_generator_min_entropy, 92 config_option :phrase_generator_length, 5, after_set: -> (_) { @phrase_possibility_count = nil @phrase_entropy = nil } config_option :phrase_delimiters, %{., -:;_+~*=}.split(''), after_set: -> (delimiters) { @phrase_possibility_count = nil @phrase_entropy = nil } config_option :secret_qr_length, 50 config_option :jwt_leeway, 0 config_option :jwt_hmac_algorithm, 'HS512' config_option :jwt_rsa_algorithm, 'RS512' def word_list_count @word_list_count ||= `sed -n '$=' #{word_list_path}`.chomp.to_i end def phrase_possibility_count @phrase_possibility_count ||= (word_list_count ** phrase_generator_length) * phrase_delimiters.length end def phrase_entropy @phrase_entropy ||= Math.log2 phrase_possibility_count end def secondstep_path path self.secondstep_uri end def base_path (@base_path ||= (secondstep_path + api_path).save!).new end def public_key rsa_key.public_key end end def self.config(&block) block ? @config = Config.new(&block) : @config end end