package config import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "errors" ) const MinimumFingerprintKeyBytes = 32 var ErrInvalidFingerprint = errors.New("invalid configuration fingerprint") // Fingerprint returns a keyed digest of one fully resolved configuration. // Only the digest is persisted; the resolved configuration and key remain local. func Fingerprint(configuration *Config, key []byte) (string, error) { if configuration == nil || len(key) < MinimumFingerprintKeyBytes { return "", ErrInvalidFingerprint } encoded, err := json.Marshal(configuration) if err != nil { return "", errors.Join(ErrInvalidFingerprint, err) } digest := hmac.New(sha256.New, key) if _, err := digest.Write(encoded); err != nil { return "", errors.Join(ErrInvalidFingerprint, err) } return hex.EncodeToString(digest.Sum(nil)), nil }