ديسكورس يتعرف بشكل خاطئ على ملف مُحمّل كصورة

لدي بعض المستخدمين الهندسيين الذين يرغبون في إرفاق بعض ملفات البيانات بامتدادات ملفات غير شائعة بمنشوراتهم. إنها في الأساس ملفات نصية عادية ولكنها تتضمن أحرف ASCII الموسعة.

لقد حاولت تحديث تكوين NGINX الخاص بـ Discourse لتحديد أنواع وسائط MIME لهذه الملفات ولكنه لم ينجح. لقد نشرت موضوعًا (How to customize MIME media type emitted for certain attachments?) حول هذا الأمر قبل أسبوعين ولكن لم أتلق أي إجابات حتى الآن. حتى لو لم يتم تحديث NGINX، فسيظل يقدم أنواع الملفات غير المعروفة باستخدام نوع MIME الافتراضي “application/octet-stream”. يمكنني التعايش مع ذلك في الوقت الحالي.

ومع ذلك، عندما يحاول المستخدمون تحميل ملفات البيانات هذه في منشور (إما باستخدام زر “تحميل” أو السحب والإفلات)، فإنهم يحصلون على نافذة منبثقة للخطأ من Discourse مثل هذه:

يبدو أنه عندما يقوم المستخدمون بتحميل الملفات، يحاول Discourse أن يكون ذكيًا ويكتشف ما إذا كان صورة أو نوع ملف آخر. علاوة على ذلك، يبدو أنه يقوم بهذا التحديد من خلال النظر إلى محتويات الملف (على غرار الأمر القياسي في Unix “file”). أفترض أن هذا حتى يقرر Discourse ما إذا كان سيضمنه في محتوى المنشور أو يضعه جانبًا كمرفق.

في حالة ملفات البيانات هذه، فإن هذا الفحص يحدد الملفات بشكل غير صحيح على أنها صور. فقط للمرح، وضعت بعضًا من ملفات البيانات هذه على جهاز Ubuntu وتحققت منها باستخدام الأمر “file”، وبالتأكيد، تم تحديدها على أنها “بيانات صور JPEG”.

هل هناك طريقة للمستخدمين لتحميل الملفات دون محاولة Discourse اكتشاف ما إذا كانت صورًا؟ أي، “يرجى تحميل هذا كمرفق، بغض النظر عن ماهيته، لا تضمنه”؟

بدلاً من ذلك، يمكنني تكوين Discourse للسماح بملفات zip وإخبار المستخدمين بضغط ملفاتهم قبل تحميلها، لكنني أفضل عدم فتح الموقع لتحميلات ملفات zip عشوائية. يبدو هذا مشكلة أمنية.

شكرا مقدما على أي مساعدة!

هناك حل آخر يتمثل في اعتماد امتداد لتلك الملفات الغريبة، مثل .bin أو .data أو حتى .anythinggoes، والتي يجب أن تكون كافية لـ Discourse لترك هذه الملفات وشأنها.

شكراً على الرد السريع! ومع ذلك، لقد جربت ذلك ولم ينجح. يبدو أن Discourse ينظر بالتأكيد إلى محتويات الملف، وليس امتداده، لتحديد ما إذا كان صورة أم لا.

إعجاب واحد (1)

هل لدى أي شخص أي أفكار حول هذا؟ يبدو أن هذا خطأ كبير جدًا.

لقد قمت ببعض البحث حول هذه المشكلة.

باختصار، يتم اكتشاف ملفك على أنه JPEG لأنه يبدأ بنفس التوقيع الخاص بهذا النوع من الملفات.
إصلاح هذا السلوك في Discourse ممكن، ولكنه يتطلب تعديلاً. (انظر في النهاية)


إليك بعض الأمور التقنية.
تبدأ هذه المشكلة هنا:

مكتبة FastImage تفتح الملف وتحدد النوع والحجم.
كما تتوقع، فإنها تُرجع نوع JPEG.

إذا نظرت إلى توقيع JPEG، فإنه يبدو كالتالي:

علامات JPEG

