Skip to content

Commit d53660f

Browse files
authored
Improve the installation data queries to always return the latest bot token (#1223)
1 parent 64e6a80 commit d53660f

File tree

4 files changed

+107
-4
lines changed

4 files changed

+107
-4
lines changed

slack_sdk/oauth/installation_store/amazon_s3/__init__.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,29 @@ def find_installation(
213213
self.logger.debug(f"S3 get_object response: {fetch_response}")
214214
body = fetch_response["Body"].read().decode("utf-8")
215215
data = json.loads(body)
216-
return Installation(**data)
216+
installation = Installation(**data)
217+
218+
if installation is not None and user_id is not None:
219+
# Retrieve the latest bot token, just in case
220+
# See also: https://github.com/slackapi/bolt-python/issues/664
221+
latest_bot_installation = self.find_installation(
222+
enterprise_id=enterprise_id,
223+
team_id=team_id,
224+
is_enterprise_install=is_enterprise_install,
225+
)
226+
if latest_bot_installation is not None and installation.bot_token != latest_bot_installation.bot_token:
227+
# NOTE: this logic is based on the assumption that every single installation has bot scopes
228+
# If you need to installation patterns without bot scopes in the same S3 bucket,
229+
# please fork this code and implement your own logic.
230+
installation.bot_id = latest_bot_installation.bot_id
231+
installation.bot_user_id = latest_bot_installation.bot_user_id
232+
installation.bot_token = latest_bot_installation.bot_token
233+
installation.bot_scopes = latest_bot_installation.bot_scopes
234+
installation.bot_refresh_token = latest_bot_installation.bot_refresh_token
235+
installation.bot_token_expires_at = latest_bot_installation.bot_token_expires_at
236+
237+
return installation
238+
217239
except Exception as e: # skipcq: PYL-W0703
218240
message = f"Failed to find an installation data for enterprise: {e_id}, team: {t_id}: {e}"
219241
self.logger.warning(message)

slack_sdk/oauth/installation_store/file/__init__.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,32 @@ def find_installation(
164164
installation_filepath = f"{self.base_dir}/{e_id}-{t_id}/installer-{user_id}-latest"
165165

166166
try:
167+
installation: Optional[Installation] = None
167168
with open(installation_filepath) as f:
168169
data = json.loads(f.read())
169-
return Installation(**data)
170+
installation = Installation(**data)
171+
172+
if installation is not None and user_id is not None:
173+
# Retrieve the latest bot token, just in case
174+
# See also: https://github.com/slackapi/bolt-python/issues/664
175+
latest_bot_installation = self.find_installation(
176+
enterprise_id=enterprise_id,
177+
team_id=team_id,
178+
is_enterprise_install=is_enterprise_install,
179+
)
180+
if latest_bot_installation is not None and installation.bot_token != latest_bot_installation.bot_token:
181+
# NOTE: this logic is based on the assumption that every single installation has bot scopes
182+
# If you need to installation patterns without bot scopes in the same S3 bucket,
183+
# please fork this code and implement your own logic.
184+
installation.bot_id = latest_bot_installation.bot_id
185+
installation.bot_user_id = latest_bot_installation.bot_user_id
186+
installation.bot_token = latest_bot_installation.bot_token
187+
installation.bot_scopes = latest_bot_installation.bot_scopes
188+
installation.bot_refresh_token = latest_bot_installation.bot_refresh_token
189+
installation.bot_token_expires_at = latest_bot_installation.bot_token_expires_at
190+
191+
return installation
192+
170193
except FileNotFoundError as e:
171194
message = f"Installation data missing for enterprise: {e_id}, team: {t_id}: {e}"
172195
self.logger.debug(message)

slack_sdk/oauth/installation_store/sqlalchemy/__init__.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,11 @@ def find_installation(
258258

259259
query = self.installations.select().where(where_clause).order_by(desc(c.installed_at)).limit(1)
260260

261+
installation: Optional[Installation] = None
261262
with self.engine.connect() as conn:
262263
result: object = conn.execute(query)
263264
for row in result: # type: ignore
264-
return Installation(
265+
installation = Installation(
265266
app_id=row["app_id"],
266267
enterprise_id=row["enterprise_id"],
267268
enterprise_name=row["enterprise_name"],
@@ -288,7 +289,28 @@ def find_installation(
288289
token_type=row["token_type"],
289290
installed_at=row["installed_at"],
290291
)
291-
return None
292+
293+
if user_id is not None and installation is not None:
294+
# Retrieve the latest bot token, just in case
295+
# See also: https://github.com/slackapi/bolt-python/issues/664
296+
where_clause = and_(
297+
c.client_id == self.client_id,
298+
c.enterprise_id == enterprise_id,
299+
c.team_id == team_id,
300+
c.bot_token.is_not(None), # the latest one that has a bot token
301+
)
302+
query = self.installations.select().where(where_clause).order_by(desc(c.installed_at)).limit(1)
303+
with self.engine.connect() as conn:
304+
result: object = conn.execute(query)
305+
for row in result: # type: ignore
306+
installation.bot_token = row["bot_token"]
307+
installation.bot_id = row["bot_id"]
308+
installation.bot_user_id = row["bot_user_id"]
309+
installation.bot_scopes = row["bot_scopes"]
310+
installation.bot_refresh_token = row["bot_refresh_token"]
311+
installation.bot_token_expires_at = row["bot_token_expires_at"]
312+
313+
return installation
292314

293315
def delete_bot(self, *, enterprise_id: Optional[str], team_id: Optional[str]) -> None:
294316
table = self.bots

slack_sdk/oauth/installation_store/sqlite3/__init__.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,42 @@ def find_installation(
489489
token_type=row[22],
490490
installed_at=row[23],
491491
)
492+
493+
if user_id is not None:
494+
# Retrieve the latest bot token, just in case
495+
# See also: https://github.com/slackapi/bolt-python/issues/664
496+
cur = conn.execute(
497+
"""
498+
select
499+
bot_token,
500+
bot_id,
501+
bot_user_id,
502+
bot_scopes,
503+
bot_refresh_token,
504+
bot_token_expires_at
505+
from
506+
slack_installations
507+
where
508+
client_id = ?
509+
and
510+
enterprise_id = ?
511+
and
512+
team_id = ?
513+
and
514+
bot_token is not null
515+
order by installed_at desc
516+
limit 1
517+
""",
518+
[self.client_id, enterprise_id or "", team_id],
519+
)
520+
row = cur.fetchone()
521+
installation.bot_token = row[0]
522+
installation.bot_id = row[1]
523+
installation.bot_user_id = row[2]
524+
installation.bot_scopes = row[3]
525+
installation.bot_refresh_token = row[4]
526+
installation.bot_token_expires_at = row[5]
527+
492528
return installation
493529
return None
494530

0 commit comments

Comments
 (0)