diff --git a/backend/internal/app/app.go b/backend/internal/app/app.go index 7ce19c41..75b93422 100644 --- a/backend/internal/app/app.go +++ b/backend/internal/app/app.go @@ -252,13 +252,8 @@ func (a *App) Reloader() *config.ConfigReloader { } func initDB(cfg *config.Config) (*gorm.DB, error) { - gormLogger := logger.New( - log.Default(), - logger.Config{LogLevel: logger.Info}, - ) - db, err := gorm.Open(postgres.Open(cfg.Database.DSN), &gorm.Config{ - Logger: gormLogger, + Logger: newDatabaseLogger(log.Default(), logger.Info), }) if err != nil { return nil, err diff --git a/backend/internal/app/database.go b/backend/internal/app/database.go index 431d3e8b..fc2df08f 100644 --- a/backend/internal/app/database.go +++ b/backend/internal/app/database.go @@ -35,7 +35,7 @@ func NewDatabase(cfg *config.DatabaseConfig, logLevel string) (*gorm.DB, error) } db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ - Logger: newDatabaseLogger(gormLogLevel), + Logger: newDatabaseLogger(log.New(os.Stdout, "\r\n", log.LstdFlags), gormLogLevel), PrepareStmt: true, DisableForeignKeyConstraintWhenMigrating: true, // migrate first, add FK constraints later }) @@ -61,8 +61,8 @@ func NewDatabase(cfg *config.DatabaseConfig, logLevel string) (*gorm.DB, error) return db, nil } -func newDatabaseLogger(level gormlogger.LogLevel) gormlogger.Interface { - return gormlogger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), gormlogger.Config{ +func newDatabaseLogger(writer gormlogger.Writer, level gormlogger.LogLevel) gormlogger.Interface { + return gormlogger.New(writer, gormlogger.Config{ SlowThreshold: 200 * time.Millisecond, LogLevel: level, IgnoreRecordNotFoundError: true, diff --git a/backend/internal/app/database_test.go b/backend/internal/app/database_test.go index 7ded0d82..b27bf6ee 100644 --- a/backend/internal/app/database_test.go +++ b/backend/internal/app/database_test.go @@ -1,19 +1,34 @@ package app import ( - "context" + "bytes" + "log" "testing" "github.com/stretchr/testify/require" + "gorm.io/driver/sqlite" "gorm.io/gorm" gormlogger "gorm.io/gorm/logger" ) -func TestDatabaseLoggerRedactsQueryParameters(t *testing.T) { - filter, ok := newDatabaseLogger(gormlogger.Info).(gorm.ParamsFilter) - require.True(t, ok) +type databaseLoggerFixture struct { + ID uint + PubsubToken string +} - sql, params := filter.ParamsFilter(context.Background(), "SELECT * FROM contact_inboxes WHERE pubsub_token = ?", "secret-token") - require.Equal(t, "SELECT * FROM contact_inboxes WHERE pubsub_token = ?", sql) - require.Empty(t, params) +func TestDatabaseLoggerRedactsQueryParametersAndIgnoresRecordNotFound(t *testing.T) { + var output bytes.Buffer + db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=private"), &gorm.Config{ + Logger: newDatabaseLogger(log.New(&output, "", 0), gormlogger.Info), + }) + require.NoError(t, err) + require.NoError(t, db.AutoMigrate(&databaseLoggerFixture{})) + output.Reset() + + const secret = "secret-pubsub-token" + err = db.Where("pubsub_token = ?", secret).First(&databaseLoggerFixture{}).Error + require.ErrorIs(t, err, gorm.ErrRecordNotFound) + require.Contains(t, output.String(), "pubsub_token = ?") + require.NotContains(t, output.String(), secret) + require.NotContains(t, output.String(), "record not found") } diff --git a/backend/internal/handler/ws/ws_test.go b/backend/internal/handler/ws/ws_test.go index 43aeb98f..5a0beb00 100644 --- a/backend/internal/handler/ws/ws_test.go +++ b/backend/internal/handler/ws/ws_test.go @@ -859,6 +859,24 @@ func TestServeCable_WidgetReceivesTokenRoomEvent(t *testing.T) { assert.Equal(t, map[string]interface{}{}, payload["additional_attributes"]) } +func TestServeCable_UnknownPubsubTokenReturnsUnauthorized(t *testing.T) { + gin.SetMode(gin.TestMode) + db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=private"), &gorm.Config{}) + require.NoError(t, err) + require.NoError(t, db.AutoMigrate(&model.Account{}, &model.Contact{}, &model.Inbox{}, &model.ContactInbox{})) + + handler := NewHandler(NewHubSimple(), wspkg.NewWSAuthenticator(nil, repository.NewContactInboxRepo(db), db)) + router := gin.New() + router.GET("/cable", handler.ServeCable) + server := httptest.NewServer(router) + t.Cleanup(server.Close) + + response, err := http.Get(server.URL + "/cable?pubsub_token=stale-token") + require.NoError(t, err) + t.Cleanup(func() { _ = response.Body.Close() }) + require.Equal(t, http.StatusUnauthorized, response.StatusCode) +} + func TestDashboardOutgoingReachesDashboardAndReconnectedWidget(t *testing.T) { gin.SetMode(gin.TestMode) db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=private"), &gorm.Config{})