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