fix: harden fake channel — production guard, token validation, typing events, URL validation, capability narrowing

- Guard fake channel with GOCHAT_ENV check: skip init() registration,
  bootstrap wiring, and inbox creation in production
- Reject empty-token webhooks in production (was silently skipped)
- Use PostgreSQL jsonb @> query for inbox lookup, keep SQLite fallback
- Replace isValidURL string-prefix hack with net/url.Parse
- Handle typing.start/typing.stop by returning nil (no garbage messages)
- Narrow Capabilities to only implemented features (Attachments, Replies)
- Hide fake channel from frontend channel list in production builds
This commit is contained in:
2026-07-10 10:55:54 +08:00
parent 9c852cd99b
commit 05af5ebcbc
6 changed files with 151 additions and 27 deletions
@@ -152,13 +152,26 @@ func (h *FakeWebhookHandler) HandleFakeWebhook(c *gin.Context) {
}
// lookupInbox finds the Inbox for a fake channel by config identifier.
// Fake channels store all config in Inbox.ChannelConfig JSON, so we query all
// fake inboxes and filter by the identifier field in Go (SQLite-compatible).
// On PostgreSQL, uses jsonb containment for a DB-side indexed lookup.
// On SQLite (test mode), falls back to loading all fake inboxes and
// filtering in Go — acceptable for low-volume test traffic.
func (h *FakeWebhookHandler) lookupInbox(identifier string) (*model.Inbox, error) {
if h.db == nil {
return nil, fmt.Errorf("fake webhook database is not configured")
}
// PostgreSQL: use jsonb @> for a server-side, indexable query.
if h.db.Dialector.Name() == "postgres" {
var inbox model.Inbox
// channel_config @> '{"identifier":"<id>"}'
query := fmt.Sprintf(`channel_type = 'fake' AND channel_config @> '{"identifier":"%s"}'`, identifier)
if err := h.db.Where(query).First(&inbox).Error; err != nil {
return nil, fmt.Errorf("fake inbox not found for identifier=%s: %w", identifier, err)
}
return &inbox, nil
}
// SQLite fallback: load all fake inboxes and filter in Go.
var inboxes []model.Inbox
if err := h.db.Where("channel_type = ?", "fake").Find(&inboxes).Error; err != nil {
return nil, fmt.Errorf("failed to query fake inboxes: %w", err)