From 7bd3a3a8882d950876d4e48633193403903e4f8b Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Sat, 5 Sep 2026 22:33:03 +0200 Subject: [PATCH] Enforce webp for remote images --- nomadnet/ui/textui/Browser.py | 4 ++-- nomadnet/ui/textui/images/_imagedata.py | 19 ++++++++++++------- nomadnet/ui/textui/images/widget.py | 7 +++++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/nomadnet/ui/textui/Browser.py b/nomadnet/ui/textui/Browser.py index 2ed21c0..04e39e1 100644 --- a/nomadnet/ui/textui/Browser.py +++ b/nomadnet/ui/textui/Browser.py @@ -668,7 +668,7 @@ class Browser: if hasattr(o, "_contained_image"): o = o._contained_image if hasattr(o, "image_url"): resolved_image = self.resolve_image(o.image_url) - if resolved_image: o.load(resolved_image) + if resolved_image: o.load(resolved_image, remote_source=True) else: image = { "widget": o, "id": o.image_id, "url": o.image_url, "refresh": None, "updated": None, "update_requested": None, "request_id": None, "link": None, "failed": False, "pr_throttle": 0, @@ -858,7 +858,7 @@ class Browser: shutil.move(file_handle.name, file_destination) resolved_path = self.resolve_image(url) - if resolved_path: w.load(resolved_path) + if resolved_path: w.load(resolved_path, remote_source=True) except Exception as e: RNS.log("Error while handling image response: "+str(e), RNS.LOG_ERROR) diff --git a/nomadnet/ui/textui/images/_imagedata.py b/nomadnet/ui/textui/images/_imagedata.py index 294f72c..d037ee9 100644 --- a/nomadnet/ui/textui/images/_imagedata.py +++ b/nomadnet/ui/textui/images/_imagedata.py @@ -69,7 +69,7 @@ def parse_image_header(data): # (Kitty's f=100 data format). The dimensions are used only for layout. # WebP sources are converted transparently to PNG on load. class ImageData(object): - def __init__(self, path, max_bytes=MAX_PAYLOAD_BYTES): + def __init__(self, path, max_bytes=MAX_PAYLOAD_BYTES, remote_source=False): self.path = path self.error = None self.format = None @@ -81,15 +81,15 @@ class ImageData(object): try: with open(path, "rb") as f: data = f.read() except OSError as e: - self.error = "could not read file: %s" % e + self.error = "Could not read file: %s" % e return if len(data) > max_bytes: - self.error = "file too large (%.1f MiB > %d MiB)" % (len(data) / (1024 * 1024), max_bytes // (1024 * 1024)) + self.error = "File too large (%.1f MiB > %d MiB)" % (len(data) / (1024 * 1024), max_bytes // (1024 * 1024)) return if not data: - self.error = "empty file" + self.error = "Empty file" return try: self.format, self.width, self.height = parse_image_header(data) @@ -102,17 +102,22 @@ class ImageData(object): from . import _webp png = _webp.convert_webp_to_png(data) if png is None: - self.error = "webp conversion failed (no working backend available)" + self.error = "WebP conversion failed (no working backend available)" return if len(png) > MAX_CONVERTED_PAYLOAD_BYTES: - self.error = "converted image too large (%.1f MiB > %d MiB)" % (len(png) / (1024 * 1024), MAX_CONVERTED_PAYLOAD_BYTES // (1024 * 1024)) + self.error = "Converted image too large (%.1f MiB > %d MiB)" % (len(png) / (1024 * 1024), MAX_CONVERTED_PAYLOAD_BYTES // (1024 * 1024)) return self.data = png self.format = "PNG" self.conversion_backend = _webp.last_backend() - else: self.data = data + else: + if remote_source: + self.error = "Invalid image format, remote images must be WebP" + return + else: + self.data = data # Content key for de-duplication: identical bytes = same key, so # the same image transmitted once can be placed many times. diff --git a/nomadnet/ui/textui/images/widget.py b/nomadnet/ui/textui/images/widget.py index 23cdaa0..9c26f14 100644 --- a/nomadnet/ui/textui/images/widget.py +++ b/nomadnet/ui/textui/images/widget.py @@ -86,12 +86,12 @@ class ImageWidget(urwid.Widget): super().__init__() if self.path: self.load() - def load(self, path=None): + def load(self, path=None, remote_source=False): if path: self.path = path if self.path: from ._imagedata import ImageData self._ti_path = os.path.abspath(os.fspath(self.path)) - self._ti_data = ImageData(self._ti_path) + self._ti_data = ImageData(self._ti_path, remote_source=remote_source) if self._ti_data.ok: # Register with the image store (de-duplicates identical data @@ -99,6 +99,9 @@ class ImageWidget(urwid.Widget): self._ti_key = self._ti_data.key image_store.register(self._ti_key, self._ti_data.data) self._invalidate() + else: + error_msg = self._ti_data.error or "Unknown error" + self.notice(f"Error: {error_msg}") def notice(self, msg=""): if not msg: self._notice = None