#!/usr/bin/env bash
# Funções de assinatura do Dracma em bash + openssl (Contrato §3, §4, §8). Use com `source lib.sh`.
# LIMITAÇÃO: bash não tem comparação em tempo constante e o segredo passa por argumento do openssl
# (visível em `ps` na mesma máquina). Serve para depurar e testar; em produção use Go/Node/PHP.

# O quê: sha256 hex do stdin (bytes crus). Onde: dracma_canonico, vetores.sh.
dracma_sha256() {
  openssl dgst -sha256 -r | cut -d' ' -f1
}

# O quê: HMAC-SHA256 hex do stdin com o segredo $1 (string UTF-8). Onde: dracma_assinar, dracma_v1.
dracma_hmac() {
  openssl dgst -sha256 -hmac "$1" -r | cut -d' ' -f1
}

# O quê: pedido canônico §3, SEM "\n" final. Args: ts nonce MÉTODO path?query arquivo_corpo (ou "" p/ vazio).
# Onde: dracma_assinar, vetores.sh.
dracma_canonico() {
  local ts="$1" nonce="$2" metodo="${3^^}" pq="$4" arq="${5:-}" h
  if [[ -n "$arq" ]]; then h=$(dracma_sha256 < "$arq"); else h=$(printf '' | dracma_sha256); fi
  printf 'v1\n%s\n%s\n%s\n%s\n%s' "$ts" "$nonce" "$metodo" "$pq" "$h"
}

# O quê: valor do header Dracma-Signature ("v1=<hex>"). Args: segredo + os de dracma_canonico.
# Onde: assinar.sh, vetores.sh.
dracma_assinar() {
  local segredo="$1"; shift
  printf 'v1=%s' "$(dracma_canonico "$@" | dracma_hmac "$segredo")"
}

# O quê: v1 de webhook/digest = hex(HMAC(segredo, "<t>." + payload)). Args: segredo t arquivo_payload.
# Onde: verificar-webhook.sh, vetores.sh.
dracma_v1() {
  { printf '%s.' "$2"; cat "$3"; } | dracma_hmac "$1"
}

# O quê: verifica webhook (§4 itens 1–3). Args: arquivo_segredos(1 por linha) Dracma-Timestamp
# Dracma-Signature arquivo_corpo [agora]. Imprime "ok" ou o motivo; retorno 0 só se válido.
# Onde: verificar-webhook.sh, vetores.sh.
dracma_verificar() {
  local segs="$1" tsh="$2" sigh="$3" corpo="$4" agora="${5:-$(date +%s)}" t="" part ok=1 s v want
  local -a v1s=()
  [[ -n "$tsh" && -n "$sigh" ]] || { echo headers_ausentes; return 1; }
  IFS=',' read -r -a parts <<< "$sigh"
  for part in "${parts[@]}"; do
    part="${part// /}"
    case "$part" in
      t=*) [[ -z "$t" ]] || { echo malformado; return 1; }; t="${part#t=}" ;;
      v1=*) v1s+=("${part#v1=}") ;;
      *=*) ;;                       # chave desconhecida: ignora
      *) echo malformado; return 1 ;;
    esac
  done
  [[ "$t" =~ ^[0-9]{1,12}$ && ${#v1s[@]} -gt 0 ]] || { echo malformado; return 1; }
  local d=$(( agora - t )); (( d < 0 )) && d=$(( -d ))
  (( d <= 300 )) || { echo fora_da_janela; return 1; }
  [[ "$tsh" == "$t" ]] || { echo timestamp_difere; return 1; }
  while IFS= read -r s || [[ -n "$s" ]]; do
    [[ -n "$s" ]] || continue
    want=$(dracma_v1 "$s" "$t" "$corpo")
    for v in "${v1s[@]}"; do
      [[ "${v,,}" == "$want" ]] && ok=0
    done
  done < "$segs"
  if (( ok == 0 )); then echo ok; else echo assinatura_invalida; fi
  return "$ok"
}
