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.

Name of the cookie that (optionally) stores the payload.

VERSION

Current version of the library.

Public Class Methods

config(key) click to toggle source

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_config(path = nil, environment = nil) click to toggle source

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_payload(encoded_payload = nil) click to toggle source

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
logged_in?() click to toggle source

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
Also aliased as: signed_in?
signed_in?()

@deprecated Since v1.2.0. Use {#logged_in?}.

Alias for: logged_in?
user_email() click to toggle source

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
user_id() click to toggle source

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

config_environment() click to toggle source

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
config_path_from_environment() click to toggle source

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_payload(encoded_payload) click to toggle source

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
expected_signature(payload) click to toggle source

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
payload() click to toggle source

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
payload_user(key) click to toggle source

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_payload(encoded_payload) click to toggle source

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
valid_config?(config) click to toggle source

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
valid_payload?(payload) click to toggle source

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