Discourse detecta incorrectamente el archivo subido como una imagen

Tengo algunos usuarios de ingeniería que desean adjuntar algunos archivos de datos con extensiones de archivo poco comunes a sus publicaciones. Son esencialmente archivos de texto plano, pero incluyen caracteres ASCII extendidos.

Intenté actualizar la configuración NGINX de Discourse para especificar los tipos de medios MIME para estos archivos, pero no funcionó. Publiqué un tema (How to customize MIME media type emitted for certain attachments?) sobre esto hace dos semanas, pero no he recibido ninguna respuesta hasta ahora. Incluso si NGINX no se actualiza, seguirá sirviendo tipos de archivo desconocidos utilizando el tipo MIME de respaldo “application/octet-stream”. Puedo vivir con eso por ahora.

Sin embargo, cuando los usuarios intentan cargar estos archivos de datos en una publicación (ya sea usando el botón “Cargar” o arrastrando y soltando), reciben un mensaje de error de Discourse como este:

Parece que cuando los usuarios cargan archivos, Discourse intenta ser inteligente y detectar si es una imagen u otro tipo de archivo. Además, parece que está haciendo esta determinación mirando el contenido del archivo (muy parecido a lo que hace el comando estándar de Unix “file”). Supongo que esto es para que Discourse pueda decidir si insertarlo en el contenido de la publicación o colocarlo a un lado como un archivo adjunto.

En el caso de estos archivos de datos, esta verificación identifica incorrectamente los archivos como imágenes. Solo por diversión, puse algunos de estos archivos de datos en una máquina Ubuntu y los verifiqué con el comando “file”, y efectivamente, fueron identificados como “datos de imagen JPEG”.

¿Hay alguna manera de que los usuarios carguen archivos sin que Discourse intente detectar si son imágenes? Es decir, “¿Por favor, carga esto como un archivo adjunto, sin importar qué, no lo insertes”?

Alternativamente, podría configurar Discourse para permitir archivos zip y decirles a los usuarios que compriman sus archivos antes de cargarlos, pero preferiría no abrir el sitio a cargas aleatorias de archivos zip. Eso parece un problema de seguridad.

¡Gracias de antemano por cualquier ayuda!

Otra solución alternativa es adoptar una extensión para esos archivos extraños, como .bin, .data o realmente .anythinggoes, lo que debería ser suficiente para que Discourse deje esos archivos en paz.

¡Gracias por la rápida respuesta! Sin embargo, lo intenté y no funciona. Discourse definitivamente está mirando el contenido del archivo, no la extensión, para determinar si es una imagen o no.

1 me gusta

¿Alguien tiene alguna opinión al respecto? Esto parece un error bastante importante.

Investigué un poco sobre este problema.

En resumen, tu archivo está siendo detectado como JPEG porque comienza con la misma firma que este tipo de archivo.
Es posible solucionar este comportamiento en Discourse, pero requiere una modificación. (ver al final)


Aquí hay algo técnico.
Este problema comienza aquí:

La biblioteca FastImage abre el archivo y determina el tipo y el tamaño.
Como esperas, devuelve un tipo JPEG.

Si miras la firma JPEG, se ve así:

Marcadores JPEG

Más información: List of file signatures - Wikipedia
JPEG - Wikipedia

Siempre comienza con los siguientes bytes de marcador: FF D8

Si miras tu muestra de archivo con un editor hexadecimal, verás que comienza igual.

Ahora, si miras cómo FastImage detecta un JPEG, puedes verlo aquí:

Sin embargo, no puedes extraer ninguna información de la imagen ya que no están todos los bytes requeridos.

¿Cómo solucionamos este problema en Discourse?
Mirando el código de FastImage, hay una opción valiosa que puedes pasar.

Al usar esta opción, cualquier error (SizeNotFound, ImageFetchFailure, CannotParseImage, UnknownImageType, BadImageURI) no devolverá información de imagen; y tu archivo no será detectado como una imagen.

@image_info =
  begin
    FastImage.new(@file, raise_on_failure: true)
  rescue StandardError
    nil
  end
...
is_image ||= @image_info && FileHelper.is_supported_image?("test.#{@image_info.type}")

Entonces, puede funcionar ahora:

Puedo hacer un PR más tarde. Usar esta opción tiene sentido aquí. :+1:

2 Me gusta

¡Guau! ¡Este es un análisis fenomenal! ¡Gracias!

Algunas preguntas rápidas:

  1. Entonces, con estos cambios, ¿el archivo no será detectado como una imagen y se cargará como no imagen y se mostrará a la derecha de la publicación?

  2. Si entiendo correctamente, me sugieres que haga estos ajustes en mi instancia local de Discourse para probar esto y/o usar esto hasta que se incluya en una futura versión de Discourse. ¿Pero cómo hago esto? (Soy un desarrollador de software experimentado pero tengo experiencia limitada con Docker y ninguna con Ruby).

  3. La llamada FastImage que necesitaría ser ajustada está en models/upload.rb, ¿verdad?

  1. Sí, es correcto, como en mi captura de pantalla anterior.

  2. No sugiero que hagas la modificación. Sin embargo, si no puedes esperar, ciertamente podrías probar ese cambio.

  • Para un cambio temporal (desaparece después de la reconstrucción):
cd /var/discourse
./launcher enter app
sed -i "s/FastImage.new(@file)/FastImage.new(@file, :raise_on_failure=true)/" lib/upload_creator.rb
sed -i "s/FastImage.new(original_path)/FastImage.new(original_path, :raise_on_failure=true)/" app/models/upload.rb
exit
  • Para un cambio persistente (permanece después de la reconstrucción):
cd /var/discourse
nano containers/app.yml  (usa tu editor preferido)

Agrega los siguientes comandos personalizados al final (sección run):

  - replace:
      filename: "/var/www/discourse/lib/upload_creator.rb"
      from: "FastImage.new(@file)"
      to: "FastImage.new(@file, :raise_on_failure=true)"
  - replace:
      filename: "/var/www/discourse/app/models/upload.rb"
      from: "FastImage.new(original_path)"
      to: "FastImage.new(original_path, :raise_on_failure=true)"

Luego, reconstruye:

./launcher rebuild app
  1. Supongo que sí si planeas subir archivos sin extensiones. No comprobé si otras ocurrencias requerían el mismo cambio.
1 me gusta

@Arkshine – Muchas gracias por estos detalles. Pude probar ambas correcciones por separado (cada una en una VM recién restaurada) ¡y ambas funcionaron!

Notas:

  1. Para la corrección temporal, necesité ejecutar “./launcher restart app” para que los cambios tuvieran efecto.

  2. Parece que “spec/models/optimized_image_spec.rb” también tiene una referencia a FastImage.new(). ¿Es necesario actualizar este también como el resto?

¡Gracias de nuevo por tu ayuda!

Me alegro de que funcione. :slight_smile:

  1. Esto es solo para fines de prueba, así que no tienes que preocuparte por ello.

¡Genial! ¡Gracias! Ahora que he probado esto en mi entorno de desarrollo, lo implementaré en los entornos de prueba y producción.

Por cierto, si tienes tiempo, me encantaría conocer tu opinión sobre un problema relacionado (How to customize MIME media type emitted for certain attachments?).

1 me gusta

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.