From ac9e049386f98e75ff821c09d4b686694ab9d651 Mon Sep 17 00:00:00 2001 From: Jack Cherng Date: Tue, 20 Feb 2024 17:18:22 +0800 Subject: [PATCH] fix: better detection for JSON with XSSI protection prefix https://security.stackexchange.com/q/110539 Signed-off-by: Jack Cherng --- plugin/commands/auto_set_syntax.py | 19 ++++++++++++------- plugin/snapshot.py | 6 +++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/plugin/commands/auto_set_syntax.py b/plugin/commands/auto_set_syntax.py index ddd21a0b..065a8017 100644 --- a/plugin/commands/auto_set_syntax.py +++ b/plugin/commands/auto_set_syntax.py @@ -252,11 +252,17 @@ def is_large_file(view: sublime.View) -> bool: return view.size() >= 10 * 1024 # 10KB def is_json(view: sublime.View) -> bool: - view_size = view.size() - text_begin = re.sub(r"\s+", "", view.substr(sublime.Region(0, 10))) - text_end = re.sub(r"\s+", "", view.substr(sublime.Region(view_size - 10, view_size))) + view_snapshot = G.view_snapshot_collection.get_by_view(view) + assert view_snapshot - return bool( + text_begin = re.sub(r"\s+", "", view_snapshot.content[:10]) + text_end = re.sub(r"\s+", "", view_snapshot.content[-10:]) + + # XSSI protection prefix (https://security.stackexchange.com/q/110539) + if text_begin.startswith((")]}'\n", ")]}',\n")): + return True + + return is_large_file(view) and bool( # map (re.search(r'^\{"', text_begin) and re.search(r'(?:[\d"\]}]|true|false|null)\}$', text_end)) # array @@ -265,9 +271,8 @@ def is_json(view: sublime.View) -> bool: or (text_begin.startswith("[{") and text_end.endswith("}]")) ) - if is_large_file(view): - if is_json(view) and (syntax := find_syntax_by_syntax_like("scope:source.json")): - return assign_syntax_to_view(view, syntax, details={"event": event, "reason": "heuristics"}) + if is_json(view) and (syntax := find_syntax_by_syntax_like("scope:source.json")): + return assign_syntax_to_view(view, syntax, details={"event": event, "reason": "heuristics"}) return False diff --git a/plugin/snapshot.py b/plugin/snapshot.py index a3d1ed0b..9f10e1c0 100644 --- a/plugin/snapshot.py +++ b/plugin/snapshot.py @@ -12,7 +12,7 @@ from .constants import VIEW_RUN_ID_SETTINGS_KEY from .settings import get_merged_plugin_setting -from .utils import head_tail_content_st, remove_prefix +from .utils import get_view_by_id, head_tail_content_st, remove_prefix @dataclass @@ -52,6 +52,10 @@ def file_size(self) -> int: """The file size in bytes, -1 if file not on a disk.""" return self.path_obj.stat().st_size if self.path_obj else -1 + @property + def view(self) -> sublime.View | None: + return get_view_by_id(self.id) + # `UserDict` is not subscriptable until Python 3.9... if TYPE_CHECKING: