Skip to content

Commit 08999a5

Browse files
fix: truncate long User-Agent strings in user subscription updates
1 parent e2654ff commit 08999a5

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

app/db/crud/user.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
from .group import get_groups_by_ids
3333

3434

35+
_USER_AGENT_MAX_LEN = UserSubscriptionUpdate.__table__.columns.user_agent.type.length or 512
36+
37+
3538
async def load_user_attrs(user: User):
3639
await user.awaitable_attrs.admin
3740
await user.awaitable_attrs.next_plan
@@ -845,7 +848,9 @@ async def user_sub_update(db: AsyncSession, user_id: User, user_agent: str) -> U
845848
user_agent (str): The user agent string.
846849
847850
"""
848-
agent = UserSubscriptionUpdate(user_id=user_id, user_agent=user_agent)
851+
# Clamp to column length; some clients send very long strings (e.g. encoded configs) as User-Agent.
852+
sanitized_user_agent = (user_agent or "")[:_USER_AGENT_MAX_LEN]
853+
agent = UserSubscriptionUpdate(user_id=user_id, user_agent=sanitized_user_agent)
849854
db.add(agent)
850855
await db.commit()
851856

tests/api/test_user.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,29 @@ def test_user_sub_update_user_agent(access_token):
176176
cleanup_groups(access_token, core, groups)
177177

178178

179+
def test_user_sub_update_user_agent_truncates_long_values(access_token):
180+
"""Ensure overly long User-Agent strings are stored without failing."""
181+
core, groups = setup_groups(access_token, 1)
182+
user = create_user(
183+
access_token,
184+
group_ids=[groups[0]["id"]],
185+
payload={"username": unique_name("test_user_agent_truncate")},
186+
)
187+
try:
188+
url = user["subscription_url"]
189+
long_user_agent = "A" * 1000
190+
client.get(url, headers={"User-Agent": long_user_agent})
191+
response = client.get(
192+
f"/api/user/{user['username']}/sub_update",
193+
headers={"Authorization": f"Bearer {access_token}"},
194+
)
195+
assert response.status_code == status.HTTP_200_OK
196+
assert response.json()["updates"][0]["user_agent"] == long_user_agent[:512]
197+
finally:
198+
delete_user(access_token, user["username"])
199+
cleanup_groups(access_token, core, groups)
200+
201+
179202
def test_user_get(access_token):
180203
"""Test that the user get by id route is accessible."""
181204
core, groups = setup_groups(access_token, 1)

0 commit comments

Comments
 (0)