fotos: si no se pueden limpiar, no se suben
Si quitar los metadatos fallaba, blobHandler subia la foto original, con el GPS. Ahora se para con un 400 y un aviso (imageMetadataUnsafe, en los 11 idiomas): HEIC/HEIF/AVIF y TIFF, que pueden llevar EXIF y aqui no se saben limpiar, y JPEG/PNG/WebP que no se dejan recorrer. Un JPEG cortado ya no sube como una imagen vacia. Formatos sin EXIF (BMP, SVG...) pasan igual. Es el cambio del 10 de octubre, llevado a la copia de la limpieza que vive ahora en blobHandler.js.
This commit is contained in:
parent
ed77a13c85
commit
b64dcf9b7a
2 changed files with 59 additions and 8 deletions
|
|
@ -85,11 +85,12 @@ const stripJpeg = (buf) => {
|
|||
const out = [buf.subarray(0, 2)];
|
||||
let orientation = 0;
|
||||
let i = 2;
|
||||
let scan = false;
|
||||
while (i + 4 <= buf.length) {
|
||||
if (buf[i] !== 0xFF) return null; // no es un JPEG sano: no tocarlo
|
||||
const marker = buf[i + 1];
|
||||
if (marker === 0xD8 || (marker >= 0xD0 && marker <= 0xD9)) { i += 2; continue; }
|
||||
if (marker === 0xDA) { out.push(buf.subarray(i)); break; } // datos comprimidos: hasta el final
|
||||
if (marker === 0xDA) { out.push(buf.subarray(i)); scan = true; break; } // datos comprimidos: hasta el final
|
||||
const len = buf.readUInt16BE(i + 2);
|
||||
if (len < 2 || i + 2 + len > buf.length) return null;
|
||||
const seg = buf.subarray(i + 4, i + 2 + len);
|
||||
|
|
@ -97,6 +98,8 @@ const stripJpeg = (buf) => {
|
|||
if (!JPEG_DROP.has(marker)) out.push(buf.subarray(i, i + 2 + len));
|
||||
i += 2 + len;
|
||||
}
|
||||
// sin datos de imagen (SOS) es un JPEG cortado: devolver la cabecera sola subiria una foto vacia
|
||||
if (!scan) return null;
|
||||
if (orientation > 1) {
|
||||
const exif = exifOnlyOrientation(orientation);
|
||||
const head = Buffer.alloc(4);
|
||||
|
|
@ -150,14 +153,40 @@ const stripWebp = (buf) => {
|
|||
return Buffer.concat([head, body]);
|
||||
};
|
||||
|
||||
/** Limpia segun el formato; si algo no cuadra, devuelve la imagen tal cual. */
|
||||
const stripMetadataPure = (buffer) => {
|
||||
try {
|
||||
const out = stripJpeg(buffer) || stripPng(buffer) || stripWebp(buffer);
|
||||
return out && out.length ? out : buffer;
|
||||
} catch {
|
||||
return buffer;
|
||||
// Formatos que pueden llevar EXIF (GPS incluido) y que aqui no se saben limpiar:
|
||||
// HEIC/HEIF/AVIF (caja ftyp) y TIFF. Antes subian tal cual, con la ubicacion.
|
||||
const isUncleanable = (buf) => {
|
||||
if (buf.length >= 12 && buf.toString("latin1", 4, 8) === "ftyp") {
|
||||
return /^(heic|heix|hevc|hevx|heim|heis|mif1|msf1|avif|avis)$/.test(buf.toString("latin1", 8, 12));
|
||||
}
|
||||
return buf.length >= 4 && (buf.toString("latin1", 0, 4) === "II*\0" || buf.toString("latin1", 0, 4) === "MM\0*");
|
||||
};
|
||||
const looksCleanable = (buf) =>
|
||||
(buf.length >= 2 && buf[0] === 0xFF && buf[1] === 0xD8) ||
|
||||
(buf.length >= 8 && buf.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]))) ||
|
||||
(buf.length >= 12 && buf.toString("latin1", 0, 4) === "RIFF" && buf.toString("latin1", 8, 12) === "WEBP");
|
||||
|
||||
const unsafe = () => {
|
||||
let msg = "This image could not be cleaned of its metadata, so it has not been uploaded.";
|
||||
try { msg = require("../views/main_views").i18n.imageMetadataUnsafe || msg; } catch (_) {}
|
||||
const err = new Error(msg);
|
||||
err.status = 400;
|
||||
return err;
|
||||
};
|
||||
|
||||
/**
|
||||
* Limpia segun el formato. Si es JPEG/PNG/WebP y no se puede limpiar, o es un
|
||||
* formato con EXIF que no sabemos limpiar, LANZA: es mejor no subir la foto que
|
||||
* subirla con la ubicacion. Formatos sin metadatos de ese tipo (BMP, SVG, ICO...)
|
||||
* pasan tal cual.
|
||||
*/
|
||||
const stripMetadataPure = (buffer) => {
|
||||
if (isUncleanable(buffer)) throw unsafe();
|
||||
if (!looksCleanable(buffer)) return buffer;
|
||||
let out = null;
|
||||
try { out = stripJpeg(buffer) || stripPng(buffer) || stripWebp(buffer); } catch (_) { out = null; }
|
||||
if (!out || !out.length) throw unsafe();
|
||||
return out;
|
||||
};
|
||||
|
||||
const stripImageMetadata = async (buffer) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue