我需要能够在客户端JavaScript应用程序和Ruby服务器上的同一文件上运行MD5哈希。
目前我不能让两个哈希都相同。
在客户端上,我使用JQuery File Upload将文件上传到S3存储桶。我正在使用Crypto在回调中散列文件:
file = data.files[0]
filename = file.name;
md5 = CryptoJS.MD5(CryptoJS.enc.Hex.parse(data.files[0].toString()));
这给了我: ee9cd5bf4272fc35bd57d184553bd25b
在Ruby中,它是一个模块Digest::MD5模块,由Gem用于散列:
Digest::MD5.file(file).to_s
这给了我: 4d51c9a4d3fd076489d6c96614ebce61
我无法控制Ruby方面,但为什么Crypto生成的校验和会有所不同?
请注意,我可以使用相同的API在本地测试:
path = 'path/to/file.jpg'
Digest::MD5.file(f).hexdigest
# 4d51c9a4d3fd076489d6c96614ebce61
该文件是一个大jpg(~1.8meg)
更新:为了回应@ kxyz的回答,使用不同编码器的加密js的结果是:
CryptoJS.MD5(CryptoJS.enc.Hex.parse(data.files[0].toString()));
// ee9cd5bf4272fc35bd57d184553bd25b
CryptoJS.MD5(CryptoJS.enc.Utf8.parse(data.files[0].toString()));
// 709d1d31dc47636e4f5ccbfd07601c19
CryptoJS.MD5(CryptoJS.enc.Latin1.parse(data.files[0].toString()));
// 709d1d31dc47636e4f5ccbfd07601c19
我还使用bash md5
检查了从S3下载的复制文件的原始文件,该文件为两个文件生成了相同的哈希值:
4d51c9a4d3fd076489d6c96614ebce61 ,这与Ruby生成的哈希相同。
还使用online hasher检查哈希:
4d51c9a4d3fd076489d6c96614ebce61
答案 0 :(得分:2)
您使用CryptoJS.enc.Latin1
,而在Ruby中,您不需要定义编码Digest::MD5.file(file).to_s
。请务必使用相同的编码。
尝试
Digest::MD5.hexdigest('foobar')
和
CryptoJS.MD5(CryptoJS.enc.Hex.parse('foobar'));
答案 1 :(得分:1)
data.files[0].toString()
没有做你认为它正在做的事情。它只返回一个“[object File]”字符串而不是文件的内容。
您实际上需要读取文件,例如:
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
var hash = CryptoJS.MD5(contents);
console.log(hash);
console.log(hash.toString(CryptoJS.enc.Base64));
};
// Read in the image file as a data URL.
reader.readAsBinaryString(data.files[0]);
CryptoJS.MD5()
的输出是本机CryptoJS二进制数组(WordArray
)。以字符串形式打印时,默认情况下将其序列化为十六进制编码。如果您想要其他编码,则需要将其传递给toString()
函数。
答案 2 :(得分:0)
我在使用uWSGI的网络主机上遇到了非常相似的问题。原来上传的文件数据有几个字符,导致md5不匹配,并且Rails在删除上传的文件后发出422响应。
如果您遇到相同的情况,这里是解决方法:
# app/controllers/upload_controller.rb <- Create this file
class UploadController < ActiveStorage::DiskController
def update
request.env['RAW_POST_DATA'] = request.body.read(request.content_length)
super
end
end
# config/routes.rb <- Edit this file
Rails.application.routes.draw do
# [your routes]
# Add the following two lines:
# Fix IntegrityError caused by uWSGI upload
put '/rails/active_storage/disk/:encoded_token', to: 'upload#update'
end
Original discussion (in French)在哪里找到修复程序。