package merchantsign import ( "net/http" "strings" "testing" "time" ) // The published test vector (Integration Guide › Authentication). func TestVector(t *testing.T) { const key, path, code, ts, rid = "test-secret-key-0001", "/wallet/debit", "M0001", "1792000000000", "req-0001" body := []byte(`{"txnId":"T7K2M9QXH4ZP8WNA","amount":"10.00"}`) if got := BodySHA256(body); got != "b8d0525520debc2d5e2c62e83d2303a4cd29ed0c18c4139e98196c76c14fc2b8" { t.Fatalf("body hash %s", got) } sig := Sign(key, "POST", path, code, ts, rid, body) if sig != "e5273ee9fb4c05408af2f8b32b26b4b98bc891fb77e5ffe5b46f9c112ebe6589" { t.Fatalf("signature %s", sig) } h := http.Header{} h.Set(HeaderMerchantCode, code) h.Set(HeaderRequestID, rid) h.Set(HeaderTimestamp, ts) h.Set(HeaderSignature, sig) now := time.UnixMilli(1792000000000) for name, c := range map[string]struct { code, body string at time.Time want string }{ "valid": {code, string(body), now, OK}, "tampered body": {code, strings.Replace(string(body), "10.00", "10.01", 1), now, InvalidSignature}, "other code": {"M0002", string(body), now, InvalidSignature}, "stale": {code, string(body), now.Add(TimestampWindow + time.Millisecond), TimestampExpired}, } { if got := Verify(key, c.code, h, "POST", path, []byte(c.body), c.at); got != c.want { t.Errorf("%s: %s, want %s", name, got, c.want) } } req, _ := http.NewRequest("POST", "https://wallet.example.com"+path, nil) SignRequest(req, code, key, body, now) if got := Verify(key, code, req.Header, "POST", path, body, now); got != OK { t.Fatalf("SignRequest then Verify: %s", got) } }