From 9c84995f98c5b80719cfde7f77fa787a8005d18f Mon Sep 17 00:00:00 2001 From: sunba91-su Date: Tue, 9 Jun 2026 06:33:07 +0330 Subject: [PATCH] fix: strip wrapping quotes from password in .env file Docker Compose .env parser treats quotes as literal characters. When users wrap passwords with special chars in quotes like: ROCKETCHAT_BOT_PASSWORD='p@ss(w0rd)!' the actual value includes the quotes, causing auth failure. Added trimQuotes() that strips matching single/double quotes from password values. Applied to both ROCKETCHAT_BOT_PASSWORD and ROCKETCHAT_BOT_PASSWORD_FILE. Closes #37 --- .env.example | 4 +++- internal/config/config.go | 13 +++++++++++++ internal/config/config_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 internal/config/config_test.go diff --git a/.env.example b/.env.example index dc6957b..8b37d37 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,10 @@ ROCKETCHAT_SERVER_URL=https://chat.yourcompany.com ROCKETCHAT_BOT_USERNAME=geekbot +# Wrap password in single quotes if it contains special characters: +# ROCKETCHAT_BOT_PASSWORD='p@ss(w0rd)!' ROCKETCHAT_BOT_PASSWORD=your-password -# Alternative: read password from a file (avoids shell/env escaping issues) +# Alternative: read password from a file (avoids all escaping issues entirely) # ROCKETCHAT_BOT_PASSWORD_FILE=/run/secrets/bot_password ROCKETCHAT_MAIN_ADMIN=admin_username diff --git a/internal/config/config.go b/internal/config/config.go index 5ad9034..5023cef 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -13,8 +13,20 @@ type Config struct { MainAdmin string } +func trimQuotes(s string) string { + if len(s) < 2 { + return s + } + if (s[0] == '\'' && s[len(s)-1] == '\'') || + (s[0] == '"' && s[len(s)-1] == '"') { + return s[1 : len(s)-1] + } + return s +} + func Load() (*Config, error) { botPass := os.Getenv("ROCKETCHAT_BOT_PASSWORD") + botPass = trimQuotes(botPass) if botPass == "" { if path := os.Getenv("ROCKETCHAT_BOT_PASSWORD_FILE"); path != "" { b, err := os.ReadFile(path) @@ -22,6 +34,7 @@ func Load() (*Config, error) { return nil, fmt.Errorf("reading ROCKETCHAT_BOT_PASSWORD_FILE: %w", err) } botPass = strings.TrimSpace(string(b)) + botPass = trimQuotes(botPass) } } diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 0000000..3fa1699 --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,30 @@ +package config + +import ( + "testing" +) + +func TestTrimQuotes(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"'password'", "password"}, + {`"password"`, "password"}, + {`'p@ss(w0rd)!'`, "p@ss(w0rd)!"}, + {`"p@ss(w0rd)!"`, "p@ss(w0rd)!"}, + {"noquotes", "noquotes"}, + {"", ""}, + {"'", "'"}, + {`"`, `"`}, + {"''", ""}, + {`""`, ""}, + {"a", "a"}, + } + for _, tt := range tests { + got := trimQuotes(tt.input) + if got != tt.expected { + t.Errorf("trimQuotes(%q) = %q, want %q", tt.input, got, tt.expected) + } + } +}