Skip to content

Commit 7b4b082

Browse files
authored
Improve the default OAuth page renderers not to embed any params without escaping them (#882)
1 parent eae0d4e commit 7b4b082

File tree

7 files changed

+35
-12
lines changed

7 files changed

+35
-12
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
),
5959
include_package_data=True, # MANIFEST.in
6060
install_requires=[
61-
"slack_sdk>=3.20.2,<4",
61+
"slack_sdk>=3.21.1,<4",
6262
],
6363
setup_requires=["pytest-runner==5.2"],
6464
tests_require=async_test_dependencies,

slack_bolt/oauth/internals.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import html
12
from logging import Logger
23
from typing import Optional
34
from typing import Union
@@ -32,7 +33,7 @@ def _build_callback_success_response( # type: ignore
3233
debug_message = f"Handling an OAuth callback success (request: {request.query})"
3334
self._logger.debug(debug_message)
3435

35-
html = self._redirect_uri_page_renderer.render_success_page(
36+
page_content = self._redirect_uri_page_renderer.render_success_page(
3637
app_id=installation.app_id,
3738
team_id=installation.team_id,
3839
is_enterprise_install=installation.is_enterprise_install,
@@ -44,7 +45,7 @@ def _build_callback_success_response( # type: ignore
4445
"Content-Type": "text/html; charset=utf-8",
4546
"Set-Cookie": self._state_utils.build_set_cookie_for_deletion(),
4647
},
47-
body=html,
48+
body=page_content,
4849
)
4950

5051
def _build_callback_failure_response( # type: ignore
@@ -60,14 +61,13 @@ def _build_callback_failure_response( # type: ignore
6061
# Adding a bit more details to the error code to help installers understand what's happening.
6162
# This modification in the HTML page works only when developers use this built-in failure handler.
6263
detailed_error = build_detailed_error(reason)
63-
html = self._redirect_uri_page_renderer.render_failure_page(detailed_error)
6464
return BoltResponse(
6565
status=status,
6666
headers={
6767
"Content-Type": "text/html; charset=utf-8",
6868
"Set-Cookie": self._state_utils.build_set_cookie_for_deletion(),
6969
},
70-
body=html,
70+
body=self._redirect_uri_page_renderer.render_failure_page(detailed_error),
7171
)
7272

7373

@@ -85,7 +85,7 @@ def _build_default_install_page_html(url: str) -> str:
8585
</head>
8686
<body>
8787
<h2>Slack App Installation</h2>
88-
<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>
88+
<p><a href="{html.escape(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>
8989
</body>
9090
</html>
9191
""" # noqa: E501
@@ -142,4 +142,4 @@ def build_detailed_error(reason: str) -> str:
142142
elif reason == "storage_error":
143143
return f"{reason}: The app's server encountered an issue. Contact the app developer."
144144
else:
145-
return f"{reason}: This error code is returned from Slack. Refer to the documents for details."
145+
return f"{html.escape(reason)}: This error code is returned from Slack. Refer to the documents for details."

tests/adapter_tests_async/test_async_falcon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,5 +201,5 @@ def test_oauth(self):
201201
response = client.simulate_get("/slack/install")
202202
assert response.status_code == 200
203203
assert response.headers.get("content-type") == "text/html; charset=utf-8"
204-
assert response.headers.get("content-length") == "597"
204+
assert response.headers.get("content-length") == "609"
205205
assert "https://slack.com/oauth/v2/authorize?state=" in response.text

tests/adapter_tests_async/test_async_fastapi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ async def endpoint(req: Request):
209209
response = client.get("/slack/install", allow_redirects=False)
210210
assert response.status_code == 200
211211
assert response.headers.get("content-type") == "text/html; charset=utf-8"
212-
assert response.headers.get("content-length") == "597"
212+
assert response.headers.get("content-length") == "609"
213213
assert "https://slack.com/oauth/v2/authorize?state=" in response.text
214214

215215
def test_custom_props(self):

tests/adapter_tests_async/test_async_sanic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,6 @@ async def endpoint(req: Request):
221221

222222
# NOTE: Although sanic-testing 0.6 does not have this value,
223223
# Sanic apps properly generate the content-length header
224-
# assert response.headers.get("content-length") == "597"
224+
# assert response.headers.get("content-length") == "609"
225225

226226
assert "https://slack.com/oauth/v2/authorize?state=" in response.text

tests/adapter_tests_async/test_async_starlette.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,5 +219,5 @@ async def endpoint(req: Request):
219219
response = client.get("/slack/install", allow_redirects=False)
220220
assert response.status_code == 200
221221
assert response.headers.get("content-type") == "text/html; charset=utf-8"
222-
assert response.headers.get("content-length") == "597"
222+
assert response.headers.get("content-length") == "609"
223223
assert "https://slack.com/oauth/v2/authorize?state=" in response.text

tests/slack_bolt/oauth/test_internals.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from slack_bolt.oauth.internals import build_detailed_error
1+
from slack_bolt.oauth.internals import build_detailed_error, _build_default_install_page_html
22

33

44
class TestOAuthInternals:
@@ -23,3 +23,26 @@ def test_build_detailed_error_others(self):
2323
assert result.startswith(
2424
"access_denied: This error code is returned from Slack. Refer to the documents for details."
2525
)
26+
27+
def test_build_detailed_error_others_with_tags(self):
28+
result = build_detailed_error("<b>test</b>")
29+
assert result.startswith(
30+
"&lt;b&gt;test&lt;/b&gt;: This error code is returned from Slack. Refer to the documents for details."
31+
)
32+
33+
def test_build_default_install_page_html(self):
34+
test_patterns = [
35+
{
36+
"input": "https://slack.com/oauth/v2/authorize?state=random&client_id=111.222&scope=commands",
37+
"expected": "https://slack.com/oauth/v2/authorize?state=random&amp;client_id=111.222&amp;scope=commands",
38+
},
39+
{
40+
"input": "<b>test</b>",
41+
"expected": "&lt;b&gt;test&lt;/b&gt;",
42+
},
43+
]
44+
for pattern in test_patterns:
45+
url = pattern["input"]
46+
result = _build_default_install_page_html(url)
47+
assert url not in result
48+
assert pattern["expected"] in result

0 commit comments

Comments
 (0)