+23
appview/db/db.go
+23
appview/db/db.go
···
140
return nil
141
})
142
143
+
runMigration(db, "add-rkey-to-pubkeys", func(tx *sql.Tx) error {
144
+
// add unconstrained column
145
+
_, err := tx.Exec(`
146
+
alter table public_keys
147
+
add column rkey text;
148
+
`)
149
+
if err != nil {
150
+
return err
151
+
}
152
+
153
+
// backfill
154
+
_, err = tx.Exec(`
155
+
update public_keys
156
+
set rkey = ''
157
+
where rkey is null;
158
+
`)
159
+
if err != nil {
160
+
return err
161
+
}
162
+
163
+
return nil
164
+
})
165
+
166
return &DB{db}, nil
167
}
168
+15
-10
appview/db/pubkeys.go
+15
-10
appview/db/pubkeys.go
···
5
"time"
6
)
7
8
-
func AddPublicKey(e Execer, did, name, key string) error {
9
-
query := `insert or ignore into public_keys (did, name, key) values (?, ?, ?)`
10
-
_, err := e.Exec(query, did, name, key)
11
return err
12
}
13
14
-
func RemovePublicKey(e Execer, did string) error {
15
-
query := `delete from public_keys where did = ?`
16
-
_, err := e.Exec(query, did)
17
return err
18
}
19
···
21
Did string `json:"did"`
22
Key string `json:"key"`
23
Name string `json:"name"`
24
Created *time.Time
25
}
26
···
38
func GetAllPublicKeys(e Execer) ([]PublicKey, error) {
39
var keys []PublicKey
40
41
-
rows, err := e.Query(`select key, name, did, created from public_keys`)
42
if err != nil {
43
return nil, err
44
}
···
47
for rows.Next() {
48
var publicKey PublicKey
49
var createdAt string
50
-
if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.Did, &createdAt); err != nil {
51
return nil, err
52
}
53
createdAtTime, _ := time.Parse(time.RFC3339, createdAt)
···
65
func GetPublicKeys(e Execer, did string) ([]PublicKey, error) {
66
var keys []PublicKey
67
68
-
rows, err := e.Query(`select did, key, name, created from public_keys where did = ?`, did)
69
if err != nil {
70
return nil, err
71
}
···
74
for rows.Next() {
75
var publicKey PublicKey
76
var createdAt string
77
-
if err := rows.Scan(&publicKey.Did, &publicKey.Key, &publicKey.Name, &createdAt); err != nil {
78
return nil, err
79
}
80
createdAtTime, _ := time.Parse(time.RFC3339, createdAt)
···
5
"time"
6
)
7
8
+
func AddPublicKey(e Execer, did, name, key, rkey string) error {
9
+
_, err := e.Exec(
10
+
`insert or ignore into public_keys (did, name, key, rkey)
11
+
values (?, ?, ?, ?)`,
12
+
did, name, key, rkey)
13
return err
14
}
15
16
+
func RemovePublicKey(e Execer, did, name, key string) error {
17
+
_, err := e.Exec(`
18
+
delete from public_keys
19
+
where did = ? and name = ? and key = ?`,
20
+
did, name, key)
21
return err
22
}
23
···
25
Did string `json:"did"`
26
Key string `json:"key"`
27
Name string `json:"name"`
28
+
Rkey string `json:"rkey"`
29
Created *time.Time
30
}
31
···
43
func GetAllPublicKeys(e Execer) ([]PublicKey, error) {
44
var keys []PublicKey
45
46
+
rows, err := e.Query(`select key, name, did, rkey, created from public_keys`)
47
if err != nil {
48
return nil, err
49
}
···
52
for rows.Next() {
53
var publicKey PublicKey
54
var createdAt string
55
+
if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.Did, &publicKey.Rkey, &createdAt); err != nil {
56
return nil, err
57
}
58
createdAtTime, _ := time.Parse(time.RFC3339, createdAt)
···
70
func GetPublicKeys(e Execer, did string) ([]PublicKey, error) {
71
var keys []PublicKey
72
73
+
rows, err := e.Query(`select did, key, name, rkey, created from public_keys where did = ?`, did)
74
if err != nil {
75
return nil, err
76
}
···
79
for rows.Next() {
80
var publicKey PublicKey
81
var createdAt string
82
+
if err := rows.Scan(&publicKey.Did, &publicKey.Key, &publicKey.Name, &publicKey.Rkey, &createdAt); err != nil {
83
return nil, err
84
}
85
createdAtTime, _ := time.Parse(time.RFC3339, createdAt)
+2
-2
appview/pages/templates/repo/issues/issue.html
+2
-2
appview/pages/templates/repo/issues/issue.html
···
5
6
{{ define "repoContent" }}
7
<header>
8
-
<p class="text-2xl font-bold">
9
{{ .Issue.Title }}
10
<span class="text-gray-500">#{{ .Issue.IssueId }}</span>
11
</p>
···
18
{{ $icon = "circle-dot" }}
19
{{ end }}
20
21
-
<section>
22
<div class="inline-flex items-center gap-2">
23
<div id="state"
24
class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }} text-sm">
···
5
6
{{ define "repoContent" }}
7
<header>
8
+
<p class="text-2xl">
9
{{ .Issue.Title }}
10
<span class="text-gray-500">#{{ .Issue.IssueId }}</span>
11
</p>
···
18
{{ $icon = "circle-dot" }}
19
{{ end }}
20
21
+
<section class="mt-2">
22
<div class="inline-flex items-center gap-2">
23
<div id="state"
24
class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }} text-sm">
+15
-6
appview/pages/templates/settings.html
+15
-6
appview/pages/templates/settings.html
···
32
<section class="rounded bg-white drop-shadow-sm px-6 py-4 mb-6 w-full lg:w-fit">
33
<div id="key-list" class="flex flex-col gap-6 mb-8">
34
{{ range .PubKeys }}
35
-
<div>
36
-
<div class="inline-flex items-center gap-4">
37
-
<i class="w-3 h-3" data-lucide="key"></i>
38
-
<p class="font-bold">{{ .Name }} </p>
39
-
<p class="text-sm text-gray-500">added {{ .Created | timeFmt }}</p>
40
</div>
41
-
<code class="block text-sm break-all text-gray-500">{{ .Key }}</code>
42
</div>
43
{{ end }}
44
</div>
···
32
<section class="rounded bg-white drop-shadow-sm px-6 py-4 mb-6 w-full lg:w-fit">
33
<div id="key-list" class="flex flex-col gap-6 mb-8">
34
{{ range .PubKeys }}
35
+
<div class="flex justify-between items-center gap-4">
36
+
<div>
37
+
<div class="inline-flex items-center gap-4">
38
+
<i class="w-3 h-3" data-lucide="key"></i>
39
+
<p class="font-bold">{{ .Name }}</p>
40
+
<p class="text-sm text-gray-500">added {{ .Created | timeFmt }}</p>
41
+
</div>
42
+
<code class="block break-all text-sm break-all text-gray-500">{{ .Key }}</code>
43
</div>
44
+
<button
45
+
class="btn text-red-500 hover:text-red-700"
46
+
title="Delete key"
47
+
hx-delete="/settings/keys?name={{urlquery .Name}}&rkey={{urlquery .Rkey}}&key={{urlquery .Key}}"
48
+
hx-confirm="Are you sure you wish to delete the key '{{ .Name }}'?">
49
+
<i class="w-5 h-5" data-lucide="trash-2"></i>
50
+
</button>
51
</div>
52
{{ end }}
53
</div>
+60
-2
appview/state/settings.go
+60
-2
appview/state/settings.go
···
48
return
49
}
50
51
-
if err := db.AddPublicKey(s.db, did, name, key); err != nil {
52
log.Printf("adding public key: %s", err)
53
s.pages.Notice(w, "settings-keys", "Failed to add public key.")
54
return
···
58
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
59
Collection: tangled.PublicKeyNSID,
60
Repo: did,
61
-
Rkey: s.TID(),
62
Record: &lexutil.LexiconTypeDecoder{
63
Val: &tangled.PublicKey{
64
Created: time.Now().Format(time.RFC3339),
···
74
}
75
76
log.Println("created atproto record: ", resp.Uri)
77
s.pages.HxLocation(w, "/settings")
78
return
79
}
···
48
return
49
}
50
51
+
rkey := s.TID()
52
+
53
+
tx, err := s.db.Begin()
54
+
if err != nil {
55
+
log.Printf("failed to start tx; adding public key: %s", err)
56
+
s.pages.Notice(w, "settings-keys", "Unable to add public key at this moment, try again later.")
57
+
return
58
+
}
59
+
defer tx.Rollback()
60
+
61
+
if err := db.AddPublicKey(tx, did, name, key, rkey); err != nil {
62
log.Printf("adding public key: %s", err)
63
s.pages.Notice(w, "settings-keys", "Failed to add public key.")
64
return
···
68
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
69
Collection: tangled.PublicKeyNSID,
70
Repo: did,
71
+
Rkey: rkey,
72
Record: &lexutil.LexiconTypeDecoder{
73
Val: &tangled.PublicKey{
74
Created: time.Now().Format(time.RFC3339),
···
84
}
85
86
log.Println("created atproto record: ", resp.Uri)
87
+
88
+
err = tx.Commit()
89
+
if err != nil {
90
+
log.Printf("failed to commit tx; adding public key: %s", err)
91
+
s.pages.Notice(w, "settings-keys", "Unable to add public key at this moment, try again later.")
92
+
return
93
+
}
94
+
95
+
s.pages.HxLocation(w, "/settings")
96
+
return
97
+
98
+
case http.MethodDelete:
99
+
did := s.auth.GetDid(r)
100
+
q := r.URL.Query()
101
+
102
+
name := q.Get("name")
103
+
rkey := q.Get("rkey")
104
+
key := q.Get("key")
105
+
106
+
log.Println(name)
107
+
log.Println(rkey)
108
+
log.Println(key)
109
+
110
+
client, _ := s.auth.AuthorizedClient(r)
111
+
112
+
if err := db.RemovePublicKey(s.db, did, name, key); err != nil {
113
+
log.Printf("removing public key: %s", err)
114
+
s.pages.Notice(w, "settings-keys", "Failed to remove public key.")
115
+
return
116
+
}
117
+
118
+
if rkey != "" {
119
+
// remove from pds too
120
+
_, err := comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
121
+
Collection: tangled.PublicKeyNSID,
122
+
Repo: did,
123
+
Rkey: rkey,
124
+
})
125
+
126
+
// invalid record
127
+
if err != nil {
128
+
log.Printf("failed to delete record from PDS: %s", err)
129
+
s.pages.Notice(w, "settings-keys", "Failed to remove key from PDS.")
130
+
return
131
+
}
132
+
}
133
+
log.Println("deleted successfully")
134
+
135
s.pages.HxLocation(w, "/settings")
136
return
137
}
+1
appview/state/state.go
+1
appview/state/state.go