Sign produces signed auth headers using the given HMAC secret. This is the canonical entry point — callers (the relay, in particular) look up the per-user secret and pass it in directly. The Signer struct below is a thin wrapper kept for tests and the legacy deployment-wide signing path.
(secret string, p AuthPayload)
| 59 | // struct below is a thin wrapper kept for tests and the legacy |
| 60 | // deployment-wide signing path. |
| 61 | func Sign(secret string, p AuthPayload) AuthHeaders { |
| 62 | ts := time.Now().UTC().Format(time.RFC3339) |
| 63 | verified := "false" |
| 64 | if p.Verified { |
| 65 | verified = "true" |
| 66 | } |
| 67 | |
| 68 | delegation := "" |
| 69 | if p.AgentID != "" && p.HumanID != "" { |
| 70 | delegation = fmt.Sprintf("agent=%s;human=%s", p.AgentID, p.HumanID) |
| 71 | } |
| 72 | |
| 73 | canonical := canonicalString(verified, p.Sender, p.EntityType, p.DomainCheck, delegation, ts, p.MessageID, p.BodyHash) |
| 74 | |
| 75 | mac := hmac.New(sha256.New, []byte(secret)) |
| 76 | mac.Write([]byte(canonical)) |
| 77 | sig := hex.EncodeToString(mac.Sum(nil)) |
| 78 | |
| 79 | h := AuthHeaders{ |
| 80 | HeaderVerified: verified, |
| 81 | HeaderSender: p.Sender, |
| 82 | HeaderEntityType: p.EntityType, |
| 83 | HeaderDomainCheck: p.DomainCheck, |
| 84 | HeaderTimestamp: ts, |
| 85 | HeaderMessageID: p.MessageID, |
| 86 | HeaderBodyHash: p.BodyHash, |
| 87 | HeaderSignature: sig, |
| 88 | } |
| 89 | if delegation != "" { |
| 90 | h[HeaderDelegation] = delegation |
| 91 | } |
| 92 | return h |
| 93 | } |
| 94 | |
| 95 | // Verify checks a header set against any of the provided secrets and |
| 96 | // the default replay window. Returns true if any secret produces a |