Handle null values in the policy format_requester helper

A requester with a banned IP but no `User-Agent` header crashed the policy
evaluation: the field is serialized as JSON `null` (not omitted), which
passes a bare truthiness check and then aborts `sprintf` in the WASM build.
This commit is contained in:
Quentin Gliech
2026-08-10 15:16:57 +02:00
parent 28338969e1
commit a3e2815a04
2 changed files with 30 additions and 10 deletions
+16 -10
View File
@@ -1,3 +1,4 @@
# Copyright 2025, 2026 Element Creations Ltd.
# Copyright 2025 New Vector Ltd.
#
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
@@ -68,22 +69,27 @@ requester_banned(requester, policy) if ip_in_list(requester.ip_address, policy.b
requester_banned(requester, policy) if matches_string_constraints(requester.user_agent, policy.banned_user_agents)
# The fields are `null` (not absent) when unknown: a bare `requester.user_agent`
# check lets `null` through to `sprintf`, which aborts the WASM evaluation. The
# helper rule is undefined for both null and absent values, which `not` handles.
requester_has(requester, key) if is_string(requester[key])
format_requester(requester) := "unknown" if {
not requester.ip_address
not requester.user_agent
not requester_has(requester, "ip_address")
not requester_has(requester, "user_agent")
}
format_requester(requester) := sprintf("%s / %s", [requester.ip_address, requester.user_agent]) if {
requester.ip_address
requester.user_agent
requester_has(requester, "ip_address")
requester_has(requester, "user_agent")
}
format_requester(requester) := sprintf("%s", [requester.ip_address]) if {
requester.ip_address
not requester.user_agent
format_requester(requester) := requester.ip_address if {
requester_has(requester, "ip_address")
not requester_has(requester, "user_agent")
}
format_requester(requester) := sprintf("%s", [requester.user_agent]) if {
not requester.ip_address
requester.user_agent
format_requester(requester) := requester.user_agent if {
not requester_has(requester, "ip_address")
requester_has(requester, "user_agent")
}
+14
View File
@@ -46,4 +46,18 @@ test_requester_banned if {
{"ip_address": "192.168.1.1", "user_agent": "Mozilla/5.0"},
{"banned_ips": ["192.168.1.1"]},
)
# A missing user agent is serialized as null, not omitted
common.requester_banned(
{"ip_address": "192.168.1.1", "user_agent": null},
{"banned_ips": ["192.168.1.1"]},
)
}
test_format_requester if {
common.format_requester({"ip_address": "192.168.1.1", "user_agent": "Mozilla/5.0"}) == "192.168.1.1 / Mozilla/5.0"
common.format_requester({"ip_address": "192.168.1.1", "user_agent": null}) == "192.168.1.1"
common.format_requester({"ip_address": null, "user_agent": "Mozilla/5.0"}) == "Mozilla/5.0"
common.format_requester({"ip_address": null, "user_agent": null}) == "unknown"
common.format_requester({}) == "unknown"
}