xyzzy
2023 年10 月 26 日 17:44
1
我的一些工程用户希望将具有不常见文件扩展名的数据文件附加到他们的帖子中。它们本质上是纯文本文件,但包含扩展的 ASCII 字符。
我曾尝试更新 Discourse 的 NGINX 配置以指定这些文件的 MIME 媒体类型,但没有成功。我两周前发布了一个主题(https://meta.discourse.org/t/how-to-customize-mime-media-type-emitted-for-certain-attachments/282111)但至今未收到任何答复。即使不更新 NGINX,它仍将使用“application/octet-stream”的备用 MIME 类型来提供未知文件类型。我现在可以接受这一点。
但是,当用户尝试将这些数据文件上传 到帖子中时(无论是使用“上传”按钮还是拖放),他们会收到一个来自 Discourse 的错误弹出窗口,如下所示:
看起来当用户上传文件时,Discourse 会尝试变得智能并检测它是图像还是其他文件类型。此外,它似乎通过查看文件内容(很像标准的 Unix 命令“file”)来做出此决定。我假设这是为了让 Discourse 决定是将其内联到帖子内容中还是将其作为附件放在旁边。
对于这些数据文件,此检查错误地将文件识别为图像。只是为了好玩,我在 Ubuntu 机器上放了一些这些数据文件,并使用“file”命令进行了检查,果然,它们被识别为“JPEG image data”。
有没有办法让用户在不让 Discourse 尝试检测它们是否为图像的情况下上传文件?即,“请将此作为附件上传,无论如何,不要内联”?
或者,我可以配置 Discourse 以允许 zip 文件,并告诉用户在上传文件之前将它们压缩,但我宁愿不向站点开放随机 zip 文件上传。这似乎是一个安全问题。
感谢您的帮助!
Falco
(Falco)
2023 年10 月 26 日 17:47
2
另一种解决方法是为那些奇怪的文件采用一个扩展名,比如 .bin、.data 或者干脆 .anythinggoes,这应该足以让 Discourse 不去管这些文件。
xyzzy
2023 年10 月 26 日 17:59
3
感谢您的快速回复! 但是,我尝试了您的方法,但它不起作用。 Discourse 绝对是根据文件内容而不是扩展名来确定它是否为图像。
1 个赞
xyzzy
2023 年11 月 15 日 23:54
4
有人对此有什么看法吗?这似乎是一个相当严重的错误。
我对此问题进行了一些研究。
简而言之,您的文件被检测为 JPEG,因为它以与此类文件相同的签名开头。
在 Discourse 中修复此行为是可能的,但这需要进行修改。(见文末)
这里有一些技术细节。
此问题始于:
FastImage 库打开文件并确定类型和大小。
正如您所料,它返回 JPEG 类型。
如果您查看 JPEG 签名 ,它看起来像这样:
JPEG 标记
更多信息:List of file signatures - Wikipedia
JPEG - Wikipedia
它总是以以下标记字节开头:FF D8
使用十六进制编辑器查看您的文件样本,您会发现它以相同的方式开头。
现在,如果您查看 FastImage 如何检测 JPEG,您可以在此处看到:
# frozen_string_literal: true
# coding: ASCII-8BIT
# FastImage finds the size or type of an image given its uri.
# It is careful to only fetch and parse as much of the image as is needed to determine the result.
# It does this by using a feature of Net::HTTP that yields strings from the resource being fetched
# as soon as the packets arrive.
#
# No external libraries such as ImageMagick are used here, this is a very lightweight solution to
# finding image information.
#
# FastImage knows about GIF, JPEG, BMP, TIFF, ICO, CUR, PNG, HEIC/HEIF, AVIF, PSD, SVG, WEBP and JXL files.
#
# FastImage can also read files from the local filesystem by supplying the path instead of a uri.
# In this case FastImage reads the file in chunks of 256 bytes until
# it has enough. This is possibly a useful bandwidth-saving feature if the file is on a network
# attached disk rather than truly local.
#
# FastImage will automatically read from any object that responds to :read - for
# instance an IO object if that is passed instead of a URI.
This file has been truncated. show original
但是,您无法提取任何图像信息,因为缺少所有必需的字节。
如何在 Discourse 中修复此问题?
查看 FastImage 代码,您可以传递一个有用的选项。
# frozen_string_literal: true
# coding: ASCII-8BIT
# FastImage finds the size or type of an image given its uri.
# It is careful to only fetch and parse as much of the image as is needed to determine the result.
# It does this by using a feature of Net::HTTP that yields strings from the resource being fetched
# as soon as the packets arrive.
#
# No external libraries such as ImageMagick are used here, this is a very lightweight solution to
# finding image information.
#
# FastImage knows about GIF, JPEG, BMP, TIFF, ICO, CUR, PNG, HEIC/HEIF, AVIF, PSD, SVG, WEBP and JXL files.
#
# FastImage can also read files from the local filesystem by supplying the path instead of a uri.
# In this case FastImage reads the file in chunks of 256 bytes until
# it has enough. This is possibly a useful bandwidth-saving feature if the file is on a network
# attached disk rather than truly local.
#
# FastImage will automatically read from any object that responds to :read - for
# instance an IO object if that is passed instead of a URI.
This file has been truncated. show original
使用此选项,任何错误(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}")
然后,它现在可以工作了:
我稍后可以做一个 PR。使用此选项在这里是有意义的。
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 个赞
xyzzy
2023 年11 月 25 日 00:39
8
@Arkshine – 非常感谢您提供这些详细信息。我能够分别测试这两个修复程序(每个修复程序都在一个已恢复的 VM 上进行测试),它们都奏效了!
备注:
对于临时修复,我需要运行“./launcher restart app”才能使更改生效。
看起来“spec/models/optimized_image_spec.rb”也引用了 FastImage.new()。这个也需要像其他的一样更新吗?
再次感谢您的帮助!
xyzzy
2023 年11 月 25 日 00:48
10
太好了!谢谢!既然我已经在我开发的で环境(dev env)中测试过了,接下来我会将其部署到测试和生产环境(test and prod envs)。
顺便说一句,如果你有时间,我很想听听你对一个相关问题的看法(https://meta.discourse.org/t/how-to-customize-mime-media-type-emitted-for-certain-attachments/282111)。
1 个赞
system
(system)
关闭
2023 年12 月 25 日 00:49
11
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.