diff --git a/server/internal/auth/crypt/crypt.go b/server/internal/auth/crypt/crypt.go index dcfd6ff0..74a3e0a2 100644 --- a/server/internal/auth/crypt/crypt.go +++ b/server/internal/auth/crypt/crypt.go @@ -10,23 +10,12 @@ import ( "github.com/jackc/pgx/v5" ) -type Auth interface { - SupportsPasswordUpdate() bool - UpdateUserPassword(db db.Handler, email, password string) error - VerifyUserPassword(db db.Handler, email, password string) (bool, error) +type Crypt struct { + generator PasswordHasher } -type auth struct { - cfg Config - generator interface { - GenerateEncodedHash(password string) (string, error) - } -} - -func New(cfg Config) (Auth, error) { - var generator interface { - GenerateEncodedHash(password string) (string, error) - } +func New(cfg Config) (*Crypt, error) { + var generator PasswordHasher if cfg.Hash == "argon2" { generator = argon2.New(cfg.Argon2) } else if cfg.Hash == "pbkdf2" { @@ -39,17 +28,16 @@ func New(cfg Config) (Auth, error) { return nil, errors.New("unrecognized hashing algorithm: " + cfg.Hash) } - return &auth{ - cfg: cfg, + return &Crypt{ generator: generator, }, nil } -func (a *auth) SupportsPasswordUpdate() bool { +func (a *Crypt) SupportsPasswordUpdate() bool { return true } -func (a *auth) UpdateUserPassword(db db.Handler, email, password string) error { +func (a *Crypt) UpdateUserPassword(db db.Handler, email, password string) error { const q = "UPDATE users SET password_hash = $2::TEXT, modified = NOW() WHERE email = $1::TEXT" if hash, err := a.generator.GenerateEncodedHash(password); err != nil { return err @@ -61,7 +49,7 @@ func (a *auth) UpdateUserPassword(db db.Handler, email, password string) error { return nil } -func (a *auth) VerifyUserPassword(db db.Handler, email, password string) (bool, error) { +func (a *Crypt) VerifyUserPassword(db db.Handler, email, password string) (bool, error) { const q = "SELECT password_hash FROM users WHERE email = $1::TEXT" row := db.QueryRow(q, strings.ToLower(email)) var encodedHash string diff --git a/server/internal/auth/crypt/password_hasher.go b/server/internal/auth/crypt/password_hasher.go new file mode 100644 index 00000000..07833732 --- /dev/null +++ b/server/internal/auth/crypt/password_hasher.go @@ -0,0 +1,26 @@ +package crypt + +import ( + "errors" + + "codeberg.org/shroff/phylum/server/internal/auth/crypt/argon2" + "codeberg.org/shroff/phylum/server/internal/auth/crypt/pbkdf2" +) + +type PasswordHasher interface { + GenerateEncodedHash(password string) (string, error) +} + +func NewPasswordHasher(cfg Config) (PasswordHasher, error) { + if cfg.Hash == "argon2" { + return argon2.New(cfg.Argon2), nil + } else if cfg.Hash == "pbkdf2" { + generator, err := pbkdf2.New(cfg.PBKDF2) + if err != nil { + return nil, errors.New("failed to create PBKDF2 hash generator: " + err.Error()) + } + return generator, nil + } else { + return nil, errors.New("unrecognized hashing algorithm: " + cfg.Hash) + } +} diff --git a/server/internal/command/config.defaults.yml b/server/internal/command/config.defaults.yml index 1f7d1943..4b42654b 100644 --- a/server/internal/command/config.defaults.yml +++ b/server/internal/command/config.defaults.yml @@ -15,6 +15,15 @@ core: user: # Config for new users basedir: /home permission: 0x10 # Invite users + publinks: + password: + # hash is either argon2 or pbkdf2 + hash: pbkdf2 + pbkdf2: + function: sha-256 + iterations: 100000 + salt: 32 + key: 32 auth: auto_create: @@ -25,7 +34,7 @@ auth: # backend is one of crypt, ldap, or none backend: crypt crypt: - # hash is one of argon2, or pbkdf2 + # hash is either argon2 or pbkdf2 hash: argon2 argon2: memory: 18 diff --git a/server/internal/core/config.go b/server/internal/core/config.go index 92b04ef9..221ecfa5 100644 --- a/server/internal/core/config.go +++ b/server/internal/core/config.go @@ -1,7 +1,14 @@ package core +import "codeberg.org/shroff/phylum/server/internal/auth/crypt" + type Config struct { - User UserConfig `koanf:"user"` + User UserConfig `koanf:"users"` + Publinks PublinksConfig `koanf:"publinks"` +} + +type PublinksConfig struct { + Password crypt.Config `koanf:"password"` } type UserConfig struct { diff --git a/server/internal/core/core.go b/server/internal/core/core.go index fe6b659e..c4acc877 100644 --- a/server/internal/core/core.go +++ b/server/internal/core/core.go @@ -3,6 +3,7 @@ package core import ( "errors" + "codeberg.org/shroff/phylum/server/internal/auth/crypt" "codeberg.org/shroff/phylum/server/internal/db" "github.com/doug-martin/goqu/v9" _ "github.com/doug-martin/goqu/v9/dialect/postgres" @@ -13,6 +14,7 @@ import ( var pg *goqu.Database var userConfig UserConfig +var publinksPasswordHasher crypt.PasswordHasher var fsPathRoot pgtype.UUID func Initialize(db db.Handler, cfg Config) error { @@ -25,6 +27,11 @@ func Initialize(db db.Handler, cfg Config) error { fsPathRoot = pgtype.UUID{Bytes: rootID, Valid: true} } userConfig = cfg.User + if c, err := crypt.NewPasswordHasher(cfg.Publinks.Password); err != nil { + return err + } else { + publinksPasswordHasher = c + } return nil } diff --git a/server/internal/core/resource_publink.go b/server/internal/core/resource_publink.go index 41910c96..91deaeff 100644 --- a/server/internal/core/resource_publink.go +++ b/server/internal/core/resource_publink.go @@ -1,9 +1,9 @@ package core import ( + "errors" "strings" - "codeberg.org/shroff/phylum/server/internal/auth/crypt" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" ) @@ -25,11 +25,11 @@ func (f txFileSystem) CreatePublink(r Resource, id, password string, expires pgt passwordHash := "" if password != "" { - hash, err := crypt.Generate(password) + var err error + passwordHash, err = publinksPasswordHasher.GenerateEncodedHash(password) if err != nil { - return err + return errors.New("failed to hash password: " + err.Error()) } - passwordHash = hash } const q = `INSERT INTO publinks(id, root, password_hash, expires, access_limit) VALUES