Class: Rack::SlackRequestVerification::Middleware
- Inherits:
-
Object
- Object
- Rack::SlackRequestVerification::Middleware
- Defined in:
- lib/rack/slack_request_verification/middleware.rb
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, path_pattern:, signing_key: nil, signing_key_env_var: 'SLACK_SIGNING_KEY', max_staleness_in_secs: 60 * 5, logger: Logger.new($stdout), signing_version: 'v0', timestamp_header: 'X-Slack-Request-Timestamp', signature_header: 'X-Slack-Signature') ⇒ Middleware
constructor
A new instance of Middleware.
Constructor Details
#initialize(app, path_pattern:, signing_key: nil, signing_key_env_var: 'SLACK_SIGNING_KEY', max_staleness_in_secs: 60 * 5, logger: Logger.new($stdout), signing_version: 'v0', timestamp_header: 'X-Slack-Request-Timestamp', signature_header: 'X-Slack-Signature') ⇒ Middleware
Returns a new instance of Middleware.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rack/slack_request_verification/middleware.rb', line 16 def initialize(app, # A regular expression used to determine which requests to verify path_pattern:, # You can provide a signing key directly, set a SLACK_SIGNING_KEY env var # or customise the env var to something else signing_key: nil, signing_key_env_var: 'SLACK_SIGNING_KEY', # Mitigates replay attacks by verifying the request was sent recently – # a better strategy is to record the signature header to ensure you only # process each request once max_staleness_in_secs: 60 * 5, # Where to log error messages logger: Logger.new($stdout), signing_version: 'v0', timestamp_header: 'X-Slack-Request-Timestamp', signature_header: 'X-Slack-Signature' ) @app = app @path_pattern = path_pattern @signing_version = signing_version @timestamp_header = @signature_header = signature_header @logger = logger @max_staleness_in_secs = max_staleness_in_secs @signing_key = signing_key || ENV.fetch(signing_key_env_var) do fail Error, "#{signing_key_env_var} env var not set, please configure a signing key" end end |
Instance Method Details
#call(env) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/rack/slack_request_verification/middleware.rb', line 50 def call(env) if !path_pattern.match?(env['PATH_INFO']) @app.call(env) else headers = { signature_header => env["HTTP_" + signature_header.gsub('-', '_').upcase], => env["HTTP_" + .gsub('-', '_').upcase]&.to_i } missing_headers = headers.select { |_, value| value.nil? }.keys if !missing_headers.empty? logger.error "Slack verification failed: missing #{missing_headers.join(', ')}" return [401, {}, "Not authorized"] end = headers[] signature = headers[signature_header] = Time.now.to_i - max_staleness_in_secs if < logger.error "Slack verification failed: #{} is #{}, only #{} or later is allowed" return [401, {}, "Not authorized"] end body = env['rack.input'] signature_base_string = [ signing_version, , body.read ].join(':') body.rewind digest = OpenSSL::HMAC.hexdigest("SHA256", signing_key, signature_base_string) computed_signature = [signing_version, digest].join('=') if computed_signature != signature logger.error "Slack verification failed: #{signature_header} does not match the signature" return [401, {}, "Not authorized"] end @app.call(env) end end |