refactor(webhooks): mask write-only credentials in the model so create/update never echo them
Webhook.ReadAll already cleared the secret and basic-auth from responses, but Create and Update did not, so the v2 handler patched the gap with a maskWebhookCredentials helper. Centralize the masking in the model via a maskCredentials helper called after every DB write (ReadAll, Create, Update) and drop the v2 handler helper. The credentials are client-provided, not server-generated: the DB row keeps them and outgoing deliveries reload + HMAC-sign from the DB copy, so clearing the returned in-memory struct is correct write-only handling. Webhook is a shared model, so v1's create/update responses also stop echoing the submitted secret/auth — intended, and approved by the maintainer.
This commit is contained in:
parent
98741d8171
commit
aac0322975
|
|
@ -79,6 +79,17 @@ func (w *Webhook) TableName() string {
|
|||
return "webhooks"
|
||||
}
|
||||
|
||||
// maskCredentials clears the write-only secret and basic-auth fields so they are
|
||||
// never echoed back in a response. The client already submitted these values and
|
||||
// the DB row keeps them (outgoing deliveries reload and sign from the DB copy);
|
||||
// only the in-memory struct returned to the caller is cleared. Always call this
|
||||
// after the DB write, never before.
|
||||
func (w *Webhook) maskCredentials() {
|
||||
w.Secret = ""
|
||||
w.BasicAuthUser = ""
|
||||
w.BasicAuthPassword = ""
|
||||
}
|
||||
|
||||
var availableWebhookEvents map[string]bool
|
||||
var availableWebhookEventsLock *sync.Mutex
|
||||
var userDirectedWebhookEvents map[string]bool
|
||||
|
|
@ -183,6 +194,11 @@ func (w *Webhook) Create(s *xorm.Session, a web.Auth) (err error) {
|
|||
}
|
||||
|
||||
w.CreatedBy, err = user.GetUserByID(s, a.GetID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.maskCredentials()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -234,9 +250,7 @@ func (w *Webhook) ReadAll(s *xorm.Session, a web.Auth, _ string, page int, perPa
|
|||
}
|
||||
|
||||
for _, webhook := range ws {
|
||||
webhook.Secret = ""
|
||||
webhook.BasicAuthUser = ""
|
||||
webhook.BasicAuthPassword = ""
|
||||
webhook.maskCredentials()
|
||||
if createdBy, has := users[webhook.CreatedByID]; has {
|
||||
webhook.CreatedBy = createdBy
|
||||
}
|
||||
|
|
@ -268,6 +282,11 @@ func (w *Webhook) Update(s *xorm.Session, _ web.Auth) (err error) {
|
|||
_, err = s.Where("id = ?", w.ID).
|
||||
Cols("events").
|
||||
Update(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.maskCredentials()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ func webhooksCreate(ctx context.Context, in *struct {
|
|||
if err := handler.DoCreate(ctx, &in.Body, a); err != nil {
|
||||
return nil, translateDomainError(err)
|
||||
}
|
||||
maskWebhookCredentials(&in.Body)
|
||||
return &singleBody[models.Webhook]{Body: &in.Body}, nil
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +136,6 @@ func webhooksUpdate(ctx context.Context, in *struct {
|
|||
if err := handler.DoUpdate(ctx, &in.Body, a); err != nil {
|
||||
return nil, translateDomainError(err)
|
||||
}
|
||||
maskWebhookCredentials(&in.Body)
|
||||
return &singleBody[models.Webhook]{Body: &in.Body}, nil
|
||||
}
|
||||
|
||||
|
|
@ -154,13 +152,3 @@ func webhooksDelete(ctx context.Context, in *struct {
|
|||
}
|
||||
return &emptyBody{}, nil
|
||||
}
|
||||
|
||||
// maskWebhookCredentials clears the write-only secret and auth fields so a
|
||||
// create/update response never echoes them back, mirroring how ReadAll masks
|
||||
// them. The fields are tagged writeOnly in the schema, but that is docs-only —
|
||||
// Huma does not strip them at runtime, so we clear them here.
|
||||
func maskWebhookCredentials(w *models.Webhook) {
|
||||
w.Secret = ""
|
||||
w.BasicAuthUser = ""
|
||||
w.BasicAuthPassword = ""
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue