Blame


1 5e70998a 2022-04-12 o package mailmux
2 5e70998a 2022-04-12 o
3 5e70998a 2022-04-12 o import (
4 5e70998a 2022-04-12 o "database/sql"
5 5e70998a 2022-04-12 o "errors"
6 5e70998a 2022-04-12 o "fmt"
7 5e70998a 2022-04-12 o
8 5e70998a 2022-04-12 o _ "github.com/mattn/go-sqlite3"
9 5e70998a 2022-04-12 o )
10 5e70998a 2022-04-12 o
11 5e70998a 2022-04-12 o // UserDB is an implementation of UserStore backed by a SQLite3 database.
12 5e70998a 2022-04-12 o // Users are fully authenticated after confirming ownership of their
13 5e70998a 2022-04-12 o // email address by supplying a matching ticket to a generated ticket file.
14 5e70998a 2022-04-12 o type UserDB struct {
15 5e70998a 2022-04-12 o *sql.DB
16 5e70998a 2022-04-12 o TicketDir string
17 5e70998a 2022-04-12 o }
18 5e70998a 2022-04-12 o
19 5e70998a 2022-04-12 o // OpenUserDB opens the named user database file and ticket directory.
20 5e70998a 2022-04-12 o func OpenUserDB(name, dir string) (*UserDB, error) {
21 5e70998a 2022-04-12 o db, err := sql.Open("sqlite3", name)
22 5e70998a 2022-04-12 o if err != nil {
23 5e70998a 2022-04-12 o return nil, err
24 5e70998a 2022-04-12 o }
25 5e70998a 2022-04-12 o return &UserDB{db, dir}, db.Ping()
26 5e70998a 2022-04-12 o }
27 5e70998a 2022-04-12 o
28 5e70998a 2022-04-12 o func (db *UserDB) Lookup(name string) (User, error) {
29 5e70998a 2022-04-12 o var u User
30 5e70998a 2022-04-12 o row := db.QueryRow("SELECT username, password FROM users WHERE username = ?", name)
31 5e70998a 2022-04-12 o if err := row.Scan(&u.name, &u.password); err != nil {
32 5e70998a 2022-04-12 o if errors.Is(err, sql.ErrNoRows) {
33 5e70998a 2022-04-12 o return User{}, fmt.Errorf("lookup %s: %w", name, ErrUnknownUser)
34 5e70998a 2022-04-12 o }
35 5e70998a 2022-04-12 o return User{}, fmt.Errorf("lookup %s: %w", name, err)
36 5e70998a 2022-04-12 o }
37 5e70998a 2022-04-12 o return u, nil
38 5e70998a 2022-04-12 o }
39 5e70998a 2022-04-12 o
40 5e70998a 2022-04-12 o func (db *UserDB) add(username string, pw Password) error {
41 5e70998a 2022-04-12 o _, err := db.Exec("INSERT INTO users (username, password) VALUES (?, ?)", username, pw)
42 5e70998a 2022-04-12 o if err != nil {
43 5e70998a 2022-04-12 o return fmt.Errorf("add %s: %w", username, err)
44 5e70998a 2022-04-12 o }
45 5e70998a 2022-04-12 o if err := createTicket(db.TicketDir, username, pw); err != nil {
46 5e70998a 2022-04-12 o return fmt.Errorf("add %s: create ticket: %w", username, err)
47 5e70998a 2022-04-12 o }
48 5e70998a 2022-04-12 o return nil
49 5e70998a 2022-04-12 o }
50 5e70998a 2022-04-12 o
51 5e70998a 2022-04-12 o func (db *UserDB) Change(name string, new Password) error {
52 5e70998a 2022-04-12 o _, err := db.Lookup(name)
53 5e70998a 2022-04-12 o if errors.Is(err, ErrUnknownUser) {
54 5e70998a 2022-04-12 o return db.add(name, new)
55 5e70998a 2022-04-12 o }
56 5e70998a 2022-04-12 o if err != nil {
57 5e70998a 2022-04-12 o return fmt.Errorf("change %s: %w", name, err)
58 5e70998a 2022-04-12 o }
59 5e70998a 2022-04-12 o
60 5e70998a 2022-04-12 o _, err = db.Exec("UPDATE users SET password = ? WHERE username = ?", new, name)
61 5e70998a 2022-04-12 o if err != nil {
62 5e70998a 2022-04-12 o return fmt.Errorf("change %s: %w", name, err)
63 5e70998a 2022-04-12 o }
64 5e70998a 2022-04-12 o return nil
65 5e70998a 2022-04-12 o }
66 5e70998a 2022-04-12 o
67 5e70998a 2022-04-12 o func (db *UserDB) Delete(name string) error {
68 5e70998a 2022-04-12 o _, err := db.Lookup(name)
69 5e70998a 2022-04-12 o if err != nil {
70 5e70998a 2022-04-12 o return fmt.Errorf("delete %s: %w", name, err)
71 5e70998a 2022-04-12 o }
72 5e70998a 2022-04-12 o _, err = db.Exec("DELETE FROM users WHERE username = ?", name)
73 5e70998a 2022-04-12 o if err != nil {
74 5e70998a 2022-04-12 o return fmt.Errorf("delete %s: %w", name, err)
75 5e70998a 2022-04-12 o }
76 5e70998a 2022-04-12 o return nil
77 5e70998a 2022-04-12 o }