From 688c54c87355b5424f33f7b089814460a74af594 Mon Sep 17 00:00:00 2001 From: Stefano Marinelli Date: Tue, 6 Jan 2026 11:02:36 +0100 Subject: 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`. --- data.c | 13 +++++++++++-- doc/snac.8 | 8 ++++++++ snac.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ snac.h | 3 +++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/data.c b/data.c index 22ea7b0..f32dc81 100644 --- a/data.c +++ b/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); } } diff --git a/doc/snac.8 b/doc/snac.8 index b8a75fa..8283ac6 100644 --- a/doc/snac.8 +++ b/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. diff --git a/snac.c b/snac.c index 965edbb..f4528cd 100644 --- a/snac.c +++ b/snac.c @@ -32,6 +32,7 @@ #include #include +#include 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; +} diff --git a/snac.h b/snac.h index 8a7dad6..c307dbd 100644 --- a/snac.h +++ b/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, -- cgit v1.2.3