* fix(security): harden auth and credential handling (HH-444) * fix(security): address HH-444 review blockers * fix(security): close remaining HH-444 review blockers --------- Co-authored-by: Rogee <rogee@ipao.vip>
77 lines
3.6 KiB
Go
77 lines
3.6 KiB
Go
package model
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// WebhookSubscription represents an account-level webhook subscription for outgoing events.
|
|
// Reference: Chatwoot webhook integration + P2B M8 spec
|
|
type WebhookSubscription struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
AccountID uint `gorm:"not null;index" json:"account_id"`
|
|
InboxID *uint `gorm:"index" json:"inbox_id,omitempty"`
|
|
Name string `gorm:"size:255" json:"name,omitempty"`
|
|
URL string `gorm:"size:2048;not null" json:"url"`
|
|
Events json.RawMessage `gorm:"type:jsonb;not null" json:"subscriptions"` // JSON array of event types, e.g. ["conversation_created","message_created"]
|
|
Secret string `gorm:"size:512;not null" json:"-" secure:"webhook_secret"` // HMAC-SHA256 signing secret
|
|
WebhookType int `gorm:"default:0" json:"webhook_type,omitempty"`
|
|
Active bool `gorm:"default:true" json:"active"`
|
|
VerifiedAt *time.Time `json:"verified_at,omitempty"`
|
|
LastDeliveryStatus string `gorm:"size:50" json:"last_delivery_status,omitempty"` // success/failed/pending
|
|
LastDeliveryAt *time.Time `json:"last_delivery_at,omitempty"`
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
|
|
|
Account Account `gorm:"foreignKey:AccountID" json:"account,omitempty"`
|
|
Inbox Inbox `gorm:"foreignKey:InboxID" json:"inbox,omitempty"`
|
|
}
|
|
|
|
func (WebhookSubscription) TableName() string { return "webhook_subscriptions" }
|
|
|
|
// WebhookDeliveryStatus constants for delivery tracking.
|
|
const (
|
|
WebhookDeliveryStatusPending = "pending"
|
|
WebhookDeliveryStatusSuccess = "success"
|
|
WebhookDeliveryStatusFailed = "failed"
|
|
WebhookDeliveryStatusRetrying = "retrying"
|
|
)
|
|
|
|
// IsEventSubscribed checks whether the subscription includes a given event type.
|
|
// The Events field is a JSON array of event type strings, e.g. ["conversation_created","message_created"].
|
|
func (s *WebhookSubscription) IsEventSubscribed(eventType string) bool {
|
|
var events []string
|
|
if err := json.Unmarshal(s.Events, &events); err != nil {
|
|
return false
|
|
}
|
|
for _, e := range events {
|
|
if e == eventType {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// WebhookDelivery represents a single webhook delivery attempt.
|
|
// Reference: Chatwoot webhook delivery tracking + P2B M8 spec
|
|
type WebhookDelivery struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
SubscriptionID uint `gorm:"not null;index" json:"subscription_id"`
|
|
EventType string `gorm:"size:100;not null;index" json:"event_type"`
|
|
Payload json.RawMessage `gorm:"type:jsonb" json:"payload"`
|
|
ResponseCode int `json:"response_code,omitempty"`
|
|
ResponseBody string `gorm:"size:4096" json:"response_body,omitempty"`
|
|
Status string `gorm:"size:50;not null;index" json:"status"` // success/failed/retrying
|
|
Attempts int `gorm:"default:0" json:"attempts"`
|
|
NextAttemptAt *time.Time `json:"next_attempt_at,omitempty"`
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
|
|
Subscription WebhookSubscription `gorm:"foreignKey:SubscriptionID" json:"subscription,omitempty"`
|
|
}
|
|
|
|
func (WebhookDelivery) TableName() string { return "webhook_deliveries" }
|