module Monk::Id
Integrate Monk
ID on the server-side by accessing payloads from the client-side JavaScript.
@author Monk
Development, Inc.
Integrate Monk
ID on the server-side by accessing payloads from the client-side JavaScript.
@author Monk
Development, Inc.
Constants
- CONFIG_FILE
Expected path of config file in Rails and Sinatra relative to the app's root directory.
- COOKIE_NAME
Name of the cookie that (optionally) stores the payload.
- VERSION
Current version of the library.
Public Class Methods
Get a config value. Attempts to load the config if it hasn't already been loaded.
@param key [String] Name of config value. @raise [StandardError] If the config can't be loaded. @return [*] Config value.
# File lib/monk/id.rb, line 52 def config(key) load_config unless @config @config[key] end
Load a YAML config file for a specific environment. Rails and Sinatra apps don't need to call this method if the config file is stored at {CONFIG_FILE}, as it's loaded automatically.
@param path [String] Path of YAML config file to load. Leave `nil` to
read from environment (`MONK_ID_CONFIG` variable, Rails, Sinatra).
@param environment [String] Environment section to use. Leave `nil` to
read from environment (`MONK_ID_ENV` variable, Rails, Sinatra). Defaults to `development`.
@raise [StandardError] If the file doesn't exist or can't be read. @return [Hash<String>] Loaded config values.
# File lib/monk/id.rb, line 35 def load_config(path = nil, environment = nil) path ||= config_path_from_environment environment ||= config_environment config = YAML.load_file(path)[environment] valid_config?(config) @config = config end
Load a payload from the client-side.
@param encoded_payload [String, []] Encoded payload or Hash-like
cookies object to automatically load the payload from.
@return [Hash<Symbol>] Decoded and validate payload. Empty if there's no
payload or it fails validation.
# File lib/monk/id.rb, line 64 def load_payload(encoded_payload = nil) payload = select_payload(encoded_payload) return @payload = {} unless payload begin payload = decode_payload(payload) valid = valid_payload?(payload) rescue valid = false end @payload = valid ? payload : {} end
Check whether there's a logged in user.
@return [Boolean] Whether there's a logged in user.
# File lib/monk/id.rb, line 98 def logged_in? !user_id.nil? end
Get the logged in user's email address.
@return [String] If logged in user. @return [nil] If no logged in user.
# File lib/monk/id.rb, line 91 def user_email payload_user(:email) end
Get the logged in user's UUID.
@return [String] If logged in user. @return [nil] If no logged in user.
# File lib/monk/id.rb, line 83 def user_id payload_user(:id) end
Protected Class Methods
Get the environment to load within the config. Supports `ENV` variable, Rails, and Sinatra. Defaults to `development` if none specify.
@return [String] Environment name.
# File lib/monk/id.rb, line 132 def config_environment if ENV['MONK_ID_ENV'] ENV['MONK_ID_ENV'] elsif defined? Rails Rails.env elsif defined? Sinatra Sinatra::Application.settings.environment.to_s else 'development' end end
Get the path to the config file from the environment. Supports `ENV` variable, Rails, and Sinatra.
@return [String] Path to the config file. @return [nil] If not set by the environment.
# File lib/monk/id.rb, line 118 def config_path_from_environment if ENV['MONK_ID_CONFIG'] ENV['MONK_ID_CONFIG'] elsif defined? Rails File.join(Rails.root, CONFIG_FILE) elsif defined? Sinatra File.join(Sinatra::Application.settings.root, CONFIG_FILE) end end
Decode a payload from the client-side.
@param encoded_payload [String] Encoded payload. @raise [JSON::ParserError] If invalid JSON. @return [Hash<Symbol>] Decoded payload.
# File lib/monk/id.rb, line 176 def decode_payload(encoded_payload) JSON.parse(Base64.decode64(encoded_payload), symbolize_names: true) end
Generate the expected signature of a payload using the app's secret.
@param payload [Hash<Symbol>] Decoded payload. @return [String] Expected signature of the payload.
# File lib/monk/id.rb, line 184 def expected_signature(payload) payload_clone = payload.clone payload_clone[:user].delete(:signature) OpenSSL::HMAC.digest( OpenSSL::Digest::SHA512.new, config('app_secret'), JSON.generate(payload_clone[:user]) ) end
Get the loaded payload.
@return [Hash<Symbol>] Loaded payload. Empty if there's no payload or it
failed validation.
# File lib/monk/id.rb, line 210 def payload @payload || load_payload end
Get a value from the `user` hash of the loaded payload.
@param key [Symbol] Name of value. @return [*] Requested value or `nil` if not set.
# File lib/monk/id.rb, line 218 def payload_user(key) payload = self.payload payload.key?(:user) ? payload[:user][key] : nil end
Select a payload from the first place one can be found.
@param encoded_payload [String, []] Encoded payload or Hash-like
cookies object to select the payload from.
@return [String] Encoded payload. @return [nil] If one can't be found.
# File lib/monk/id.rb, line 163 def select_payload(encoded_payload) if encoded_payload.is_a? String encoded_payload elsif encoded_payload.respond_to? :[] encoded_payload[COOKIE_NAME] end end
Validate that a config has all the required values.
@param config [Hash<String>] Config values. @raise [RuntimeError] If invalid. @return [true] If valid.
# File lib/monk/id.rb, line 149 def valid_config?(config) raise 'no config loaded' unless config raise 'no `app_id` config value' unless config['app_id'] raise 'no `app_secret` config value' unless config['app_secret'] true end
Validate that a payload hasn't been tampered with or faked by comparing signatures.
@param payload [Hash<Symbol>] Decoded payload. @return [Boolean] Whether the payload is valid.
# File lib/monk/id.rb, line 200 def valid_payload?(payload) signature = Base64.decode64(payload[:user][:signature]) signature == expected_signature(payload) end