Skip to content

Commit c352e88

Browse files
committed
Add more tests and check for None values
1 parent 104bdc6 commit c352e88

File tree

2 files changed

+59
-10
lines changed

2 files changed

+59
-10
lines changed

slack/signature/verifier.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import hashlib
22
import hmac
33
from time import time
4-
from typing import Dict
4+
from typing import Dict, Optional
55

66

77
class Clock:
@@ -23,6 +23,8 @@ def __init__(self, signing_secret: str, clock: Clock = Clock()):
2323

2424
def is_valid_request(self, body: str, headers: Dict[str, str],) -> bool:
2525
"""Verifies if the given signature is valid"""
26+
if headers is None:
27+
return False
2628
normalized_headers = {k.lower(): v for k, v in headers.items()}
2729
return self.is_valid(
2830
body=body,
@@ -32,14 +34,25 @@ def is_valid_request(self, body: str, headers: Dict[str, str],) -> bool:
3234

3335
def is_valid(self, body: str, timestamp: str, signature: str,) -> bool:
3436
"""Verifies if the given signature is valid"""
37+
if timestamp is None or signature is None:
38+
return False
39+
3540
if abs(self.clock.now() - int(timestamp)) > 60 * 5:
3641
return False
3742

43+
if body is None:
44+
body = ""
45+
3846
calculated_signature = self.generate_signature(timestamp=timestamp, body=body)
47+
if calculated_signature is None:
48+
return False
3949
return hmac.compare_digest(calculated_signature, signature)
4050

41-
def generate_signature(self, *, timestamp: str, body: str) -> str:
51+
def generate_signature(self, *, timestamp: str, body: str) -> Optional[str]:
4252
"""Generates a signature"""
53+
if timestamp is None:
54+
return None
55+
4356
format_req = str.encode(f"v0:{timestamp}:{body}")
4457
encoded_secret = str.encode(self.signing_secret)
4558
request_hash = hmac.new(encoded_secret, format_req, hashlib.sha256).hexdigest()

tests/signature/test_signature_verifier.py

+44-8
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,72 @@ def setUp(self):
1515
def tearDown(self):
1616
pass
1717

18+
# https://api.slack.com/authentication/verifying-requests-from-slack
19+
signing_secret = "8f742231b10e8888abcd99yyyzzz85a5"
20+
1821
body = "token=xyzz0WbapA4vBCDEFasx0q6G&team_id=T1DC2JH3J&team_domain=testteamnow&channel_id=G8PSS9T3V&channel_name=foobar&user_id=U2CERLKJA&user_name=roadrunner&command=%2Fwebhook-collect&text=&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT1DC2JH3J%2F397700885554%2F96rGlfmibIGlgcZRskXaIFfN&trigger_id=398738663015.47445629121.803a0bc887a14d10d2c447fce8b6703c"
22+
23+
timestamp = "1531420618"
24+
valid_signature = "v0=a2114d57b48eac39b9ad189dd8316235a7b4a8d21a10bd27519666489c69b503"
25+
1926
headers = {
20-
"X-Slack-Request-Timestamp": "1531420618",
21-
"X-Slack-Signature": "v0=a2114d57b48eac39b9ad189dd8316235a7b4a8d21a10bd27519666489c69b503",
27+
"X-Slack-Request-Timestamp": timestamp,
28+
"X-Slack-Signature": valid_signature,
2229
}
2330

2431
def test_generate_signature(self):
25-
# https://api.slack.com/authentication/verifying-requests-from-slack
2632
verifier = SignatureVerifier("8f742231b10e8888abcd99yyyzzz85a5")
2733
timestamp = "1531420618"
2834
signature = verifier.generate_signature(timestamp=timestamp, body=self.body)
29-
self.assertEqual("v0=a2114d57b48eac39b9ad189dd8316235a7b4a8d21a10bd27519666489c69b503", signature)
35+
self.assertEqual(self.valid_signature, signature)
3036

3137
def test_is_valid_request(self):
3238
verifier = SignatureVerifier(
33-
signing_secret="8f742231b10e8888abcd99yyyzzz85a5",
39+
signing_secret=self.signing_secret,
3440
clock=MockClock()
3541
)
3642
self.assertTrue(verifier.is_valid_request(self.body, self.headers))
3743

3844
def test_is_valid_request_invalid_body(self):
3945
verifier = SignatureVerifier(
40-
signing_secret="8f742231b10e8888abcd99yyyzzz85a5",
41-
clock=MockClock()
46+
signing_secret=self.signing_secret,
47+
clock=MockClock(),
4248
)
4349
modified_body = self.body + "------"
4450
self.assertFalse(verifier.is_valid_request(modified_body, self.headers))
4551

4652
def test_is_valid_request_expiration(self):
4753
verifier = SignatureVerifier(
48-
signing_secret="8f742231b10e8888abcd99yyyzzz85a5"
54+
signing_secret=self.signing_secret,
4955
)
5056
self.assertFalse(verifier.is_valid_request(self.body, self.headers))
57+
58+
def test_is_valid_request_none(self):
59+
verifier = SignatureVerifier(
60+
signing_secret=self.signing_secret,
61+
clock=MockClock(),
62+
)
63+
self.assertFalse(verifier.is_valid_request(None, self.headers))
64+
self.assertFalse(verifier.is_valid_request(self.body, None))
65+
self.assertFalse(verifier.is_valid_request(None, None))
66+
67+
def test_is_valid(self):
68+
verifier = SignatureVerifier(
69+
signing_secret=self.signing_secret,
70+
clock=MockClock(),
71+
)
72+
self.assertTrue(verifier.is_valid(self.body, self.timestamp, self.valid_signature))
73+
self.assertTrue(verifier.is_valid(self.body, 1531420618, self.valid_signature))
74+
75+
def test_is_valid_none(self):
76+
verifier = SignatureVerifier(
77+
signing_secret=self.signing_secret,
78+
clock=MockClock(),
79+
)
80+
self.assertFalse(verifier.is_valid(None, self.timestamp, self.valid_signature))
81+
self.assertFalse(verifier.is_valid(self.body, None, self.valid_signature))
82+
self.assertFalse(verifier.is_valid(self.body, self.timestamp, None))
83+
self.assertFalse(verifier.is_valid(None, None, self.valid_signature))
84+
self.assertFalse(verifier.is_valid(None, self.timestamp, None))
85+
self.assertFalse(verifier.is_valid(self.body, None, None))
86+
self.assertFalse(verifier.is_valid(None, None, None))

0 commit comments

Comments
 (0)