Browse Source

Implement configurable EXIF stripping for uploaded media

- Add `strip_exif` configuration option to enable metadata removal.
- Add `mogrify_path` configuration to specify external tool location.
- Implement strip_media using `mogrify -strip`.
- Support multiple image formats: jpg, png, webp, heic, heif, avif, tiff, gif, bmp.
- Add strict startup check: fail to start if `strip_exif` is enabled but `mogrify` is missing/broken.
- Update documentation in `doc/snac.8`.
Stefano Marinelli 6 tháng trước cách đây
mục cha
commit
688c54c873
4 tập tin đã thay đổi với 86 bổ sung2 xóa
  1. 11 2
      data.c
  2. 8 0
      doc/snac.8
  3. 64 0
      snac.c
  4. 3 0
      snac.h

+ 11 - 2
data.c

@@ -89,8 +89,15 @@ int srv_open(const char *basedir, int auto_upgrade)
                 else {
                     if (xs_number_get(xs_dict_get(srv_config, "layout")) < disk_layout)
                         error = xs_fmt("ERROR: disk layout changed - execute 'snac upgrade' first");
-                    else
-                        ret = 1;
+                    else {
+                        if (!check_strip_tool()) {
+                            const char *mp = xs_dict_get(srv_config, "mogrify_path");
+                            if (mp == NULL) mp = "mogrify";
+                            error = xs_fmt("ERROR: strip_exif enabled but '%s' not found or not working (set 'mogrify_path' in server.json)", mp);
+                        }
+                        else
+                            ret = 1;
+                    }
                 }
             }
 
@@ -2710,6 +2717,8 @@ void static_put(snac *snac, const char *id, const char *data, int size)
     if (fn && (f = fopen(fn, "wb")) != NULL) {
         fwrite(data, size, 1, f);
         fclose(f);
+
+        strip_media(fn);
     }
 }
 

+ 8 - 0
doc/snac.8

@@ -296,6 +296,14 @@ outgoing messages (default: 15). Anyway, whenever any incoming activity from a
 failed instance is detected, this counter is reset for it.
 .It Ic vkey
 Public vapid key. Used for notification on some client.
+.It Ic strip_exif
+If set to true, EXIF metadata will be stripped from uploaded images (jpg, png, webp, heic, avif, tiff, gif, bmp). This requires the
+.Nm mogrify
+tool to be installed. If
+.Nm snac
+cannot find or execute the tool at startup, it will refuse to run.
+.It Ic mogrify_path
+Overrides the default "mogrify" command name or path. Use this if the tool is not in the system PATH or has a different name.
 .El
 .Pp
 You must restart the server to make effective these changes.

+ 64 - 0
snac.c

@@ -32,6 +32,7 @@
 
 #include <sys/time.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 
 xs_str *srv_basedir = NULL;
 xs_dict *srv_config = NULL;
@@ -170,3 +171,66 @@ int check_password(const char *uid, const char *passwd, const char *hash)
 
     return ret;
 }
+
+
+int strip_media(const char *fn)
+/* strips EXIF data from a file */
+{
+    int ret = 0;
+    const xs_val *v = xs_dict_get(srv_config, "strip_exif");
+
+    if (xs_type(v) == XSTYPE_TRUE) {
+        xs *l_fn = xs_tolower_i(xs_dup(fn));
+
+        /* check extensions */
+        if (xs_endswith(l_fn, ".jpg") || xs_endswith(l_fn, ".jpeg") ||
+            xs_endswith(l_fn, ".png") || xs_endswith(l_fn, ".webp") ||
+            xs_endswith(l_fn, ".heic") || xs_endswith(l_fn, ".heif") ||
+            xs_endswith(l_fn, ".avif") || xs_endswith(l_fn, ".tiff") ||
+            xs_endswith(l_fn, ".gif")  || xs_endswith(l_fn, ".bmp")) {
+
+            const char *mp = xs_dict_get(srv_config, "mogrify_path");
+            if (mp == NULL)
+                mp = "mogrify";
+
+            xs *cmd = xs_fmt("%s -strip \"%s\" 2>/dev/null", mp, fn);
+
+            ret = system(cmd);
+
+            if (ret != 0) {
+                int code = 0;
+                if (WIFEXITED(ret))
+                    code = WEXITSTATUS(ret);
+                
+                if (code == 127)
+                    srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'mogrify_path' in server.json.", fn, mp));
+                else
+                    srv_log(xs_fmt("strip_media: error stripping %s %d", fn, ret));
+            }
+            else
+                srv_debug(1, xs_fmt("strip_media: stripped %s", fn));
+        }
+    }
+
+    return ret;
+}
+
+
+int check_strip_tool(void)
+{
+    const xs_val *v = xs_dict_get(srv_config, "strip_exif");
+    int ret = 1;
+
+    if (xs_type(v) == XSTYPE_TRUE) {
+        const char *mp = xs_dict_get(srv_config, "mogrify_path");
+        if (mp == NULL)
+            mp = "mogrify";
+
+        xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", mp);
+        
+        if (system(cmd) != 0)
+            ret = 0;
+    }
+
+    return ret;
+}

+ 3 - 0
snac.h

@@ -105,6 +105,9 @@ int validate_uid(const char *uid);
 xs_str *hash_password(const char *uid, const char *passwd, const char *nonce);
 int check_password(const char *uid, const char *passwd, const char *hash);
 
+int strip_media(const char *fn);
+int check_strip_tool(void);
+
 void srv_archive(const char *direction, const char *url, xs_dict *req,
                  const char *payload, int p_size,
                  int status, xs_dict *headers,