memos/server/router/api/v1/user_webhook_test.go
boojack f497f009ce fix(webhook): fail loud on malformed signing secret and add tests
Follow-up to #6013. The signing path silently fell back to using the raw
secret string as the HMAC key when a whsec_-prefixed secret had invalid
base64, producing signatures no receiver could verify with no server-side
signal.

- Extract resolveSigningKey helper that errors on invalid whsec_ base64
- Post returns that error (logged by the async dispatcher); ValidateSigningSecret
  rejects it at write time so a bad secret is never stored
- Fix stale comment referencing a nonexistent Authorization header
- Add Go tests: key derivation, secret validation, end-to-end signature
  round-trip, and the invariant that the secret never leaks into API responses
2026-06-09 22:58:10 +08:00

29 lines
1 KiB
Go

package v1
import (
"testing"
"github.com/stretchr/testify/require"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
// TestConvertUserWebhookFromUserSettingOmitsSigningSecret guards the core security
// invariant of the signing-secret feature: the secret is INPUT_ONLY and must never
// be copied into an API response, even though it is persisted in the user setting.
func TestConvertUserWebhookFromUserSettingOmitsSigningSecret(t *testing.T) {
user := &store.User{Username: "alice"}
stored := &storepb.WebhooksUserSetting_Webhook{
Id: "webhook-id",
Title: "My Webhook",
Url: "https://example.com/postreceive",
SigningSecret: "whsec_super-secret-value",
}
apiWebhook := convertUserWebhookFromUserSetting(stored, user)
require.Equal(t, "My Webhook", apiWebhook.DisplayName)
require.Equal(t, "https://example.com/postreceive", apiWebhook.Url)
require.Empty(t, apiWebhook.SigningSecret, "signing secret must never be returned in API responses")
}