مزيد من المعلومات: List of file signatures - Wikipedia
JPEG - Wikipedia

يبدأ دائمًا ببايتات العلامة التالية: FF D8

بالنظر إلى عينة ملفك باستخدام محرر سداسي عشري، سترى أنها تبدأ بنفس الطريقة.

الآن، إذا نظرت إلى كيفية اكتشاف FastImage لملف JPEG، يمكنك رؤية ذلك هنا:

ومع ذلك، لا يمكنك استخراج أي معلومات عن الصورة نظرًا لعدم وجود جميع البايتات المطلوبة.

كيف نحل هذه المشكلة في Discourse؟
بالنظر إلى كود FastImage، هناك خيار قيم يمكنك تمريره.

باستخدام هذا الخيار، أي خطأ (SizeNotFound، ImageFetchFailure، CannotParseImage، UnknownImageType، BadImageURI) لن يُرجع أي معلومات عن الصورة؛ ولن يتم اكتشاف ملفك كصورة.

@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}")

بعد ذلك، يمكن أن يعمل الآن:

يمكنني إنشاء طلب سحب لاحقًا. استخدام هذا الخيار منطقي هنا. :+1:

إعجابَين (2)

رائع! هذا تحليل رائع! شكرا لك!

بعض الأسئلة السريعة:

  1. مع هذه التغييرات، لن يتم اكتشاف الملف كصورة وسيتم تحميله كغير صورة وعرضه على يمين المنشور؟

  2. إذا فهمت بشكل صحيح، فإنك تقترح علي إجراء هذه التعديلات في نسختي المحلية من Discourse لتجربتها و/أو استخدامها حتى يتم تضمينها في إصدار مستقبلي من Discourse. ولكن كيف أفعل ذلك؟ (أنا مطور برامج ذو خبرة ولكن لدي خبرة محدودة في Docker ولا خبرة لدي في Ruby.)

  3. استدعاء FastImage الذي سيحتاج إلى تعديل موجود في models/upload.rb، أليس كذلك؟

  1. نعم، هذا صحيح – كما في لقطة الشاشة الخاصة بي أعلاه

  2. أنا لا أقترح عليك إجراء التعديل. ومع ذلك، إذا لم تتمكن من الانتظار، يمكنك بالتأكيد اختبار هذا التغيير.

  • لتغيير مؤقت (يختفي بعد إعادة البناء):
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
  • لتغيير دائم (يبقى بعد إعادة البناء):
cd /var/discourse
nano containers/app.yml  (استخدم محرر النصوص المفضل لديك)

أضف الأوامر المخصصة التالية في النهاية (قسم 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)"

ثم، أعد البناء:

./launcher rebuild app
  1. أعتقد ذلك إذا كنت تخطط لتحميل ملفات بدون امتدادات. لم أتحقق مما إذا كانت هناك حالات أخرى تتطلب نفس التغيير.
إعجاب واحد (1)

@Arkshine – شكراً جزيلاً على هذه التفاصيل. تمكنت من اختبار كلا الإصلاحين بشكل منفصل (كل منهما على جهاز افتراضي تم استعادته حديثًا) وكلاهما نجح!

ملاحظات:

  1. بالنسبة للإصلاح المؤقت، احتجت إلى تشغيل “./launcher restart app” حتى تسري التغييرات.

  2. يبدو أن “spec/models/optimized_image_spec.rb” يحتوي أيضًا على إشارة إلى FastImage.new(). هل يجب تحديث هذا أيضًا مثل البقية؟

شكراً مرة أخرى على مساعدتك!

يسرني أنه يعمل. :slight_smile:

  1. هذا فقط لأغراض الاختبار، لذا لا داعي للقلق بشأنه.

عظيم! شكراً! الآن بعد أن اختبرت هذا في بيئة التطوير الخاصة بي، سأقوم بنشره في بيئات الاختبار والإنتاج.

بالمناسبة، إذا كان لديك وقت، أود أن أحصل على أفكارك حول مشكلة ذات صلة (How to customize MIME media type emitted for certain attachments?).

إعجاب واحد (1)

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