this repo has no description
1package db
2
3import (
4 "database/sql"
5 "fmt"
6 "log"
7 "time"
8
9 "github.com/google/uuid"
10 _ "github.com/mattn/go-sqlite3"
11)
12
13type DB struct {
14 db *sql.DB
15}
16
17func Make(dbPath string) (*DB, error) {
18 db, err := sql.Open("sqlite3", dbPath)
19 if err != nil {
20 return nil, err
21 }
22 _, err = db.Exec(`
23 create table if not exists registrations (
24 id integer primary key autoincrement,
25 domain text not null unique,
26 did text not null,
27 secret text not null,
28 created timestamp default current_timestamp,
29 registered timestamp);
30 create table if not exists public_keys (
31 id integer primary key autoincrement,
32 did text not null,
33 name text not null,
34 key text not null,
35 created timestamp default current_timestamp,
36 unique(did, name, key)
37 );
38 `)
39 if err != nil {
40 return nil, err
41 }
42 return &DB{db: db}, nil
43}
44
45type Registration struct {
46 Domain string
47 ByDid string
48 Created *time.Time
49 Registered *time.Time
50}
51
52func (r *Registration) Status() Status {
53 if r.Registered != nil {
54 return Registered
55 } else {
56 return Pending
57 }
58}
59
60type Status uint32
61
62const (
63 Registered Status = iota
64 Pending
65)
66
67// returns registered status, did of owner, error
68func (d *DB) RegistrationsByDid(did string) ([]Registration, error) {
69 var registrations []Registration
70
71 rows, err := d.db.Query(`
72 select domain, did, created, registered from registrations
73 where did = ?
74 `, did)
75 if err != nil {
76 return nil, err
77 }
78
79 for rows.Next() {
80 var createdAt *int64
81 var registeredAt *int64
82 var registration Registration
83 err = rows.Scan(®istration.Domain, ®istration.ByDid, &createdAt, ®isteredAt)
84
85 if err != nil {
86 log.Println(err)
87 } else {
88 createdAtTime := time.Unix(*createdAt, 0)
89
90 var registeredAtTime *time.Time
91 if registeredAt != nil {
92 x := time.Unix(*registeredAt, 0)
93 registeredAtTime = &x
94 }
95
96 registration.Created = &createdAtTime
97 registration.Registered = registeredAtTime
98 registrations = append(registrations, registration)
99 }
100 }
101
102 return registrations, nil
103}
104
105// returns registered status, did of owner, error
106func (d *DB) RegistrationByDomain(domain string) (*Registration, error) {
107 var createdAt *int64
108 var registeredAt *int64
109 var registration Registration
110 err := d.db.QueryRow(`
111 select domain, did, created, registered from registrations
112 where domain = ?
113 `, domain).Scan(®istration.Domain, ®istration.ByDid, &createdAt, ®isteredAt)
114
115 createdAtTime := time.Unix(*createdAt, 0)
116 var registeredAtTime *time.Time
117 if registeredAt != nil {
118 x := time.Unix(*registeredAt, 0)
119 registeredAtTime = &x
120 }
121
122 registration.Created = &createdAtTime
123 registration.Registered = registeredAtTime
124
125 if err != nil {
126 if err == sql.ErrNoRows {
127 return nil, nil
128 } else {
129 return nil, err
130 }
131 }
132
133 return ®istration, nil
134}
135
136func (d *DB) GenerateRegistrationKey(domain, did string) (string, error) {
137 // sanity check: does this domain already have a registration?
138 reg, err := d.RegistrationByDomain(domain)
139 if err != nil {
140 return "", err
141 }
142
143 // registration is open
144 if reg != nil {
145 switch reg.Status() {
146 case Registered:
147 // already registered by `owner`
148 return "", fmt.Errorf("%s already registered by %s", domain, reg.ByDid)
149 case Pending:
150 // TODO: be loud about this
151 log.Printf("%s registered by %s, status pending", domain, reg.ByDid)
152 }
153 }
154
155 secret := uuid.New().String()
156
157 _, err = d.db.Exec(`
158 insert into registrations (domain, did, secret)
159 values (?, ?, ?)
160 on conflict(domain) do update set did = excluded.did, secret = excluded.secret
161 `, domain, did, secret)
162
163 if err != nil {
164 return "", err
165 }
166
167 return secret, nil
168}
169
170func (d *DB) GetRegistrationKey(domain string) (string, error) {
171 res := d.db.QueryRow(`select secret from registrations where domain = ?`, domain)
172
173 var secret string
174 err := res.Scan(&secret)
175 if err != nil || secret == "" {
176 return "", err
177 }
178
179 log.Println("domain, secret: ", domain, secret)
180
181 return secret, nil
182}
183
184func (d *DB) Register(domain string) error {
185 _, err := d.db.Exec(`
186 update registrations
187 set registered = strftime('%s', 'now')
188 where domain = ?;
189 `, domain)
190
191 if err != nil {
192 return err
193 }
194
195 return nil
196}