Eliminar los metadatos de tus archivos con Azure Functions

Desde hace bastante tiempo, redes sociales como Facebook, Instagram, Twitter o WhatsApp se preocupan de eliminar los metadatos de las imágenes que subes a sus plataformas o compartes con tus contactos. Esto no significa que nos guarden las originales con todo aquello que parecen eliminar pero, al menos de cara al público, sí que podemos estar algo más tranquilos. Esto es muy buena práctica y deberías de hacerlo en todos aquellos archivos que pueden ser públicos o compartidos, con el fin de mejorar la privacidad de tus usuarios, y así evitar el uso de aplicaciones como Creepy que se aprovecha de los metadatos de las imágenes subidas a las redes sociales para geolocalizarte.

La aplicación Creepy se aprovecha de las imágenes que subes para geolocalizarte

Ahora que ya sabes cómo trabajar con Azure Functions, en este post te quiero contar lo fácil que es limpiar los metadatos de tus archivos cuando estos son añadidos a una cuenta de Azure Storage.

Para llevar a cabo esta tarea, lo que he hecho es hacer uso de una herramienta bastante conocida llamada Exiftool y crearme una Azure Function, enlazada a un trigger de tipo blob. Esto significa que cada vez que añada un nuevo archivo dentro de la cuenta de Azure Storage que yo elija se lanzará esta función donde lanzaré exiftool para que limpie los metadatos.

const
    execFile = require('child_process').execFile,
    exiftool = require('dist-exiftool'),
    fs = require('fs');

module.exports = function(context, myBlob) {
    context.log("Clean EXIF function is going to process this blob \n Name:", context.bindingData.name, "\n Blob Size:", myBlob.length, "Bytes");

    fs.writeFile(context.bindingData.name, myBlob, function(err) {
        if (err) {
            console.error(err);
        } else {
            console.log("The file was saved in ", __dirname + '\\' + context.bindingData.name);
            execFile(exiftool, ['-all=', context.bindingData.name], (error, stdout, stderr) => {
                if (err) {
                    console.error(`exec error: ${error}`);
                    return;
                }

                console.log(`stdout: ${stdout}`);
                console.log(`stderr: ${stderr}`);

                fs.readFile(context.bindingData.name, (err, data) => {
                    context.bindings.outBlobName = context.bindingData.name;
                    context.bindings.output = data;

                    fs.unlink(context.bindingData.name, (err) => {
                        if (err) throw err;
                        console.log('successfully deleted ' + context.bindingData.name);
                    });

                    fs.unlink(context.bindingData.name + '_original', (err) => {
                        if (err) throw err;
                        console.log('successfully deleted ' + context.bindingData.name + '_original');
                    });

                    context.done();
                });
            });
        }
    });
};

Por un lado, se está recuperando el blob que ha hecho que la función se ejecute. Se utiliza el módulo fs para crear una copia en local de dicho blob y pasarle a exiftool la ruta del archivo y el parámetro -all= que hará que borre todos los metadatos. Una vez hecho esto, eliminará tanto el archivo original como el modificado. Como último paso, he utilizado un binding de tipo salida que me facilita la escritura de blobs.

{
    "disabled": false,
    "bindings": [{
            "name": "myBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "raw/{name}",
            "connection": "exifdemo_STORAGE"
        },
        {
            "name": "output",
            "type": "blob",
            "dataType": "binary",
            "direction": "out",
            "path": "cleaned/{name}",
            "connection": "exifdemo_STORAGE"
        }
    ]
}

Lo único que hago con este binding es copiar el resultado de mi archivo, ya sin metadatos, en un nuevo contenedor llamado cleaned.

Gracias a esta función tan sencilla, ya tienes todos tus archivos limpios de metadatos y listos para compartir.

El código lo tienes disponible en mi GitHub.

¡Saludos!