Skip to content

Commit

Permalink
Fix #183 Easier way to configure the installation URL as the direct i…
Browse files Browse the repository at this point in the history
…nstall URL on App Directory
  • Loading branch information
seratch committed Jan 9, 2021
1 parent 899ce76 commit 512a53c
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 22 deletions.
31 changes: 21 additions & 10 deletions slack_bolt/oauth/async_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,30 @@ def sqlite3(
async def handle_installation(self, request: AsyncBoltRequest) -> BoltResponse:
state = await self.issue_new_state(request)
url = await self.build_authorize_url(state, request)
html = await self.build_install_page_html(url, request)
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
state
)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
if self.settings.install_page_rendering_enabled:
html = await self.build_install_page_html(url, request)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
else:
return BoltResponse(
status=302,
body="",
headers={
"Content-Type": "text/html; charset=utf-8",
"Location": url,
"Set-Cookie": [set_cookie_value],
},
)

# ----------------------
# Internal methods for Installation
Expand Down
4 changes: 4 additions & 0 deletions slack_bolt/oauth/async_oauth_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AsyncOAuthSettings:
redirect_uri: Optional[str]
# Handler configuration
install_path: str
install_page_rendering_enabled: bool
redirect_uri_path: str
callback_options: Optional[CallbackOptions] = None
success_url: Optional[str]
Expand Down Expand Up @@ -63,6 +64,7 @@ def __init__(
redirect_uri: Optional[str] = None,
# Handler configuration
install_path: str = "/slack/install",
install_page_rendering_enabled: bool = True,
redirect_uri_path: str = "/slack/oauth_redirect",
callback_options: Optional[CallbackOptions] = None,
success_url: Optional[str] = None,
Expand All @@ -86,6 +88,7 @@ def __init__(
:param user_scopes: Check the value in Settings > Manage Distribution
:param redirect_uri: Check the value in Features > OAuth & Permissions > Redirect URLs
:param install_path: The endpoint to start an OAuth flow (Default: /slack/install)
:param install_page_rendering_enabled: Renders a web page for install_path access if True
:param redirect_uri_path: The path of Redirect URL (Default: /slack/oauth_redirect)
:param callback_options: Give success/failure functions f you want to customize callback functions.
:param success_url: Set a complete URL if you want to redirect end-users when an installation completes.
Expand Down Expand Up @@ -119,6 +122,7 @@ def __init__(
self.install_path = install_path or os.environ.get(
"SLACK_INSTALL_PATH", "/slack/install"
)
self.install_page_rendering_enabled = install_page_rendering_enabled
self.redirect_uri_path = redirect_uri_path or os.environ.get(
"SLACK_REDIRECT_URI_PATH", "/slack/oauth_redirect"
)
Expand Down
31 changes: 21 additions & 10 deletions slack_bolt/oauth/oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,30 @@ def sqlite3(
def handle_installation(self, request: BoltRequest) -> BoltResponse:
state = self.issue_new_state(request)
url = self.build_authorize_url(state, request)
html = self.build_install_page_html(url, request)
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
state
)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
if self.settings.install_page_rendering_enabled:
html = self.build_install_page_html(url, request)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
else:
return BoltResponse(
status=302,
body="",
headers={
"Content-Type": "text/html; charset=utf-8",
"Location": url,
"Set-Cookie": [set_cookie_value],
},
)

# ----------------------
# Internal methods for Installation
Expand Down
4 changes: 4 additions & 0 deletions slack_bolt/oauth/oauth_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class OAuthSettings:
redirect_uri: Optional[str]
# Handler configuration
install_path: str
install_page_rendering_enabled: bool
redirect_uri_path: str
callback_options: Optional[CallbackOptions] = None
success_url: Optional[str]
Expand Down Expand Up @@ -58,6 +59,7 @@ def __init__(
redirect_uri: Optional[str] = None,
# Handler configuration
install_path: str = "/slack/install",
install_page_rendering_enabled: bool = True,
redirect_uri_path: str = "/slack/oauth_redirect",
callback_options: Optional[CallbackOptions] = None,
success_url: Optional[str] = None,
Expand All @@ -81,6 +83,7 @@ def __init__(
:param user_scopes: Check the value in Settings > Manage Distribution
:param redirect_uri: Check the value in Features > OAuth & Permissions > Redirect URLs
:param install_path: The endpoint to start an OAuth flow (Default: /slack/install)
:param install_page_rendering_enabled: Renders a web page for install_path access if True
:param redirect_uri_path: The path of Redirect URL (Default: /slack/oauth_redirect)
:param callback_options: Give success/failure functions f you want to customize callback functions.
:param success_url: Set a complete URL if you want to redirect end-users when an installation completes.
Expand Down Expand Up @@ -113,6 +116,7 @@ def __init__(
self.install_path = install_path or os.environ.get(
"SLACK_INSTALL_PATH", "/slack/install"
)
self.install_page_rendering_enabled = install_page_rendering_enabled
self.redirect_uri_path = redirect_uri_path or os.environ.get(
"SLACK_REDIRECT_URI_PATH", "/slack/oauth_redirect"
)
Expand Down
22 changes: 21 additions & 1 deletion tests/slack_bolt/oauth/test_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_instantiation(self):
assert oauth_flow.logger is not None
assert oauth_flow.client is not None

def test_handle_installation(self):
def test_handle_installation_default(self):
oauth_flow = OAuthFlow(
settings=OAuthSettings(
client_id="111.222",
Expand All @@ -58,6 +58,26 @@ def test_handle_installation(self):
assert resp.headers.get("content-length") == ["576"]
assert "https://slack.com/oauth/v2/authorize?state=" in resp.body

# https://github.com/slackapi/bolt-python/issues/183
# For direct install URL suppport
def test_handle_installation_no_rendering(self):
oauth_flow = OAuthFlow(
settings=OAuthSettings(
client_id="111.222",
client_secret="xxx",
scopes=["chat:write", "commands"],
user_scopes=["search:read"],
installation_store=FileInstallationStore(),
install_page_rendering_enabled=False, # disabled
state_store=FileOAuthStateStore(expiration_seconds=120),
)
)
req = BoltRequest(body="")
resp = oauth_flow.handle_installation(req)
assert resp.status == 302
location_header = resp.headers.get("location")[0]
assert "https://slack.com/oauth/v2/authorize?state=" in location_header

def test_scopes_as_str(self):
settings = OAuthSettings(
client_id="111.222",
Expand Down
20 changes: 19 additions & 1 deletion tests/slack_bolt_async/oauth/test_async_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async def test_instantiation_non_async_settings_to_app(self):
)

@pytest.mark.asyncio
async def test_handle_installation(self):
async def test_handle_installation_default(self):
oauth_flow = AsyncOAuthFlow(
settings=AsyncOAuthSettings(
client_id="111.222",
Expand All @@ -109,6 +109,24 @@ async def test_handle_installation(self):
assert resp.headers.get("content-length") == ["565"]
assert "https://slack.com/oauth/v2/authorize?state=" in resp.body

@pytest.mark.asyncio
async def test_handle_installation_no_rendering(self):
oauth_flow = AsyncOAuthFlow(
settings=AsyncOAuthSettings(
client_id="111.222",
client_secret="xxx",
scopes=["chat:write", "commands"],
installation_store=FileInstallationStore(),
install_page_rendering_enabled=False, # disabled
state_store=FileOAuthStateStore(expiration_seconds=120),
)
)
req = AsyncBoltRequest(body="")
resp = await oauth_flow.handle_installation(req)
assert resp.status == 302
location_header = resp.headers.get("location")[0]
assert "https://slack.com/oauth/v2/authorize?state=" in location_header

@pytest.mark.asyncio
async def test_handle_callback(self):
oauth_flow = AsyncOAuthFlow(
Expand Down

0 comments on commit 512a53c

Please sign in to comment.