Skip to content

Commit d493319

Browse files
committed
Fix #140 by updating the default install page handler
1 parent 31599be commit d493319

21 files changed

+128
-115
lines changed

slack_bolt/oauth/async_oauth_flow.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
AsyncFailureArgs,
1212
)
1313
from slack_bolt.oauth.async_oauth_settings import AsyncOAuthSettings
14+
from slack_bolt.oauth.internals import _build_default_install_page_html
1415
from slack_bolt.request.async_request import AsyncBoltRequest
1516
from slack_bolt.response import BoltResponse
1617
from slack_sdk.errors import SlackApiError
@@ -151,26 +152,32 @@ def sqlite3(
151152

152153
async def handle_installation(self, request: AsyncBoltRequest) -> BoltResponse:
153154
state = await self.issue_new_state(request)
154-
return await self.build_authorize_url_redirection(request, state)
155+
url = await self.build_authorize_url(state, request)
156+
html = await self.build_install_page_html(url, request)
157+
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
158+
state
159+
)
160+
return BoltResponse(
161+
status=200,
162+
body=html,
163+
headers={
164+
"Content-Type": "text/html; charset=utf-8",
165+
"Content-Length": len(bytes(html, "utf-8")),
166+
"Set-Cookie": [set_cookie_value],
167+
},
168+
)
155169

156170
# ----------------------
157171
# Internal methods for Installation
158172

159173
async def issue_new_state(self, request: AsyncBoltRequest) -> str:
160174
return await self.settings.state_store.async_issue()
161175

162-
async def build_authorize_url_redirection(
163-
self, request: AsyncBoltRequest, state: str
164-
) -> BoltResponse:
165-
return BoltResponse(
166-
status=302,
167-
headers={
168-
"Location": [self.settings.authorize_url_generator.generate(state)],
169-
"Set-Cookie": [
170-
self.settings.state_utils.build_set_cookie_for_new_state(state)
171-
],
172-
},
173-
)
176+
async def build_authorize_url(self, state: str, request: AsyncBoltRequest) -> str:
177+
return self.settings.authorize_url_generator.generate(state)
178+
179+
async def build_install_page_html(self, url: str, request: AsyncBoltRequest) -> str:
180+
return _build_default_install_page_html(url)
174181

175182
# -----------------------------
176183
# Callback

slack_bolt/oauth/internals.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,22 @@ def _build_callback_failure_response( # type: ignore
6464
},
6565
body=html,
6666
)
67+
68+
69+
def _build_default_install_page_html(url: str) -> str:
70+
return f"""<html>
71+
<head>
72+
<style>
73+
body {{
74+
padding: 10px 15px;
75+
font-family: verdana;
76+
text-align: center;
77+
}}
78+
</style>
79+
</head>
80+
<body>
81+
<h2>Slack App Installation</h2>
82+
<p><a href="{url}"><img alt=""Add to Slack"" height="40" width="139" src="https://platform.slack-edge.com/img/add_to_slack.png" srcset="https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/[email protected] 2x" /></a></p>
83+
</body>
84+
</html>
85+
"""

slack_bolt/oauth/oauth_flow.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
DefaultCallbackOptions,
1111
CallbackOptions,
1212
)
13+
from slack_bolt.oauth.internals import _build_default_install_page_html
1314

1415
from slack_bolt.oauth.oauth_settings import OAuthSettings
1516
from slack_bolt.request import BoltRequest
@@ -151,26 +152,32 @@ def sqlite3(
151152

152153
def handle_installation(self, request: BoltRequest) -> BoltResponse:
153154
state = self.issue_new_state(request)
154-
return self.build_authorize_url_redirection(request, state)
155+
url = self.build_authorize_url(state, request)
156+
html = self.build_install_page_html(url, request)
157+
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
158+
state
159+
)
160+
return BoltResponse(
161+
status=200,
162+
body=html,
163+
headers={
164+
"Content-Type": "text/html; charset=utf-8",
165+
"Content-Length": len(bytes(html, "utf-8")),
166+
"Set-Cookie": [set_cookie_value],
167+
},
168+
)
155169

156170
# ----------------------
157171
# Internal methods for Installation
158172

159173
def issue_new_state(self, request: BoltRequest) -> str:
160174
return self.settings.state_store.issue()
161175

162-
def build_authorize_url_redirection(
163-
self, request: BoltRequest, state: str
164-
) -> BoltResponse:
165-
return BoltResponse(
166-
status=302,
167-
headers={
168-
"Location": [self.settings.authorize_url_generator.generate(state)],
169-
"Set-Cookie": [
170-
self.settings.state_utils.build_set_cookie_for_new_state(state)
171-
],
172-
},
173-
)
176+
def build_authorize_url(self, state: str, request: BoltRequest) -> str:
177+
return self.settings.authorize_url_generator.generate(state)
178+
179+
def build_install_page_html(self, url: str, request: BoltRequest) -> str:
180+
return _build_default_install_page_html(url)
174181

