forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
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 Id int64
14 Domain string
15 ByDid string
16 Created *time.Time
17 Registered *time.Time
18}
19
20func (r *Registration) Status() Status {
21 if r.Registered != nil {
22 return Registered
23 } else {
24 return Pending
25 }
26}
27
28type Status uint32
29
30const (
31 Registered Status = iota
32 Pending
33)
34
35// returns registered status, did of owner, error
36func RegistrationsByDid(e Execer, did string) ([]Registration, error) {
37 var registrations []Registration
38
39 rows, err := e.Query(`
40 select id, domain, did, created, registered from registrations
41 where did = ?
42 `, did)
43 if err != nil {
44 return nil, err
45 }
46
47 for rows.Next() {
48 var createdAt *string
49 var registeredAt *string
50 var registration Registration
51 err = rows.Scan(®istration.Id, ®istration.Domain, ®istration.ByDid, &createdAt, ®isteredAt)
52
53 if err != nil {
54 log.Println(err)
55 } else {
56 createdAtTime, _ := time.Parse(time.RFC3339, *createdAt)
57 var registeredAtTime *time.Time
58 if registeredAt != nil {
59 x, _ := time.Parse(time.RFC3339, *registeredAt)
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 RegistrationByDomain(e Execer, domain string) (*Registration, error) {
74 var createdAt *string
75 var registeredAt *string
76 var registration Registration
77
78 err := e.QueryRow(`
79 select id, domain, did, created, registered from registrations
80 where domain = ?
81 `, domain).Scan(®istration.Id, ®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.Parse(time.RFC3339, *createdAt)
92 var registeredAtTime *time.Time
93 if registeredAt != nil {
94 x, _ := time.Parse(time.RFC3339, *registeredAt)
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 GenerateRegistrationKey(e Execer, domain, did string) (string, error) {
111 // sanity check: does this domain already have a registration?
112 reg, err := RegistrationByDomain(e, 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 = e.Exec(`
132 insert into registrations (domain, did, secret)
133 values (?, ?, ?)
134 on conflict(domain) do update set did = excluded.did, secret = excluded.secret, created = excluded.created
135 `, domain, did, secret)
136
137 if err != nil {
138 return "", err
139 }
140
141 return secret, nil
142}
143
144func GetRegistrationKey(e Execer, domain string) (string, error) {
145 res := e.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 GetCompletedRegistrations(e Execer) ([]string, error) {
157 rows, err := e.Query(`select domain from registrations where registered not null`)
158 if err != nil {
159 return nil, err
160 }
161
162 var domains []string
163 for rows.Next() {
164 var domain string
165 err = rows.Scan(&domain)
166
167 if err != nil {
168 log.Println(err)
169 } else {
170 domains = append(domains, domain)
171 }
172 }
173
174 if err = rows.Err(); err != nil {
175 return nil, err
176 }
177
178 return domains, nil
179}
180
181func Register(e Execer, domain string) error {
182 _, err := e.Exec(`
183 update registrations
184 set registered = strftime('%Y-%m-%dT%H:%M:%SZ', 'now')
185 where domain = ?;
186 `, domain)
187
188 return err
189}