diff --git a/go.mod b/go.mod index 6c27e00..e39416e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( crawshaw.io/sqlite v0.3.2 github.com/matryer/is v1.4.0 + github.com/matthewhartstonge/argon2 v0.1.4 github.com/rickb777/date v1.14.0 gitlab.codemonkeysoftware.net/b/hatmill v0.0.6 ) diff --git a/go.sum b/go.sum index 0e9138c..510ede8 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,8 @@ github.com/leanovate/gopter v0.2.4 h1:U4YLBggDFhJdqQsG4Na2zX7joVTky9vHaj/AGEwSuX github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/matthewhartstonge/argon2 v0.1.4 h1:XalXB/BERpIZbOHV/31FYFFQxsl6GTrTq2N10rwfNGc= +github.com/matthewhartstonge/argon2 v0.1.4/go.mod h1:ZOSVMa24Ro9NpCjIobiwO49tymOSJ8ZaUmbcdrbrhYQ= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -36,6 +38,8 @@ github.com/rickb777/plural v1.2.1/go.mod h1:j058+3M5QQFgcZZ2oKIOekcygoZUL8gKW5yR gitlab.codemonkeysoftware.net/b/hatmill v0.0.6 h1:5Vs30ORHoujCYRvtbIwrusGBQgPzbKv011xKrTFa5ng= gitlab.codemonkeysoftware.net/b/hatmill v0.0.6/go.mod h1:T19ms3BmsEzy5YTS4icMO1oLC53xWhOP9MFeBv4NcFQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= diff --git a/internal/back/store.go b/internal/back/store.go index b5f9571..85e5284 100644 --- a/internal/back/store.go +++ b/internal/back/store.go @@ -9,6 +9,7 @@ import ( "crawshaw.io/sqlite" "crawshaw.io/sqlite/sqlitex" + "github.com/matthewhartstonge/argon2" "github.com/rickb777/date" ) @@ -23,6 +24,21 @@ func (u UnauthorizedError) Error() string { return fmt.Sprintf("unauthorized: EventID = %s, AdminCode = %s", u.EventID, u.AdminCode) } +func hash(password string) (string, error) { + hashed, err := (&argon2.Config{ + HashLength: 32, + // We don't need a salt because our random passwords are not + // susceptible to dictionary attacks. + SaltLength: 0, + TimeCost: 3, + MemoryCost: 64 * 1024, + Parallelism: 4, + Mode: argon2.ModeArgon2id, + Version: argon2.Version13, + }).HashEncoded([]byte(password)) + return string(hashed), err +} + type GenString func(length int) (string, error) type Store struct { @@ -82,7 +98,7 @@ func (s *Store) Close() error { const schema = ` CREATE TABLE event ( id TEXT NOT NULL PRIMARY KEY, - admin_code TEXT NOT NULL, + admin_code_hash TEXT NOT NULL, name TEXT NOT NULL, description TEXT NOT NULL, earliest_date DATE NOT NULL, @@ -157,12 +173,17 @@ func (s *Store) CreateEvent(ctx context.Context, cmd CreateEventCommand) (result return } + adminCodeHash, err := hash(adminCode) + if err != nil { + return + } + const query = ` - INSERT INTO event(id, admin_code, name, description, earliest_date, latest_date) + INSERT INTO event(id, admin_code_hash, name, description, earliest_date, latest_date) VALUES (?, ?, ?, ?, ?, ?);` err = sqlitex.Exec(conn, query, nil, id, - adminCode, + adminCodeHash, cmd.Name, cmd.Description, cmd.Earliest.Format(dbDateLayout), @@ -186,16 +207,21 @@ func (s *Store) AuthorizeEventAdmin(ctx context.Context, query CheckEventAdminCo conn := s.pool.Get(ctx) defer s.pool.Put(conn) + adminCodeHash, err := hash(query.AdminCode) + if err != nil { + return err + } + const dbQuery = ` SELECT 1 FROM event - WHERE id = ? AND admin_code = ?;` + WHERE id = ? AND admin_code_hash = ?;` var doesMatch bool - err := sqlitex.Exec(conn, dbQuery, + err = sqlitex.Exec(conn, dbQuery, func(stmt *sqlite.Stmt) error { doesMatch = true return nil - }, query.EventID, query.AdminCode) + }, query.EventID, adminCodeHash) if err != nil { return err }