175182
# -----------------------------
176183
# Callback

tests/adapter_tests/test_aws_chalice.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,7 @@ def install() -> Response:
272272
response: Dict[str, Any] = LocalGateway(chalice_app, Config()).handle_request(
273273
method="GET", path="/slack/install", body="", headers={}
274274
)
275-
assert response["statusCode"] == 302
275+
assert response["statusCode"] == 200
276+
assert response["headers"]["content-type"] == "text/html; charset=utf-8"
277+
assert response["headers"]["content-length"] == "565"
278+
assert response.get("body") is not None

tests/adapter_tests/test_aws_lambda.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,10 @@ def test_oauth(self):
283283
"isBase64Encoded": False,
284284
}
285285
response = SlackRequestHandler(app).handle(event, self.context)
286-
assert response["statusCode"] == 302
286+
assert response["statusCode"] == 200
287+
assert response["headers"]["content-type"] == "text/html; charset=utf-8"
288+
assert response["headers"]["content-length"] == "565"
289+
assert response.get("body") is not None
287290

288291
event = {
289292
"body": "",
@@ -293,4 +296,7 @@ def test_oauth(self):
293296
"isBase64Encoded": False,
294297
}
295298
response = SlackRequestHandler(app).handle(event, self.context)
296-
assert response["statusCode"] == 302
299+
assert response["statusCode"] == 200
300+
assert response["headers"]["content-type"] == "text/html; charset=utf-8"
301+
assert response["headers"]["content-length"] == "565"
302+
assert response.get("body") is not None

tests/adapter_tests/test_bottle_oauth.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ class TestBottle:
2626
def test_oauth(self):
2727
with boddle(method="GET", path="/slack/install"):
2828
response_body = install()
29-
assert response_body == ""
30-
assert response.status_code == 302
31-
assert re.match(
32-
"https://slack.com/oauth/v2/authorize\\?state=[^&]+&client_id=111.111&scope=chat:write,commands&user_scope=",
33-
response.headers["Location"],
34-
)
29+
assert response.status_code == 200
30+
assert response.headers.get("content-type") == "text/html; charset=utf-8"
31+
assert "https://slack.com/oauth/v2/authorize?state=" in response_body

tests/adapter_tests/test_cherrypy_oauth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ def teardown_class(cls):
4949
def test_oauth(self):
5050
cherrypy.request.process_request_body = False
5151
self.getPage("/slack/install", method="GET")
52-
self.assertStatus("302 Found")
52+
self.assertStatus("200 OK")

tests/adapter_tests/test_django.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,9 @@ def test_oauth(self):
170170
)
171171
request = self.rf.get("/slack/install")
172172
response = SlackRequestHandler(app).handle(request)
173-
assert response.status_code == 302
173+
assert response.status_code == 200
174+
assert response.get("content-type") == "text/html; charset=utf-8"
175+
assert response.get("content-length") == "565"
176+
assert "https://slack.com/oauth/v2/authorize?state=" in response.content.decode(
177+
"utf-8"
178+
)

tests/adapter_tests/test_falcon.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,5 @@ def test_oauth(self):
179179

180180
client = testing.TestClient(api)
181181
response = client.simulate_get("/slack/install")
182-
assert response.status_code == 302
183-
assert re.match(
184-
"https://slack.com/oauth/v2/authorize\\?state=[^&]+&client_id=111.111&scope=chat:write,commands&user_scope=",
185-
response.headers["Location"],
186-
)
182+
assert response.status_code == 200
183+
assert "https://slack.com/oauth/v2/authorize?state=" in response.text

tests/adapter_tests/test_fastapi.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,7 @@ async def endpoint(req: Request):
192192

193193
client = TestClient(api)
194194
response = client.get("/slack/install", allow_redirects=False)
195-
assert response.status_code == 302
196-
assert re.match(
197-
"https://slack.com/oauth/v2/authorize\\?state=[^&]+&client_id=111.111&scope=chat:write,commands&user_scope=",
198-
response.headers["Location"],
199-
)
195+
assert response.status_code == 200
196+
assert response.headers.get("content-type") == "text/html; charset=utf-8"
197+
assert response.headers.get("content-length") == "565"
198+
assert "https://slack.com/oauth/v2/authorize?state=" in response.text

0 commit comments

Comments
 (0)