Skip to content

Commit a9dabc5

Browse files
Gabriel Dealdblock
authored andcommitted
Add support for specifying signing secrets on a per-request basis (#256)
1 parent d0c1b75 commit a9dabc5

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
### 0.14.2 (Next)
22

3+
* [#256](https://github.com/slack-ruby/slack-ruby-client/pull/256): Added support for specifying signing secrets on a per-request basis via optional parameters to the `Slack::Events::Request` constructor - [@gabrielmdeal](https://github.com/gabrielmdeal).
34
* Your contribution here.
45

56
### 0.14.1 (2019/2/26)

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,13 @@ slack_request = Slack::Events::Request.new(http_request)
506506
slack_request.verify!
507507
```
508508

509+
To specify secrets on a per-request basis:
510+
```ruby
511+
Slack::Events::Request.new(http_request,
512+
signing_secret: signing_secret,
513+
signature_expires_in: signature_expires_in)
514+
```
515+
509516
The `verify!` call may raise `Slack::Events::MissingSigningSecret`, `Slack::Events::InvalidSignature` or `Slack::Events::TimestampExpired` errors.
510517

511518
### Message Parsing

lib/slack/events/request.rb

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ class MissingSigningSecret < StandardError; end
55
class TimestampExpired < StandardError; end
66
class InvalidSignature < StandardError; end
77

8-
attr_reader :http_request
8+
attr_reader :http_request,
9+
:signing_secret,
10+
:signature_expires_in
911

10-
def initialize(http_request)
12+
def initialize(http_request, options = {})
1113
@http_request = http_request
14+
@signing_secret = options[:signing_secret] || Slack::Events.config.signing_secret
15+
@signature_expires_in = options[:signature_expires_in] || Slack::Events.config.signature_expires_in
1216
end
1317

1418
# Request timestamp.
@@ -34,16 +38,16 @@ def body
3438

3539
# Returns true if the signature coming from Slack has expired.
3640
def expired?
37-
timestamp.nil? || (Time.now.to_i - timestamp.to_i).abs > Slack::Events.config.signature_expires_in
41+
timestamp.nil? || (Time.now.to_i - timestamp.to_i).abs > signature_expires_in
3842
end
3943

4044
# Returns true if the signature coming from Slack is valid.
4145
def valid?
42-
raise MissingSigningSecret unless Slack::Events.config.signing_secret
46+
raise MissingSigningSecret unless signing_secret
4347

4448
digest = OpenSSL::Digest::SHA256.new
4549
signature_basestring = [version, timestamp, body].join(':')
46-
hex_hash = OpenSSL::HMAC.hexdigest(digest, Slack::Events.config.signing_secret, signature_basestring)
50+
hex_hash = OpenSSL::HMAC.hexdigest(digest, signing_secret, signature_basestring)
4751
computed_signature = [version, hex_hash].join('=')
4852
computed_signature == signature
4953
end

spec/slack/events/request_spec.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
RSpec.describe Slack::Events::Request do
44
before do
55
Slack::Events.configure do |config|
6-
config.signing_secret = 'ade6ca762ade4db0e7d31484cd616b9c'
6+
config.signing_secret = signing_secret
77
config.signature_expires_in = 30
88
end
99
end
10+
let(:signing_secret) { 'ade6ca762ade4db0e7d31484cd616b9c' }
1011
let(:signature) { 'v0=91177eea054d65de0fc0f9b4ec57714307bc0ce2c5f3bf0d28b1b720c8f92ba2' }
1112
let(:timestamp) { '1547933148' }
1213
let(:body) { '{"token":"X34FAqCu8tmGEkEEpoDncnja","challenge":"P7sFXA4o3HV2hTx4zb4zcQ9yrvuQs8pDh6EacOxmMRj0tJaXfQFF","type":"url_verification"}' }
@@ -115,6 +116,33 @@
115116
end
116117
end
117118
end
119+
context 'without global config' do
120+
before do
121+
Slack::Events.config.reset
122+
end
123+
context 'without a signing secret parameter' do
124+
subject do
125+
Slack::Events::Request.new(http_request)
126+
end
127+
it 'raises MissingSigningSecret' do
128+
expect { subject.valid? }.to raise_error Slack::Events::Request::MissingSigningSecret
129+
end
130+
end
131+
context 'with a signing secret parameter' do
132+
subject do
133+
Slack::Events::Request.new(http_request,
134+
signing_secret: signing_secret,
135+
signature_expires_in: 30)
136+
end
137+
before do
138+
Timecop.freeze(Time.at(timestamp.to_i))
139+
end
140+
it 'is valid and not expired' do
141+
expect(subject).to be_valid
142+
expect(subject).to_not be_expired
143+
end
144+
end
145+
end
118146
after do
119147
Slack::Events.config.reset
120148
end

0 commit comments

Comments
 (0)