Skip to content

Commit 7b00fef

Browse files
committed
Fix #121 by changing the built-in middleware
1 parent 4ecce6b commit 7b00fef

File tree

8 files changed

+193
-3
lines changed

8 files changed

+193
-3
lines changed

slack_bolt/middleware/authorization/async_multi_teams_authorization.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from slack_bolt.response import BoltResponse
77
from .async_authorization import AsyncAuthorization
88
from .async_internals import _build_error_response, _is_no_auth_required
9+
from .internals import _is_no_auth_test_call_required
910
from ...authorization import AuthorizeResult
1011
from ...authorization.async_authorize import AsyncAuthorize
1112
from ...util.async_utils import create_async_web_client
@@ -31,6 +32,17 @@ async def async_process(
3132
) -> BoltResponse:
3233
if _is_no_auth_required(req):
3334
return await next()
35+
36+
if _is_no_auth_test_call_required(req):
37+
req.context.set_authorize_result(
38+
AuthorizeResult(
39+
enterprise_id=req.context.enterprise_id,
40+
team_id=req.context.team_id,
41+
user_id=req.context.user_id,
42+
)
43+
)
44+
return await next()
45+
3446
try:
3547
auth_result: Optional[AuthorizeResult] = await self.authorize(
3648
context=req.context,

slack_bolt/middleware/authorization/async_single_team_authorization.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from slack_sdk.web.async_slack_response import AsyncSlackResponse
88
from slack_sdk.errors import SlackApiError
99
from .async_internals import _build_error_response, _is_no_auth_required
10-
from .internals import _to_authorize_result
10+
from .internals import _to_authorize_result, _is_no_auth_test_call_required
11+
from ...authorization import AuthorizeResult
1112

1213

1314
class AsyncSingleTeamAuthorization(AsyncAuthorization):
@@ -26,6 +27,16 @@ async def async_process(
2627
if _is_no_auth_required(req):
2728
return await next()
2829

30+
if _is_no_auth_test_call_required(req):
31+
req.context.set_authorize_result(
32+
AuthorizeResult(
33+
enterprise_id=req.context.enterprise_id,
34+
team_id=req.context.team_id,
35+
user_id=req.context.user_id,
36+
)
37+
)
38+
return await next()
39+
2940
try:
3041
if self.auth_test_result is None:
3142
self.auth_test_result = await req.context.client.auth_test()

slack_bolt/middleware/authorization/internals.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,32 @@ def _is_ssl_check(req: BoltRequest) -> bool:
2121
)
2222

2323

24+
def _is_uninstallation_event(req: BoltRequest) -> bool:
25+
return (
26+
req is not None
27+
and req.body is not None
28+
and req.body.get("type") == "event_callback"
29+
and req.body.get("event", {}).get("type") == "app_uninstalled"
30+
)
31+
32+
33+
def _is_tokens_revoked_event(req: BoltRequest) -> bool:
34+
return (
35+
req is not None
36+
and req.body is not None
37+
and req.body.get("type") == "event_callback"
38+
and req.body.get("event", {}).get("type") == "tokens_revoked"
39+
)
40+
41+
2442
def _is_no_auth_required(req: BoltRequest) -> bool:
2543
return _is_url_verification(req) or _is_ssl_check(req)
2644

2745

46+
def _is_no_auth_test_call_required(req: BoltRequest) -> bool:
47+
return _is_uninstallation_event(req) or _is_tokens_revoked_event(req)
48+
49+
2850
def _build_error_response() -> BoltResponse:
2951
# show an ephemeral message to the end-user
3052
return BoltResponse(

slack_bolt/middleware/authorization/multi_teams_authorization.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
from slack_bolt.response import BoltResponse
66
from slack_sdk.errors import SlackApiError
77
from .authorization import Authorization
8-
from .internals import _build_error_response, _is_no_auth_required
8+
from .internals import (
9+
_build_error_response,
10+
_is_no_auth_required,
11+
_is_no_auth_test_call_required,
12+
)
913
from ...authorization import AuthorizeResult
1014
from ...authorization.authorize import Authorize
1115
from ...util.utils import create_web_client
@@ -29,6 +33,17 @@ def process(
2933
) -> BoltResponse:
3034
if _is_no_auth_required(req):
3135
return next()
36+
37+
if _is_no_auth_test_call_required(req):
38+
req.context.set_authorize_result(
39+
AuthorizeResult(
40+
enterprise_id=req.context.enterprise_id,
41+
team_id=req.context.team_id,
42+
user_id=req.context.user_id,
43+
)
44+
)
45+
return next()
46+
3247
try:
3348
auth_result: Optional[AuthorizeResult] = self.authorize(
3449
context=req.context,

slack_bolt/middleware/authorization/single_team_authorization.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
_build_error_response,
1111
_is_no_auth_required,
1212
_to_authorize_result,
13+
_is_no_auth_test_call_required,
1314
)
15+
from ...authorization import AuthorizeResult
1416

1517

1618
class SingleTeamAuthorization(Authorization):
@@ -28,6 +30,16 @@ def process(
2830
if _is_no_auth_required(req):
2931
return next()
3032

33+
if _is_no_auth_test_call_required(req):
34+
req.context.set_authorize_result(
35+
AuthorizeResult(
36+
enterprise_id=req.context.enterprise_id,
37+
team_id=req.context.team_id,
38+
user_id=req.context.user_id,
39+
)
40+
)
41+
return next()
42+
3143
try:
3244
if not self.auth_test_result:
3345
self.auth_test_result = req.context.client.auth_test()

slack_bolt/middleware/ignoring_self_events/ignoring_self_events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def _is_self_event(
3636
):
3737
return (
3838
auth_result is not None
39+
and user_id is not None
3940
and user_id == auth_result.bot_user_id
4041
and body.get("event") is not None
4142
and body.get("event", {}).get("type") not in cls.events_that_should_be_kept

tests/scenario_tests/test_events.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from slack_sdk.signature import SignatureVerifier
55
from slack_sdk.web import WebClient
66

7-
from slack_bolt import App, BoltRequest
7+
from slack_bolt import App, BoltRequest, Say
88
from tests.mock_web_api_server import (
99
setup_mock_web_api_server,
1010
cleanup_mock_web_api_server,
@@ -335,3 +335,60 @@ def handle_app_mention(say):
335335
sleep(1) # wait a bit after auto ack()
336336
# the listeners should not be executed
337337
assert self.mock_received_requests["/chat.postMessage"] == 2
338+
339+
def test_uninstallation_and_revokes(self):
340+
app = App(client=self.web_client, signing_secret=self.signing_secret)
341+
app._client = WebClient(
342+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
343+
)
344+
345+
@app.event("app_uninstalled")
346+
def handler1(say: Say):
347+
say(channel="C111", text="What's up?")
348+
349+
@app.event("tokens_revoked")
350+
def handler2(say: Say):
351+
say(channel="C111", text="What's up?")
352+
353+
app_uninstalled_body = {
354+
"token": "verification_token",
355+
"team_id": "T111",
356+
"enterprise_id": "E111",
357+
"api_app_id": "A111",
358+
"event": {"type": "app_uninstalled"},
359+
"type": "event_callback",
360+
"event_id": "Ev111",
361+
"event_time": 1599616881,
362+
}
363+
364+
timestamp, body = str(int(time())), json.dumps(app_uninstalled_body)
365+
request: BoltRequest = BoltRequest(
366+
body=body, headers=self.build_headers(timestamp, body)
367+
)
368+
response = app.dispatch(request)
369+
assert response.status == 200
370+
371+
tokens_revoked_body = {
372+
"token": "verification_token",
373+
"team_id": "T111",
374+
"enterprise_id": "E111",
375+
"api_app_id": "A111",
376+
"event": {
377+
"type": "tokens_revoked",
378+
"tokens": {"oauth": ["UXXXXXXXX"], "bot": ["UXXXXXXXX"]},
379+
},
380+
"type": "event_callback",
381+
"event_id": "Ev111",
382+
"event_time": 1599616881,
383+
}
384+
385+
timestamp, body = str(int(time())), json.dumps(tokens_revoked_body)
386+
request: BoltRequest = BoltRequest(
387+
body=body, headers=self.build_headers(timestamp, body)
388+
)
389+
response = app.dispatch(request)
390+
assert response.status == 200
391+
392+
assert self.mock_received_requests["/auth.test"] == 1
393+
sleep(1) # wait a bit after auto ack()
394+
assert self.mock_received_requests["/chat.postMessage"] == 2

tests/scenario_tests_async/test_events.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from slack_sdk.web.async_client import AsyncWebClient
99

1010
from slack_bolt.app.async_app import AsyncApp
11+
from slack_bolt.context.say.async_say import AsyncSay
1112
from slack_bolt.request.async_request import AsyncBoltRequest
1213
from tests.mock_web_api_server import (
1314
setup_mock_web_api_server,
@@ -315,6 +316,65 @@ async def handle_member_left_channel(say):
315316
# The listeners should be executed
316317
assert self.mock_received_requests.get("/chat.postMessage") == 2
317318

319+
@pytest.mark.asyncio
320+
async def test_uninstallation_and_revokes(self):
321+
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
322+
app._client = AsyncWebClient(
323+
token="uninstalled-revoked", base_url=self.mock_api_server_base_url
324+
)
325+
326+
@app.event("app_uninstalled")
327+
async def handler1(say: AsyncSay):
328+
await say(channel="C111", text="What's up?")
329+
330+
@app.event("tokens_revoked")
331+
async def handler2(say: AsyncSay):
332+
await say(channel="C111", text="What's up?")
333+
334+
app_uninstalled_body = {
335+
"token": "verification_token",
336+
"team_id": "T111",
337+
"enterprise_id": "E111",
338+
"api_app_id": "A111",
339+
"event": {"type": "app_uninstalled"},
340+
"type": "event_callback",
341+
"event_id": "Ev111",
342+
"event_time": 1599616881,
343+
}
344+
345+
timestamp, body = str(int(time())), json.dumps(app_uninstalled_body)
346+
request: AsyncBoltRequest = AsyncBoltRequest(
347+
body=body, headers=self.build_headers(timestamp, body)
348+
)
349+
response = await app.async_dispatch(request)
350+
assert response.status == 200
351+
352+
tokens_revoked_body = {
353+
"token": "verification_token",
354+
"team_id": "T111",
355+
"enterprise_id": "E111",
356+
"api_app_id": "A111",
357+
"event": {
358+
"type": "tokens_revoked",
359+
"tokens": {"oauth": ["UXXXXXXXX"], "bot": ["UXXXXXXXX"]},
360+
},
361+
"type": "event_callback",
362+
"event_id": "Ev111",
363+
"event_time": 1599616881,
364+
}
365+
366+
timestamp, body = str(int(time())), json.dumps(tokens_revoked_body)
367+
request: AsyncBoltRequest = AsyncBoltRequest(
368+
body=body, headers=self.build_headers(timestamp, body)
369+
)
370+
response = await app.async_dispatch(request)
371+
assert response.status == 200
372+
373+
# AsyncApp doesn't call auth.test when booting
374+
assert self.mock_received_requests.get("/auth.test") is None
375+
await asyncio.sleep(1) # wait a bit after auto ack()
376+
assert self.mock_received_requests["/chat.postMessage"] == 2
377+
318378

319379
app_mention_body = {
320380
"token": "verification_token",

0 commit comments

Comments
 (0)