commit 688c54c
Stefano Marinelli
·
2026-01-06 10:02:36 +0000 UTC
parent b84b92d
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`.
4 files changed,
+86,
-2
M
data.c
+11,
-2
1@@ -89,8 +89,15 @@ int srv_open(const char *basedir, int auto_upgrade)
2 else {
3 if (xs_number_get(xs_dict_get(srv_config, "layout")) < disk_layout)
4 error = xs_fmt("ERROR: disk layout changed - execute 'snac upgrade' first");
5- else
6- ret = 1;
7+ else {
8+ if (!check_strip_tool()) {
9+ const char *mp = xs_dict_get(srv_config, "mogrify_path");
10+ if (mp == NULL) mp = "mogrify";
11+ error = xs_fmt("ERROR: strip_exif enabled but '%s' not found or not working (set 'mogrify_path' in server.json)", mp);
12+ }
13+ else
14+ ret = 1;
15+ }
16 }
17 }
18
19@@ -2710,6 +2717,8 @@ void static_put(snac *snac, const char *id, const char *data, int size)
20 if (fn && (f = fopen(fn, "wb")) != NULL) {
21 fwrite(data, size, 1, f);
22 fclose(f);
23+
24+ strip_media(fn);
25 }
26 }
27
+8,
-0
1@@ -296,6 +296,14 @@ outgoing messages (default: 15). Anyway, whenever any incoming activity from a
2 failed instance is detected, this counter is reset for it.
3 .It Ic vkey
4 Public vapid key. Used for notification on some client.
5+.It Ic strip_exif
6+If set to true, EXIF metadata will be stripped from uploaded images (jpg, png, webp, heic, avif, tiff, gif, bmp). This requires the
7+.Nm mogrify
8+tool to be installed. If
9+.Nm snac
10+cannot find or execute the tool at startup, it will refuse to run.
11+.It Ic mogrify_path
12+Overrides the default "mogrify" command name or path. Use this if the tool is not in the system PATH or has a different name.
13 .El
14 .Pp
15 You must restart the server to make effective these changes.
M
snac.c
+64,
-0
1@@ -32,6 +32,7 @@
2
3 #include <sys/time.h>
4 #include <sys/stat.h>
5+#include <sys/wait.h>
6
7 xs_str *srv_basedir = NULL;
8 xs_dict *srv_config = NULL;
9@@ -170,3 +171,66 @@ int check_password(const char *uid, const char *passwd, const char *hash)
10
11 return ret;
12 }
13+
14+
15+int strip_media(const char *fn)
16+/* strips EXIF data from a file */
17+{
18+ int ret = 0;
19+ const xs_val *v = xs_dict_get(srv_config, "strip_exif");
20+
21+ if (xs_type(v) == XSTYPE_TRUE) {
22+ xs *l_fn = xs_tolower_i(xs_dup(fn));
23+
24+ /* check extensions */
25+ if (xs_endswith(l_fn, ".jpg") || xs_endswith(l_fn, ".jpeg") ||
26+ xs_endswith(l_fn, ".png") || xs_endswith(l_fn, ".webp") ||
27+ xs_endswith(l_fn, ".heic") || xs_endswith(l_fn, ".heif") ||
28+ xs_endswith(l_fn, ".avif") || xs_endswith(l_fn, ".tiff") ||
29+ xs_endswith(l_fn, ".gif") || xs_endswith(l_fn, ".bmp")) {
30+
31+ const char *mp = xs_dict_get(srv_config, "mogrify_path");
32+ if (mp == NULL)
33+ mp = "mogrify";
34+
35+ xs *cmd = xs_fmt("%s -strip \"%s\" 2>/dev/null", mp, fn);
36+
37+ ret = system(cmd);
38+
39+ if (ret != 0) {
40+ int code = 0;
41+ if (WIFEXITED(ret))
42+ code = WEXITSTATUS(ret);
43+
44+ if (code == 127)
45+ srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'mogrify_path' in server.json.", fn, mp));
46+ else
47+ srv_log(xs_fmt("strip_media: error stripping %s %d", fn, ret));
48+ }
49+ else
50+ srv_debug(1, xs_fmt("strip_media: stripped %s", fn));
51+ }
52+ }
53+
54+ return ret;
55+}
56+
57+
58+int check_strip_tool(void)
59+{
60+ const xs_val *v = xs_dict_get(srv_config, "strip_exif");
61+ int ret = 1;
62+
63+ if (xs_type(v) == XSTYPE_TRUE) {
64+ const char *mp = xs_dict_get(srv_config, "mogrify_path");
65+ if (mp == NULL)
66+ mp = "mogrify";
67+
68+ xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", mp);
69+
70+ if (system(cmd) != 0)
71+ ret = 0;
72+ }
73+
74+ return ret;
75+}
M
snac.h
+3,
-0
1@@ -105,6 +105,9 @@ int validate_uid(const char *uid);
2 xs_str *hash_password(const char *uid, const char *passwd, const char *nonce);
3 int check_password(const char *uid, const char *passwd, const char *hash);
4
5+int strip_media(const char *fn);
6+int check_strip_tool(void);
7+
8 void srv_archive(const char *direction, const char *url, xs_dict *req,
9 const char *payload, int p_size,
10 int status, xs_dict *headers,