Add metadata_scan.c/.h: pure-C, dependency-free byte scanners for JPEG (APP1 Exif/XMP, APP13 IPTC), PNG (eXIf, denylisted tEXt/iTXt/zTXt keys), WebP (EXIF/XMP chunks), GIF (comment/XMP extensions), PDF (/Author, /Producer, /CreationDate, etc.), TIFF (ExifIFD/GPS IFD pointers), HEIC (Exif item payload). Conservative — when in doubt, flags. Wire into handle_upload_request_with_validation() after SHA-256 compute, before fopen: rejects with 415 + X-Reason: exif_detected, preserving BUD-01 content addressing (server never rewrites). Add metadata_scan_enabled config toggle (default true). Add to Makefile + Dockerfile.alpine-musl. Tests: metadata_scan_test.c unit test (20 cases) + metadata_scan_test.sh integration test (7 cases, run against live server). See ~/lt/metadata_stripping/plans/blob-metadata-stripping.md (Part 2).
66 lines
2.1 KiB
C
66 lines
2.1 KiB
C
/*
|
|
* metadata_scan.h — Privacy-metadata detection for uploaded blobs.
|
|
*
|
|
* The server-side backstop of the metadata-stripping pipeline. Scans the
|
|
* in-memory upload buffer for EXIF / XMP / IPTC / PNG text chunks / PDF
|
|
* author tags / GIF comments / HEIC Exif items and rejects the upload if
|
|
* forbidden metadata is present.
|
|
*
|
|
* The scanner is conservative: when in doubt, flag. The cost of a false
|
|
* positive is a client retry with stripped bytes; the cost of a false
|
|
* negative is a privacy leak.
|
|
*
|
|
* See ~/lt/metadata_stripping/plans/blob-metadata-stripping.md (Part 2).
|
|
*/
|
|
|
|
#ifndef METADATA_SCAN_H
|
|
#define METADATA_SCAN_H
|
|
|
|
#include <stddef.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef enum {
|
|
META_SCAN_OK = 0,
|
|
META_SCAN_FORBIDDEN_FOUND = 1,
|
|
META_SCAN_ERROR = 2
|
|
} meta_scan_result_t;
|
|
|
|
/*
|
|
* Scan an in-memory blob for privacy-sensitive metadata.
|
|
*
|
|
* data — pointer to the uploaded bytes
|
|
* size — number of bytes
|
|
* content_type — MIME type from the Content-Type header (may be NULL)
|
|
* reason_out — buffer to receive a short human-readable reason string
|
|
* (e.g. "exif_detected: JPEG APP1 Exif segment")
|
|
* reason_out_size — size of reason_out; the reason is truncated to fit
|
|
*
|
|
* Returns:
|
|
* META_SCAN_OK — no forbidden metadata found
|
|
* META_SCAN_FORBIDDEN_FOUND — forbidden metadata detected; reason_out filled
|
|
* META_SCAN_ERROR — internal error (scan skipped)
|
|
*
|
|
* The format is auto-detected from the byte signature; content_type is used
|
|
* only as a hint (e.g. to distinguish a mislabeled TIFF).
|
|
*/
|
|
meta_scan_result_t metadata_scan(const unsigned char *data,
|
|
size_t size,
|
|
const char *content_type,
|
|
char *reason_out,
|
|
size_t reason_out_size);
|
|
|
|
/*
|
|
* Read the metadata_scan_enabled config row. Returns 1 if the server should
|
|
* reject uploads carrying forbidden metadata (default), 0 if disabled.
|
|
*/
|
|
int metadata_scan_enabled(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* METADATA_SCAN_H */
|