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
111 err := d.db.QueryRow(`
112 select domain, did, created, registered from registrations
113 where domain = ?
114 `, domain).Scan(®istration.Domain, ®istration.ByDid, &createdAt, ®isteredAt)
115
116 if err != nil {
117 if err == sql.ErrNoRows {
118 return nil, nil
119 } else {
120 return nil, err
121 }
122 }
123
124 createdAtTime := time.Unix(*createdAt, 0)
125 var registeredAtTime *time.Time
126 if registeredAt != nil {
127 x := time.Unix(*registeredAt, 0)
128 registeredAtTime = &x
129 }
130
131 registration.Created = &createdAtTime
132 registration.Registered = registeredAtTime
133
134 return ®istration, nil
135}
136
137func (d *DB) GenerateRegistrationKey(domain, did string) (string, error) {
138 // sanity check: does this domain already have a registration?
139 reg, err := d.RegistrationByDomain(domain)
140 if err != nil {
141 return "", err
142 }
143
144 // registration is open
145 if reg != nil {
146 switch reg.Status() {
147 case Registered:
148 // already registered by `owner`
149 return "", fmt.Errorf("%s already registered by %s", domain, reg.ByDid)
150 case Pending:
151 // TODO: be loud about this
152 log.Printf("%s registered by %s, status pending", domain, reg.ByDid)
153 }
154 }
155
156 secret := uuid.New().String()
157
158 _, err = d.db.Exec(`
159 insert into registrations (domain, did, secret)
160 values (?, ?, ?)
161 on conflict(domain) do update set did = excluded.did, secret = excluded.secret
162 `, domain, did, secret)
163
164 if err != nil {
165 return "", err
166 }
167
168 return secret, nil
169}
170
171func (d *DB) GetRegistrationKey(domain string) (string, error) {
172 res := d.db.QueryRow(`select secret from registrations where domain = ?`, domain)
173
174 var secret string
175 err := res.Scan(&secret)
176 if err != nil || secret == "" {
177 return "", err
178 }
179
180 log.Println("domain, secret: ", domain, secret)
181
182 return secret, nil
183}
184
185func (d *DB) Register(domain string) error {
186 _, err := d.db.Exec(`
187 update registrations
188 set registered = strftime('%s', 'now')
189 where domain = ?;
190 `, domain)
191
192 return err
193}