Skip to content
This repository was archived by the owner on Feb 18, 2026. It is now read-only.

Commit cdbc9fd

Browse files
committed
Fix tag obfuscation for anonymous users
- get_show_private_tags() now checks plugin's header_modifications, not just actual HTTP headers. This fixes anonymous users getting tag_count: 0 instead of obfuscated tags. - Only recognize 'tags-private' header (not bare 'private') to align with config regex. - Fix variable naming bug in should_obfuscate_private_tags(). - Add regression test to catch this issue. - Update unit tests for new behavior.
1 parent 50af33c commit cdbc9fd

File tree

5 files changed

+40
-9
lines changed

5 files changed

+40
-9
lines changed

gsrest/builtin/plugins/obfuscate_tags/obfuscate_tags.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
)
2929

3030
GROUPS_HEADER_NAME = "X-Consumer-Groups"
31-
NO_OBFUSCATION_MARKER_PATTERN = re.compile(r"(private|tags-private)")
31+
NO_OBFUSCATION_MARKER_PATTERN = re.compile(r"tags-private")
3232
OBFUSCATION_MARKER_GROUP = "obfuscate"
3333

3434

gsrest/dependencies.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,9 @@ def get_username(request) -> Optional[str]:
257257

258258
def should_obfuscate_private_tags(request) -> bool:
259259
# Check header modifications from plugin middleware first
260-
header_mods = getattr(request, "state", None)
261-
if header_mods is not None:
262-
header_mods = getattr(header_mods, "header_modifications", {})
260+
state = getattr(request, "state", None)
261+
if state is not None:
262+
header_mods = getattr(state, "header_modifications", {})
263263
if header_mods.get(GROUPS_HEADER_NAME) == OBFUSCATION_MARKER_GROUP:
264264
return True
265265
# Fall back to checking actual headers

gsrest/routes/base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,13 @@ def get_show_private_tags(
115115
if not show_private_tags_conf:
116116
return False
117117

118+
# Get header modifications from plugin middleware (if any)
119+
header_mods = getattr(request.state, "header_modifications", {})
120+
118121
show_private_tags = True
119122
for k, v in show_private_tags_conf.get("on_header", {}).items():
120-
hval = request.headers.get(k, None)
123+
# Check both actual headers and plugin-set header modifications
124+
hval = header_mods.get(k) or request.headers.get(k, None)
121125
if not hval:
122126
return False
123127
show_private_tags = show_private_tags and bool(re.match(re.compile(v), hval))

tests/test_plugins.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ def make_request(path, headers=None, query=""):
6363
# --- Helper Function Tests ---
6464

6565
@pytest.mark.parametrize("groups,expected", [
66-
(["private"], True),
66+
(["private"], False), # Only 'tags-private' is recognized, not bare 'private'
6767
(["tags-private"], True),
68-
(["public", "private"], True),
68+
(["public", "tags-private"], True),
6969
(["public"], False),
7070
(["obfuscate"], False),
7171
([], False),
@@ -110,7 +110,7 @@ def test_preserves_non_matching(self):
110110
# --- before_request Tests ---
111111

112112
@pytest.mark.parametrize("path,headers,query", [
113-
("/btc/entities/123", {GROUPS_HEADER_NAME: "private"}, ""),
113+
# Only 'tags-private' is recognized, not bare 'private'
114114
("/btc/entities/123", {GROUPS_HEADER_NAME: "tags-private"}, ""),
115115
("/btc/entities/123/neighbors", {}, "include_labels=true"),
116116
("/btc/entities/123/neighbors", {}, "INCLUDE_LABELS=TRUE"),
@@ -190,7 +190,7 @@ def test_obfuscates_neighbor_tags(self):
190190
assert neighbors.neighbors[1].entity.best_address_tag.label == "Kept"
191191

192192

193-
@pytest.mark.parametrize("group", ["private", "tags-private"])
193+
@pytest.mark.parametrize("group", ["tags-private"]) # Only 'tags-private' skips obfuscation
194194
def test_before_response_skips_with_no_obfuscation_group(group):
195195
entity = make_entity(tag=make_tag(is_public=False, label="Private"))
196196
req = make_request("/btc/entities/123", {GROUPS_HEADER_NAME: group})

tests/test_regression.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,33 @@ def test_txs_list():
207207
assert False, f"Outputs differ for call: {call}\n\nDetailed differences:\n{diff_details}"
208208

209209

210+
@pytest.mark.regression
211+
def test_obfuscation():
212+
"""Test that anonymous users get obfuscated tags (not zero tags).
213+
214+
This catches the bug where get_show_private_tags() didn't check
215+
header_modifications from the plugin middleware.
216+
"""
217+
# Address known to have private tags
218+
call = "btc/addresses/3D4gm7eGSXiEkWS5V3hN9kDVo2eDGBK4eA/tag_summary"
219+
220+
# Get data without auth header (anonymous user)
221+
data, _ = get_data_from_new_endpoint(call)
222+
223+
# Anonymous users should still get tags (not zero)
224+
assert data.get("tag_count", 0) > 0, \
225+
"Anonymous users should see obfuscated tags, not zero tags"
226+
227+
# But labels should be obfuscated (empty string)
228+
assert data.get("best_label") == "", \
229+
f"Labels should be obfuscated for anonymous users, got: {data.get('best_label')}"
230+
231+
# All label keys in summary should be empty
232+
for label_key in data.get("label_summary", {}).keys():
233+
assert label_key == "", \
234+
f"Label keys should be obfuscated, got: {label_key}"
235+
236+
210237
@pytest.mark.regression
211238
def test_search():
212239
"""Run the regression test and return the comparison result."""

0 commit comments

Comments
 (0)