fixed settings smtp password clear persistence
This commit is contained in:
@@ -327,6 +327,8 @@ func (s *Settings) MarshalJSON() ([]byte, error) {
|
||||
copy := s.settings
|
||||
s.mu.RUnlock()
|
||||
|
||||
copy.SMTP.hidePassword = true
|
||||
|
||||
sensitiveFields := []*string{
|
||||
©.SMTP.Password,
|
||||
©.S3.Secret,
|
||||
@@ -346,6 +348,12 @@ func (s *Settings) MarshalJSON() ([]byte, error) {
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
type SMTPConfig struct {
|
||||
// @todo temp workaround to avoid introducing breaking changes;
|
||||
// consider refactoring and/or normalizing with the other Settings sensitive fields
|
||||
//
|
||||
// hidePassword specifies whether to hide the password field from the struct JSON serialization.
|
||||
hidePassword bool
|
||||
|
||||
Enabled bool `form:"enabled" json:"enabled"`
|
||||
Port int `form:"port" json:"port"`
|
||||
Host string `form:"host" json:"host"`
|
||||
@@ -392,6 +400,27 @@ func (c SMTPConfig) Validate() error {
|
||||
)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the [json.Marshaler] interface.
|
||||
func (c SMTPConfig) MarshalJSON() ([]byte, error) {
|
||||
type alias SMTPConfig
|
||||
|
||||
if c.hidePassword {
|
||||
v := struct {
|
||||
alias
|
||||
Password string `json:"password,omitempty"`
|
||||
}{alias(c), ""}
|
||||
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
v := struct {
|
||||
alias
|
||||
Password string `json:"password"`
|
||||
}{alias(c), c.Password}
|
||||
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
type S3Config struct {
|
||||
|
||||
@@ -3,6 +3,7 @@ package core_test
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tests"
|
||||
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||
"github.com/pocketbase/pocketbase/tools/security"
|
||||
)
|
||||
|
||||
func TestSettingsDelete(t *testing.T) {
|
||||
@@ -24,6 +26,72 @@ func TestSettingsDelete(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettings_DBExport(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
encryption bool
|
||||
}{
|
||||
{"no encryption", false},
|
||||
{"with encryption", true},
|
||||
}
|
||||
|
||||
encryptionKey := strings.Repeat("a", 32)
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
originalEnv := os.Getenv(app.EncryptionEnv())
|
||||
defer func() {
|
||||
os.Setenv(app.EncryptionEnv(), originalEnv)
|
||||
}()
|
||||
|
||||
settings := &core.Settings{}
|
||||
settings.Meta.AppName = "test_app_name"
|
||||
settings.Logs.MaxDays = 123
|
||||
settings.SMTP.Host = "smtp_host"
|
||||
settings.SMTP.Username = "smtp_username"
|
||||
settings.SMTP.Password = "" // ensures that empty password is exported
|
||||
settings.S3.Endpoint = "s3_endpoint"
|
||||
settings.S3.Secret = "s3_secret"
|
||||
settings.Backups.Cron = "* * * * *"
|
||||
settings.Backups.S3.Enabled = true
|
||||
settings.Backups.S3.Secret = ""
|
||||
settings.Batch.Timeout = 15
|
||||
settings.RateLimits.Enabled = true
|
||||
settings.TrustedProxy.UseLeftmostIP = true
|
||||
|
||||
if s.encryption {
|
||||
os.Setenv(app.EncryptionEnv(), encryptionKey)
|
||||
}
|
||||
|
||||
export, err := settings.DBExport(app)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var valueStr string
|
||||
|
||||
if s.encryption {
|
||||
decrypted, err := security.Decrypt(export["value"].(string), encryptionKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decrypt test value: %v", err)
|
||||
}
|
||||
|
||||
valueStr = string(decrypted)
|
||||
} else {
|
||||
valueStr = string(export["value"].([]byte))
|
||||
}
|
||||
|
||||
expected := `{"smtp":{"enabled":false,"port":0,"host":"smtp_host","username":"smtp_username","authMethod":"","tls":false,"localName":"","password":""},"backups":{"cron":"* * * * *","cronMaxKeep":0,"s3":{"enabled":true,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"s3_endpoint","accessKey":"","secret":"s3_secret","forcePathStyle":false},"meta":{"appName":"test_app_name","appURL":"","senderName":"","senderAddress":"","hideControls":false},"rateLimits":{"rules":[],"enabled":true},"trustedProxy":{"headers":[],"useLeftmostIP":true},"batch":{"enabled":false,"maxRequests":0,"timeout":15,"maxBodySize":0},"logs":{"maxDays":123,"minLevel":0,"logIP":false,"logAuthId":false}}`
|
||||
if valueStr != expected {
|
||||
t.Fatalf("Expected exported settings\n%s\ngot\n%s", expected, valueStr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingsMerge(t *testing.T) {
|
||||
s1 := &core.Settings{}
|
||||
s1.Meta.AppURL = "app_url" // should be unset
|
||||
|
||||
Reference in New Issue
Block a user