163 lines
3.5 kB
1
package db
2
3
import (
4
"crypto/rand"
5
"database/sql"
6
"encoding/hex"
7
"fmt"
8
"log"
9
"time"
10
)
11
12
type Registration struct {
13
Domain string
14
ByDid string
15
Created *time.Time
16
Registered *time.Time
17
}
18
19
func (r *Registration) Status() Status {
20
if r.Registered != nil {
21
return Registered
22
} else {
23
return Pending
24
}
25
}
26
27
type Status uint32
28
29
const (
30
Registered Status = iota
31
Pending
32
)
33
34
// returns registered status, did of owner, error
35
func (d *DB) RegistrationsByDid(did string) ([]Registration, error) {
36
var registrations []Registration
37
38
rows, err := d.db.Query(`
39
select domain, did, created, registered from registrations
40
where did = ?
41
`, did)
42
if err != nil {
43
return nil, err
44
}
45
46
for rows.Next() {
47
var createdAt *string
48
var registeredAt *string
49
var registration Registration
50
err = rows.Scan(®istration.Domain, ®istration.ByDid, &createdAt, ®isteredAt)
51
52
if err != nil {
53
log.Println(err)
54
} else {
55
createdAtTime, _ := time.Parse(time.RFC3339, *createdAt)
56
var registeredAtTime *time.Time
57
if registeredAt != nil {
58
x, _ := time.Parse(time.RFC3339, *registeredAt)
59
registeredAtTime = &x
60
}
61
62
registration.Created = &createdAtTime
63
registration.Registered = registeredAtTime
64
registrations = append(registrations, registration)
65
}
66
}
67
68
return registrations, nil
69
}
70
71
// returns registered status, did of owner, error
72
func (d *DB) RegistrationByDomain(domain string) (*Registration, error) {
73
var createdAt *string
74
var registeredAt *string
75
var registration Registration
76
77
err := d.db.QueryRow(`
78
select domain, did, created, registered from registrations
79
where domain = ?
80
`, domain).Scan(®istration.Domain, ®istration.ByDid, &createdAt, ®isteredAt)
81
82
if err != nil {
83
if err == sql.ErrNoRows {
84
return nil, nil
85
} else {
86
return nil, err
87
}
88
}
89
90
createdAtTime, _ := time.Parse(time.RFC3339, *createdAt)
91
var registeredAtTime *time.Time
92
if registeredAt != nil {
93
x, _ := time.Parse(time.RFC3339, *registeredAt)
94
registeredAtTime = &x
95
}
96
97
registration.Created = &createdAtTime
98
registration.Registered = registeredAtTime
99
100
return ®istration, nil
101
}
102
103
func genSecret() string {
104
key := make([]byte, 32)
105
rand.Read(key)
106
return hex.EncodeToString(key)
107
}
108
109
func (d *DB) GenerateRegistrationKey(domain, did string) (string, error) {
110
// sanity check: does this domain already have a registration?
111
reg, err := d.RegistrationByDomain(domain)
112
if err != nil {
113
return "", err
114
}
115
116
// registration is open
117
if reg != nil {
118
switch reg.Status() {
119
case Registered:
120
// already registered by `owner`
121
return "", fmt.Errorf("%s already registered by %s", domain, reg.ByDid)
122
case Pending:
123
// TODO: be loud about this
124
log.Printf("%s registered by %s, status pending", domain, reg.ByDid)
125
}
126
}
127
128
secret := genSecret()
129
130
_, err = d.db.Exec(`
131
insert into registrations (domain, did, secret)
132
values (?, ?, ?)
133
on conflict(domain) do update set did = excluded.did, secret = excluded.secret
134
`, domain, did, secret)
135
136
if err != nil {
137
return "", err
138
}
139
140
return secret, nil
141
}
142
143
func (d *DB) GetRegistrationKey(domain string) (string, error) {
144
res := d.db.QueryRow(`select secret from registrations where domain = ?`, domain)
145
146
var secret string
147
err := res.Scan(&secret)
148
if err != nil || secret == "" {
149
return "", err
150
}
151
152
return secret, nil
153
}
154
155
func (d *DB) Register(domain string) error {
156
_, err := d.db.Exec(`
157
update registrations
158
set registered = strftime('%Y-%m-%dT%H:%M:%SZ', 'now')
159
where domain = ?;
160
`, domain)
161
162
return err
163
}
164