Os hashes de anexo do Couchdb não correspondem ao conteúdo do anexo

2

Ao fazer algumas auditorias de um banco de dados, descobri que alguns conteúdos de anexos não correspondiam aos hashes dados no _attachments map do documento.

Eu testei isso baixando o documento e calculando seu hash. Comparando isso com couchdb mostrou que eles não combinavam. Então notei que os anexos incompatíveis eram aqueles que o couchdb estava configurado para compactar. Parece que meu id de sofá foi configurado para usar compactação instantânea:

foobox# grep -E 'file_compression|compressible_types' /etc/couchdb/{default,local}.ini 
/etc/couchdb/default.ini:file_compression = snappy
/etc/couchdb/default.ini:compressible_types = text/*, application/javascript, application/json, application/xml

No entanto, quando tento compactar o conteúdo do anexo usando instantâneo e calculo o hash dos dados compactados, ainda não corresponde ao hash do couchdb. No meu exemplo abaixo, document-25977 está descompactado (digite application / pdf), e o hash descompactado corresponde ao fornecido pelo couchdb. O segundo, document-78608 , é um tipo compressível (text / plain), e os hashes não correspondem:

foobox$ python hashcompare.py
document-25977
couch len:  142918
couch hash:  028540dd92e1982bcb65c29d32e9617e (md5)
local uncompressed len:  142918
local uncompressed hash:  028540dd92e1982bcb65c29d32e9617e
local compressed len:  132333
local compressed hash:  3157583223dc1a53e1a3386d6abc312d

document-78608
couch len:  2180
couch hash:  e613ab6d7f884b835142979489170499 (md5)
local uncompressed len:  2180
local uncompressed hash:  0ab2516c820f5d7afb208e3be7b924dd
local compressed len:  1382
local compressed hash:  d9e79232662f57e6af262fc9f867eaf2

Este é o script que usei para fazer a comparação:

import couchdb
import snappy
import md5
import base64

server = couchdb.Server('http://localhost:9999')

db = server['program1']

for doc_id in ['document-25977', 'document-78608']:
    print doc_id
    doc = db[doc_id]
    att_stub = doc['_attachments'][doc_id]
    hash_type, tmpdigest = att_stub['digest'].split('-', 1)
    att = db.get_attachment(doc, doc_id)
    data = att.read()
    # CouchDB is using snappy compression
    compressed_data = snappy.compress(data)

    print 'couch len: ', att_stub['length']
    print 'couch hash: ', base64.b64decode(tmpdigest).encode('hex'), '(%s)' % hash_type
    print 'local uncompressed len: ', len(data)
    print 'local uncompressed hash: ', md5.md5(data).digest().encode('hex')
    print 'local compressed len: ', len(compressed_data)
    print 'local compressed hash: ', md5.md5(compressed_data).digest().encode('hex')
    print

Eu verifiquei que os documentos não estão corrompidos quando buscados. Então, o que estou perdendo? Eu não sou versado o suficiente em Erlang para ler a fonte couchdb e descobrir o que está acontecendo. Por que os documentos têm um resumo que não corresponde ao seu conteúdo compactado ou de outra forma?

    
por vezult 07.11.2013 / 20:43

2 respostas

1

Não tenho certeza se você resolveu isso, mas comecei a seguir o mesmo caminho. Depois de olhar um pouco para a fonte, parece que os cálculos de digest ocorrem antes da compressão, então eu não acredito que a compressão terá um efeito sobre o valor da digestão.

Eu consegui reproduzir o resumo md5 produzido pelo CouchDB para anexos usando o seguinte no nó:

var crypto = require('crypto');

var attachmentData = "base64-encoded-data"

var buf = new Buffer(attachmentData, 'base64')
  , md5 = crypto.createHash('md5').update(buf).digest('base64');

Espero que isso ajude você ou alguém que esteja pesquisando detalhes no futuro.

    
por 23.04.2014 / 11:23
0

O CouchDB calcula o hash após a compactação para arquivos compactáveis.

Mas os anexos são compactados com o zlib e não consigo corresponder ao que eles fazem, portanto, a única solução parece buscar o resumo depois de fazer o upload e armazená-lo em algum lugar.

    
por 23.05.2014 / 15:02

Tags