module Sinatra::Slack::InstanceHelpers

Instance level helper methods

Public Instance Methods

action() click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 16
def action
  @action ||= Helpers::ActionRequest.parse(params)
end
authorized?() click to toggle source

Checks for Slack defined HTTP headers and computes the request signature (HMAC). If provided signature is the same as the computed one, the request is valid.

Go to this page for the verification process: api.slack.com/docs/verifying-requests-from-slack

# File lib/sinatra/slack/instance_helpers.rb, line 62
def authorized?
  logger.warn 'Missing Slack signing token' unless settings.slack_secret
  return true unless settings.slack_secret

  valid_headers? &&
    compute_signature(settings.slack_secret) == slack_signature
end
channel() click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 20
def channel
  @channel ||= Helpers::Channel.parse(params)
end
command() click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 12
def command
  @command ||= Helpers::CommandRequest.new(params)
end
compute_signature(secret) click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 87
def compute_signature(secret)
  # in case someone already read it
  request.body.rewind

  # From Slack API docs, the "v0" is always fixed for now
  sig_basestring = "v0:#{slack_timestamp}:#{request.body.read}"
  "v0=#{hmac_signed(sig_basestring, secret)}"
end
handle_request(request_handler:, request_params:, quick_reply: '...') click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 36
def handle_request(request_handler:, request_params:, quick_reply: '...')
  EM.defer do
    handle_with_rescue do
      deferred_message = request_handler.bind(self).call(*request_params)
      channel.send(deferred_message)
    end
  end

  body quick_reply
end
handle_with_rescue() { || ... } click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 47
def handle_with_rescue
  return unless block_given?

  yield
rescue StandardError => ex
  logger.error ex.full_message
  channel.send(slack_error_notification(ex))
end
hmac_signed(to_sign, hmac_key) click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 96
def hmac_signed(to_sign, hmac_key)
  sha256 = OpenSSL::Digest.new('sha256')
  OpenSSL::HMAC.hexdigest(sha256, hmac_key, to_sign)
end
slack_error_notification(_error) click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 30
def slack_error_notification(_error)
  slack_response '' do |r|
    r.text = 'Ups, something went wrong'
  end
end
slack_response(callback_id) { |s_resp| ... } click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 24
def slack_response(callback_id)
  s_resp = Helpers::SlackResponse.new(callback_id)
  yield s_resp if block_given?
  s_resp
end
slack_signature() click to toggle source

Helper methods for Slack request validation

# File lib/sinatra/slack/instance_helpers.rb, line 71
def slack_signature
  @slack_signature ||= env['HTTP_X_SLACK_SIGNATURE']
end
slack_timestamp() click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 75
def slack_timestamp
  @slack_timestamp ||= env['HTTP_X_SLACK_REQUEST_TIMESTAMP']
end
valid_headers?() click to toggle source
# File lib/sinatra/slack/instance_helpers.rb, line 79
def valid_headers?
  return false unless slack_signature || slack_timestamp

  # The request timestamp is more than five minutes from local time.
  # It could be a replay attack, so let's ignore it.
  (Time.now.to_i - slack_timestamp.to_i).abs <= 60 * 5
end