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:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -496,9 +497,15 @@ func Bootstrap(env string) (*App, error) {
|
||||
// FakeProvider is self-contained (no service/repo/pipeline deps), so we
|
||||
// only need to create the webhook handler here. The provider itself is
|
||||
// registered via init() in the provider package.
|
||||
fakeProvider := channelprovider.NewFakeProvider()
|
||||
fakeWebhookHandler := webhook.NewFakeWebhookHandler(fakeProvider, db, channelDispatcher)
|
||||
fakeWebhookHandler.WithWorkerPool(workerPool)
|
||||
// Skip in production — the fake channel is a test-only tool.
|
||||
var fakeWebhookHandler *webhook.FakeWebhookHandler
|
||||
if !isFakeChannelEnabled(env) {
|
||||
applogger.L().Info("Fake channel provider skipped (production environment)")
|
||||
} else {
|
||||
fakeProvider := channelprovider.NewFakeProvider()
|
||||
fakeWebhookHandler = webhook.NewFakeWebhookHandler(fakeProvider, db, channelDispatcher)
|
||||
fakeWebhookHandler.WithWorkerPool(workerPool)
|
||||
}
|
||||
|
||||
// Create Email webhook handler (Gin HTTP handler for Email webhook endpoints)
|
||||
emailWebhook := emailchannel.NewWebhookHandler()
|
||||
@@ -723,7 +730,9 @@ func Bootstrap(env string) (*App, error) {
|
||||
tiktokWebhookHandler.WithSearchIndexer(searchIndexer)
|
||||
lineWebhookHandler.WithSearchIndexer(searchIndexer)
|
||||
twilioWebhookHandler.WithSearchIndexer(searchIndexer)
|
||||
fakeWebhookHandler.WithSearchIndexer(searchIndexer)
|
||||
if fakeWebhookHandler != nil {
|
||||
fakeWebhookHandler.WithSearchIndexer(searchIndexer)
|
||||
}
|
||||
// Event-triggered automation/AgentBot listeners are registered after the durable
|
||||
// search indexer exists so action side effects keep Meilisearch current.
|
||||
channelDispatcher.Register(automation.NewAgentBotRuleListenerWithSearchIndexer(&dbProvider{db: db}, searchIndexer))
|
||||
@@ -1017,3 +1026,16 @@ func (a *hubTypingAdapter) SetTypingOff(ctx context.Context, accountID, conversa
|
||||
a.hub.SendToAccount(accountID, data)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// isFakeChannelEnabled reports whether the fake test channel should be wired.
|
||||
// It is disabled in production environments to prevent test endpoints from
|
||||
// being exposed in deployed images.
|
||||
func isFakeChannelEnabled(env string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(env)) {
|
||||
case "production", "prod":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user