summaryrefslogtreecommitdiff
path: root/lib/api/integrations/slack/request.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api/integrations/slack/request.rb')
-rw-r--r--lib/api/integrations/slack/request.rb51
1 files changed, 51 insertions, 0 deletions
diff --git a/lib/api/integrations/slack/request.rb b/lib/api/integrations/slack/request.rb
new file mode 100644
index 00000000000..df0109b07aa
--- /dev/null
+++ b/lib/api/integrations/slack/request.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module API
+ class Integrations
+ module Slack
+ module Request
+ VERIFICATION_VERSION = 'v0'
+ VERIFICATION_TIMESTAMP_HEADER = 'X-Slack-Request-Timestamp'
+ VERIFICATION_SIGNATURE_HEADER = 'X-Slack-Signature'
+ VERIFICATION_DELIMITER = ':'
+ VERIFICATION_HMAC_ALGORITHM = 'sha256'
+ VERIFICATION_TIMESTAMP_EXPIRY = 1.minute.to_i
+
+ # Verify the request by comparing the given request signature in the header
+ # with a signature value that we compute according to the steps in:
+ # https://api.slack.com/authentication/verifying-requests-from-slack.
+ def self.verify!(request)
+ return false unless Gitlab::CurrentSettings.slack_app_signing_secret
+
+ timestamp, signature = request.headers.values_at(
+ VERIFICATION_TIMESTAMP_HEADER,
+ VERIFICATION_SIGNATURE_HEADER
+ )
+
+ return false if timestamp.nil? || signature.nil?
+ return false if Time.current.to_i - timestamp.to_i >= VERIFICATION_TIMESTAMP_EXPIRY
+
+ request.body.rewind
+
+ basestring = [
+ VERIFICATION_VERSION,
+ timestamp,
+ request.body.read
+ ].join(VERIFICATION_DELIMITER)
+
+ hmac_digest = OpenSSL::HMAC.hexdigest(
+ VERIFICATION_HMAC_ALGORITHM,
+ Gitlab::CurrentSettings.slack_app_signing_secret,
+ basestring
+ )
+
+ # Signature will look like: 'v0=a2114d57b48eac39b9ad189dd8316235a7b4a8d21a10bd27519666489c69b503'
+ ActiveSupport::SecurityUtils.secure_compare(
+ signature,
+ "#{VERIFICATION_VERSION}=#{hmac_digest}"
+ )
+ end
+ end
+ end
+ end
+end