fix(config): Datenbank-Passwort mit Sonderzeichen bricht den Start
Die Verbindungszeichenkette wurde mit fmt.Sprintf zusammengeklebt. Ein Passwort mit % und @ ergab eine kaputte URL: parse "postgres://aether:8UoNj%CoWJ7ze@qy@localhost:5432/aether": invalid URL escape "%Co" Der Server kam nicht über die Migrationen hinaus. Die key=value-Form hätte dasselbe Problem mit einem Leerzeichen gehabt, nur stiller. config.DSN() liefert jetzt eine postgres://-URL, gebaut mit net/url und net.JoinHostPort (klammert IPv6). pgxpool und golang-migrate nehmen sie beide unverändert – dsnToURL, splitDSN, indexByte und orDefault in pkg/db sind ersatzlos entfallen. Test deckt %, @, :, /, Leerzeichen und IPv6 ab. Dazu: DB_HOST und DB_PORT fehlten in der schlanken .env.example, weshalb localhost statt postgres gegriffen hat. APP_ENV ergänzt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
16ab6f385b
commit
35ebf609b7
5 files changed
+153
-71
No files matched your search
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -218,11 +219,37 @@ func Load() (*Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// DSN liefert eine `postgres://`-URL – nicht die `key=value`-Form.
|
||||
//
|
||||
// Vorher wurde hier mit fmt.Sprintf zusammengeklebt, und beide Formate haben
|
||||
// Sonderzeichen, die dabei kaputtgehen:
|
||||
//
|
||||
// - In der URL-Form beenden `@` und `:` den Anmeldeteil, und `%` leitet eine
|
||||
// Maskierung ein. Ein Passwort wie `8UoNj%CoWJ7ze@qy` ergab
|
||||
// `postgres://aether:8UoNj%CoWJ7ze@qy@localhost:5432/...` und damit
|
||||
// „invalid URL escape %Co". Der Server kam nicht über die Migrationen
|
||||
// hinaus – gemessen bei der ersten Einrichtung.
|
||||
// - In der key=value-Form trennt das Leerzeichen die Paare. Ein Passwort mit
|
||||
// Leerzeichen wäre dort genauso kaputtgegangen, nur stiller: Der Rest
|
||||
// hinter dem Leerzeichen wäre als eigener Schlüssel gelesen worden.
|
||||
//
|
||||
// Beides erledigt jetzt die Standardbibliothek. `url.UserPassword` maskiert,
|
||||
// was maskiert werden muss, und `net.JoinHostPort` klammert eine IPv6-Adresse.
|
||||
// pgxpool und golang-migrate nehmen beide diese URL unverändert an – die
|
||||
// Umrechnung von Hand in pkg/db ist damit ersatzlos weggefallen.
|
||||
//
|
||||
// Ein Passwort darf danach jedes Zeichen enthalten. Das ist keine
|
||||
// Bequemlichkeit: Wer erst herausfinden muss, welche Zeichen erlaubt sind,
|
||||
// wählt am Ende ein schwächeres.
|
||||
func (c *Config) DSN() string {
|
||||
return fmt.Sprintf(
|
||||
"host=%s port=%s dbname=%s user=%s password=%s sslmode=disable",
|
||||
c.DBHost, c.DBPort, c.DBName, c.DBUser, c.DBPassword,
|
||||
)
|
||||
u := url.URL{
|
||||
Scheme: "postgres",
|
||||
User: url.UserPassword(c.DBUser, c.DBPassword),
|
||||
Host: net.JoinHostPort(c.DBHost, c.DBPort),
|
||||
Path: "/" + c.DBName,
|
||||
RawQuery: "sslmode=disable",
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (c *Config) IsDev() bool {
|
||||
|
||||
Reference in new issue
Block a user