Skip to content

Commit fcd0a35

Browse files
authored
Fix #1636 Custom Values passed into correctly into Bot/Installation class when cloned during token rotation (#1638)
1 parent c9fff5d commit fcd0a35

File tree

7 files changed

+77
-12
lines changed

7 files changed

+77
-12
lines changed

slack_sdk/oauth/installation_store/models/bot.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def set_custom_value(self, name: str, value: Any):
8787
def get_custom_value(self, name: str) -> Optional[Any]:
8888
return self.custom_values.get(name)
8989

90-
def to_dict(self) -> Dict[str, Any]:
91-
standard_values = {
90+
def _to_standard_value_dict(self) -> Dict[str, Any]:
91+
return {
9292
"app_id": self.app_id,
9393
"enterprise_id": self.enterprise_id,
9494
"enterprise_name": self.enterprise_name,
@@ -105,6 +105,11 @@ def to_dict(self) -> Dict[str, Any]:
105105
"is_enterprise_install": self.is_enterprise_install,
106106
"installed_at": datetime.utcfromtimestamp(self.installed_at),
107107
}
108+
109+
def to_dict_for_copying(self) -> Dict[str, Any]:
110+
return {"custom_values": self.custom_values, **self._to_standard_value_dict()}
111+
112+
def to_dict(self) -> Dict[str, Any]:
108113
# prioritize standard_values over custom_values
109114
# when the same keys exist in both
110-
return {**self.custom_values, **standard_values}
115+
return {**self.custom_values, **self._to_standard_value_dict()}

slack_sdk/oauth/installation_store/models/installation.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ def set_custom_value(self, name: str, value: Any):
159159
def get_custom_value(self, name: str) -> Optional[Any]:
160160
return self.custom_values.get(name)
161161

162-
def to_dict(self) -> Dict[str, Any]:
163-
standard_values = {
162+
def _to_standard_value_dict(self) -> Dict[str, Any]:
163+
return {
164164
"app_id": self.app_id,
165165
"enterprise_id": self.enterprise_id,
166166
"enterprise_name": self.enterprise_name,
@@ -190,6 +190,11 @@ def to_dict(self) -> Dict[str, Any]:
190190
"token_type": self.token_type,
191191
"installed_at": datetime.utcfromtimestamp(self.installed_at),
192192
}
193+
194+
def to_dict_for_copying(self) -> Dict[str, Any]:
195+
return {"custom_values": self.custom_values, **self._to_standard_value_dict()}
196+
197+
def to_dict(self) -> Dict[str, Any]:
193198
# prioritize standard_values over custom_values
194199
# when the same keys exist in both
195-
return {**self.custom_values, **standard_values}
200+
return {**self.custom_values, **self._to_standard_value_dict()}

slack_sdk/oauth/token_rotation/async_rotator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async def perform_token_rotation(
5454

5555
if rotated_bot is not None:
5656
if rotated_installation is None:
57-
rotated_installation = Installation(**installation.to_dict())
57+
rotated_installation = Installation(**installation.to_dict_for_copying())
5858
rotated_installation.bot_token = rotated_bot.bot_token
5959
rotated_installation.bot_refresh_token = rotated_bot.bot_refresh_token
6060
rotated_installation.bot_token_expires_at = rotated_bot.bot_token_expires_at
@@ -93,7 +93,7 @@ async def perform_bot_token_rotation(
9393
if refresh_response.get("token_type") != "bot":
9494
return None
9595

96-
refreshed_bot = Bot(**bot.to_dict())
96+
refreshed_bot = Bot(**bot.to_dict_for_copying())
9797
refreshed_bot.bot_token = refresh_response["access_token"]
9898
refreshed_bot.bot_refresh_token = refresh_response.get("refresh_token")
9999
refreshed_bot.bot_token_expires_at = int(time()) + int(refresh_response["expires_in"])
@@ -132,7 +132,7 @@ async def perform_user_token_rotation(
132132
if refresh_response.get("token_type") != "user":
133133
return None
134134

135-
refreshed_installation = Installation(**installation.to_dict())
135+
refreshed_installation = Installation(**installation.to_dict_for_copying())
136136
refreshed_installation.user_token = refresh_response.get("access_token")
137137
refreshed_installation.user_refresh_token = refresh_response.get("refresh_token")
138138
refreshed_installation.user_token_expires_at = int(time()) + int(refresh_response.get("expires_in")) # type: ignore[arg-type] # noqa: E501

slack_sdk/oauth/token_rotation/rotator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def perform_token_rotation(
4848

4949
if rotated_bot is not None:
5050
if rotated_installation is None:
51-
rotated_installation = Installation(**installation.to_dict())
51+
rotated_installation = Installation(**installation.to_dict_for_copying())
5252
rotated_installation.bot_token = rotated_bot.bot_token
5353
rotated_installation.bot_refresh_token = rotated_bot.bot_refresh_token
5454
rotated_installation.bot_token_expires_at = rotated_bot.bot_token_expires_at
@@ -85,7 +85,7 @@ def perform_bot_token_rotation(
8585
if refresh_response.get("token_type") != "bot":
8686
return None
8787

88-
refreshed_bot = Bot(**bot.to_dict())
88+
refreshed_bot = Bot(**bot.to_dict_for_copying())
8989
refreshed_bot.bot_token = refresh_response["access_token"]
9090
refreshed_bot.bot_refresh_token = refresh_response.get("refresh_token")
9191
refreshed_bot.bot_token_expires_at = int(time()) + int(refresh_response["expires_in"])
@@ -125,7 +125,7 @@ def perform_user_token_rotation(
125125
if refresh_response.get("token_type") != "user":
126126
return None
127127

128-
refreshed_installation = Installation(**installation.to_dict())
128+
refreshed_installation = Installation(**installation.to_dict_for_copying())
129129
refreshed_installation.user_token = refresh_response.get("access_token")
130130
refreshed_installation.user_refresh_token = refresh_response.get("refresh_token")
131131
refreshed_installation.user_token_expires_at = int(time()) + int(refresh_response["expires_in"])

tests/slack_sdk/oauth/installation_store/test_models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def test_bot(self):
2020
)
2121
self.assertIsNotNone(bot)
2222
self.assertIsNotNone(bot.to_dict())
23+
self.assertIsNotNone(bot.to_dict_for_copying())
2324

2425
def test_bot_custom_fields(self):
2526
bot = Bot(
@@ -33,6 +34,7 @@ def test_bot_custom_fields(self):
3334
bot.set_custom_value("app_id", "A222")
3435
self.assertEqual(bot.get_custom_value("service_user_id"), "XYZ123")
3536
self.assertEqual(bot.to_dict().get("service_user_id"), "XYZ123")
37+
self.assertEqual(bot.to_dict_for_copying().get("custom_values").get("service_user_id"), "XYZ123")
3638

3739
def test_installation(self):
3840
installation = Installation(
@@ -73,10 +75,12 @@ def test_installation_custom_fields(self):
7375
self.assertEqual(installation.get_custom_value("service_user_id"), "XYZ123")
7476
self.assertEqual(installation.to_dict().get("service_user_id"), "XYZ123")
7577
self.assertEqual(installation.to_dict().get("app_id"), "A111")
78+
self.assertEqual(installation.to_dict_for_copying().get("custom_values").get("app_id"), "A222")
7679

7780
bot = installation.to_bot()
7881
self.assertEqual(bot.app_id, "A111")
7982
self.assertEqual(bot.get_custom_value("service_user_id"), "XYZ123")
8083

8184
self.assertEqual(bot.to_dict().get("app_id"), "A111")
8285
self.assertEqual(bot.to_dict().get("service_user_id"), "XYZ123")
86+
self.assertEqual(bot.to_dict_for_copying().get("custom_values").get("app_id"), "A222")

tests/slack_sdk/oauth/token_rotation/test_token_rotator.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,31 @@ def test_refresh(self):
4343
)
4444
self.assertIsNone(should_not_be_refreshed)
4545

46+
def test_refresh_with_custom_values(self):
47+
installation = Installation(
48+
app_id="A111",
49+
enterprise_id="E111",
50+
team_id="T111",
51+
user_id="U111",
52+
bot_id="B111",
53+
bot_token="xoxe.xoxp-1-initial",
54+
bot_scopes=["chat:write"],
55+
bot_user_id="U222",
56+
bot_refresh_token="xoxe-1-initial",
57+
bot_token_expires_in=43200,
58+
custom_values={"foo": "bar"},
59+
)
60+
refreshed = self.token_rotator.perform_token_rotation(
61+
installation=installation, minutes_before_expiration=60 * 24 * 365
62+
)
63+
self.assertIsNotNone(refreshed)
64+
self.assertIsNotNone(refreshed.custom_values)
65+
66+
should_not_be_refreshed = self.token_rotator.perform_token_rotation(
67+
installation=installation, minutes_before_expiration=1
68+
)
69+
self.assertIsNone(should_not_be_refreshed)
70+
4671
def test_token_rotation_disabled(self):
4772
installation = Installation(
4873
app_id="A111",

tests/slack_sdk_async/oauth/token_rotation/test_token_rotator.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,32 @@ async def test_refresh(self):
4545
)
4646
self.assertIsNone(should_not_be_refreshed)
4747

48+
@async_test
49+
async def test_refresh_with_custom_values(self):
50+
installation = Installation(
51+
app_id="A111",
52+
enterprise_id="E111",
53+
team_id="T111",
54+
user_id="U111",
55+
bot_id="B111",
56+
bot_token="xoxe.xoxp-1-initial",
57+
bot_scopes=["chat:write"],
58+
bot_user_id="U222",
59+
bot_refresh_token="xoxe-1-initial",
60+
bot_token_expires_in=43200,
61+
custom_values={"foo": "bar"},
62+
)
63+
refreshed = await self.token_rotator.perform_token_rotation(
64+
installation=installation, minutes_before_expiration=60 * 24 * 365
65+
)
66+
self.assertIsNotNone(refreshed)
67+
self.assertIsNotNone(refreshed.custom_values)
68+
69+
should_not_be_refreshed = await self.token_rotator.perform_token_rotation(
70+
installation=installation, minutes_before_expiration=1
71+
)
72+
self.assertIsNone(should_not_be_refreshed)
73+
4874
@async_test
4975
async def test_token_rotation_disabled(self):
5076
installation = Installation(

0 commit comments

Comments
 (0)