Skip to content

Calculando HASH

Como calcular corretamente o hash

Assumindo um objeto DOM representando a requisição SOAP e um nome de tag de mensagem TISS válidos. Busque o primeiro nó da mensagem no documento XML que corresponda ao nome fornecido, considerando qualquer namespace.

Ex.: getElementsByTagNameNS('*', nodeName)
  1. Se o nó não for encontrado, considere que houve um erro/exceção.
  2. Extraia todo o conteúdo textual dos nós descendentes do nó alvo.
    1. Para cada nó filho:
      1. Se for um elemento com filhos, aplique a mesma lógica para cada filho.
      2. Senão, se for um nó de texto inclua seu valor textual, removendo espaços em branco extras (início e fim).
      3. Concatene todos os textos extraídos em uma única string e retorne.
    2. Concatene todos os textos extraídos em uma única string e retorne.
  3. Calcule o hash MD5 da string final, representando em hexadecimal (preferencialmente minúsculas mas webservice aceitará a string como case insensitive).
  4. Crie um elemento com a tag <hash>, o conteúdo deve ser o MD5.
  5. Adicione a tag como último filho da tag de mensagem.
  6. Retorne o documento XML atualizado.

Exemplo em NodeJS

import {createHash} from 'node:crypto';
import { DOMParser, XMLSerializer } from 'xmldom';
/**
* Extrai o texto de todos os nós filhos de um nó, em qualquer profundidade.
*
* @param {Node} node
* O nó XML a ser processado.
* @returns {string}
* O texto concatenado dos nós filhos.
*/
function getTextContent(node) {
let text = '';
for (const child of Array.from(node.childNodes)) {
if (child.nodeType === 3) {
text += child.nodeValue.trim();
} else if (child.nodeType === 1) {
text += getTextContent(child);
}
}
return text;
}
/**
* Calcula o HASH MD5 do conteúdo de um nó especificado e adiciona a tag <hash>.
*
* @param {Document} xmlDoc
* O documento XML parseado.
* @param {string} nodeName
* O nome do nó a processar.
* @param {string} [charset='utf-8']
* O charset para codificação (ex.: 'utf-8', 'latin1').
* @returns {Document}
* O documento XML atualizado com a tag <hash>.
* @throws {Error}
* Se o documento for inválido ou o nó não for encontrado.
*/
function calcularHash(xmlDoc, nodeName, charset = 'utf-8') {
if (!xmlDoc || xmlDoc.getElementsByTagName('parsererror').length > 0) {
throw new Error('Documento XML inválido');
}
if (!nodeName || typeof nodeName !== 'string') {
throw new Error('Nome do nó inválido');
}
const targetNode = xmlDoc.getElementsByTagNameNS('*', nodeName)[0];
if (!targetNode) {
throw new Error(`Nó <${nodeName}> não encontrado`);
}
const conteudo = getTextContent(targetNode);
console.log('Conteúdo', conteudo);
const hashMd5 = createHash('md5')
.update(Buffer.from(conteudo, charset.toLowerCase()))
.digest('hex');
const hashTag = xmlDoc.createElement('hash');
hashTag.textContent = hashMd5;
targetNode.appendChild(hashTag);
// Não é necessário, apenas facilita visualização
targetNode.appendChild(xmlDoc.createTextNode('\n '));
return xmlDoc;
}
// main.js
const xmlString = `
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<dados>
<nome>João Assis</nome>
<idade>30</idade>
<cidade>São Paulo</cidade>
<detalhes>
<rua>Avenida Brasil</rua>
</detalhes>
</dados>
</soap:Body>
</soap:Envelope>
`;
async function main() {
try {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, 'application/xml');
if (xmlDoc.getElementsByTagName('parsererror').length > 0) {
throw new Error('Erro ao parsear o XML');
}
let charset = 'utf-8';
const prologo = xmlString.match(/encoding=["'](.*?)["']/i);
if (prologo && prologo[1]) {
charset = prologo[1].toLowerCase();
}
const xmlAtualizado = calcularHash(xmlDoc, 'dados', charset);
const serializer = new XMLSerializer();
const xmlSerializado = serializer.serializeToString(xmlAtualizado);
console.log('XML Atualizado:');
console.log(xmlSerializado);
} catch (error) {
console.error('Falha na execução:', error.message);
}
}
main();