+30
-2
appview/auth/auth.go
+30
-2
appview/auth/auth.go
···
179
179
}
180
180
181
181
func (a *Auth) GetDID(r *http.Request) string {
182
-
clientSession, _ := a.Store.Get(r, appview.SessionName)
182
+
clientSession, err := a.Store.Get(r, appview.SessionName)
183
+
if err != nil || clientSession.IsNew {
184
+
return ""
185
+
}
186
+
183
187
return clientSession.Values[appview.SessionDid].(string)
184
188
}
185
189
186
190
func (a *Auth) GetHandle(r *http.Request) string {
187
-
clientSession, _ := a.Store.Get(r, appview.SessionHandle)
191
+
clientSession, err := a.Store.Get(r, appview.SessionName)
192
+
if err != nil || clientSession.IsNew {
193
+
return ""
194
+
}
195
+
188
196
return clientSession.Values[appview.SessionHandle].(string)
189
197
}
198
+
199
+
type User struct {
200
+
Handle string
201
+
Did string
202
+
Pds string
203
+
}
204
+
205
+
func (a *Auth) GetUser(r *http.Request) *User {
206
+
clientSession, err := a.Store.Get(r, appview.SessionName)
207
+
208
+
if err != nil || clientSession.IsNew {
209
+
return nil
210
+
}
211
+
212
+
return &User{
213
+
Handle: clientSession.Values[appview.SessionHandle].(string),
214
+
Did: clientSession.Values[appview.SessionDid].(string),
215
+
Pds: clientSession.Values[appview.SessionPds].(string),
216
+
}
217
+
}
+20
appview/pages/layout.html
+20
appview/pages/layout.html
···
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="UTF-8">
5
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+
<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
7
+
<title>{{block "title" .}}tangled{{end}}</title>
8
+
</head>
9
+
<body>
10
+
11
+
<div class="navbar">
12
+
<a href="/" style="color: white; text-decoration: none;">Home</a>
13
+
</div>
14
+
15
+
<div class="content">
16
+
{{block "content" .}}{{end}}
17
+
</div>
18
+
19
+
</body>
20
+
</html>
+14
appview/pages/login.html
+14
appview/pages/login.html
···
1
+
{{define "title"}}login{{end}}
2
+
3
+
{{define "content"}}
4
+
<h1>Login</h1>
5
+
<form method="POST" action="/login">
6
+
<label for="handle">handle</label>
7
+
<input type="text" id="handle" name="handle" required>
8
+
9
+
<label for="app_password">app password</label>
10
+
<input type="password" id="app_password" name="app_password" required>
11
+
12
+
<button type="submit">login</button>
13
+
</form>
14
+
{{end}}
+59
appview/pages/pages.go
+59
appview/pages/pages.go
···
1
+
package pages
2
+
3
+
import (
4
+
"embed"
5
+
"html/template"
6
+
"io"
7
+
"sync"
8
+
9
+
"github.com/sotangled/tangled/appview/auth"
10
+
"github.com/sotangled/tangled/appview/db"
11
+
)
12
+
13
+
//go:embed *.html
14
+
var files embed.FS
15
+
16
+
var (
17
+
cache = make(map[string]*template.Template)
18
+
mutex sync.Mutex
19
+
)
20
+
21
+
func parse(file string) *template.Template {
22
+
mutex.Lock()
23
+
defer mutex.Unlock()
24
+
25
+
if tmpl, found := cache[file]; found {
26
+
return tmpl
27
+
}
28
+
29
+
tmpl := template.Must(
30
+
template.New("layout.html").ParseFS(files, "layout.html", file),
31
+
)
32
+
33
+
cache[file] = tmpl
34
+
return tmpl
35
+
}
36
+
37
+
type LoginParams struct {
38
+
}
39
+
40
+
func Login(w io.Writer, p LoginParams) error {
41
+
return parse("login.html").Execute(w, p)
42
+
}
43
+
44
+
type TimelineParams struct {
45
+
User *auth.User
46
+
}
47
+
48
+
func Timeline(w io.Writer, p TimelineParams) error {
49
+
return parse("timeline.html").Execute(w, p)
50
+
}
51
+
52
+
type SettingsParams struct {
53
+
User *auth.User
54
+
PubKeys []db.PublicKey
55
+
}
56
+
57
+
func Settings(w io.Writer, p SettingsParams) error {
58
+
return parse("settings.html").Execute(w, p)
59
+
}
+34
appview/pages/settings.html
+34
appview/pages/settings.html
···
1
+
{{define "title"}}settings{{end}}
2
+
3
+
{{define "content"}}
4
+
<a href="/">back to timeline</a>
5
+
<h1>settings</h1>
6
+
7
+
<h2>profile</h2>
8
+
<p><strong>handle:</strong> {{.User.Handle}}</p>
9
+
<p><strong>did:</strong> {{.User.Did}}</p>
10
+
<p><strong>pds:</strong> {{.User.Pds}}</p>
11
+
12
+
<h2>ssh keys</h2>
13
+
<form hx-put="/settings/keys">
14
+
<label for="name">key name:</label>
15
+
<input type="text" id="name" name="name" required>
16
+
17
+
<label for="key">pub key:</label>
18
+
<textarea id="key" name="key" placeholder="ssh-rsa AAAAAA..." required></textarea>
19
+
20
+
<button type="submit">add key</button>
21
+
</form>
22
+
23
+
<h3>existing keys</h3>
24
+
<ul id="key-list">
25
+
{{range .PubKeys}}
26
+
<li>
27
+
<strong>{{.Name}}</strong><br>
28
+
<code>{{.Key}}</code>
29
+
</li>
30
+
{{else}}
31
+
<p>no ssh keys added yet</p>
32
+
{{end}}
33
+
</ul>
34
+
{{end}}
+10
appview/pages/timeline.html
+10
appview/pages/timeline.html
+33
-3
appview/state/state.go
+33
-3
appview/state/state.go
···
18
18
"github.com/sotangled/tangled/appview"
19
19
"github.com/sotangled/tangled/appview/auth"
20
20
"github.com/sotangled/tangled/appview/db"
21
+
"github.com/sotangled/tangled/appview/pages"
21
22
)
22
23
23
24
type State struct {
···
50
51
51
52
switch r.Method {
52
53
case http.MethodGet:
53
-
log.Println("unimplemented")
54
+
pages.Login(w, pages.LoginParams{})
54
55
return
55
56
case http.MethodPost:
56
57
handle := r.FormValue("handle")
···
84
85
}
85
86
}
86
87
88
+
func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
89
+
user := s.auth.GetUser(r)
90
+
fmt.Printf("%+v\n", user)
91
+
pages.Timeline(w, pages.TimelineParams{
92
+
User: user,
93
+
})
94
+
return
95
+
}
96
+
87
97
// requires auth
88
98
func (s *State) RegistrationKey(w http.ResponseWriter, r *http.Request) {
89
99
switch r.Method {
···
118
128
119
129
w.Write([]byte(key))
120
130
}
131
+
}
132
+
133
+
func (s *State) Settings(w http.ResponseWriter, r *http.Request) {
134
+
// for now, this is just pubkeys
135
+
user := s.auth.GetUser(r)
136
+
pubKeys, err := s.db.GetPublicKeys(user.Did)
137
+
if err != nil {
138
+
log.Println(err)
139
+
}
140
+
141
+
pages.Settings(w, pages.SettingsParams{
142
+
User: user,
143
+
PubKeys: pubKeys,
144
+
})
145
+
return
146
+
121
147
}
122
148
123
149
func (s *State) Keys(w http.ResponseWriter, r *http.Request) {
···
284
310
func (s *State) Router() http.Handler {
285
311
r := chi.NewRouter()
286
312
313
+
r.Get("/", s.Timeline)
314
+
315
+
r.Get("/login", s.Login)
287
316
r.Post("/login", s.Login)
288
317
289
318
r.Route("/node", func(r chi.Router) {
···
295
324
})
296
325
})
297
326
298
-
r.Route("/settings", func(r chi.Router) {
327
+
r.Group(func(r chi.Router) {
299
328
r.Use(AuthMiddleware(s))
300
-
r.Put("/keys", s.Keys)
329
+
r.Get("/settings", s.Settings)
330
+
r.Put("/settings/keys", s.Keys)
301
331
})
302
332
303
333
return r