+2
-2
routes/git.go
+2
-2
routes/git.go
···
11
11
)
12
12
13
13
func (d *Handle) InfoRefs(w http.ResponseWriter, r *http.Request) {
14
-
name := uniqueName(r)
14
+
name := displayRepoName(r)
15
15
name = filepath.Clean(name)
16
16
17
17
repo := filepath.Join(d.c.Repo.ScanPath, name)
···
32
32
}
33
33
34
34
func (d *Handle) UploadPack(w http.ResponseWriter, r *http.Request) {
35
-
name := uniqueName(r)
35
+
name := displayRepoName(r)
36
36
name = filepath.Clean(name)
37
37
38
38
repo := filepath.Join(d.c.Repo.ScanPath, name)
+3
-1
routes/handler.go
+3
-1
routes/handler.go
···
9
9
_ "github.com/bluesky-social/indigo/xrpc"
10
10
"github.com/go-chi/chi/v5"
11
11
"github.com/gorilla/sessions"
12
+
"github.com/icyphox/bild/auth"
12
13
"github.com/icyphox/bild/config"
13
14
"github.com/icyphox/bild/db"
14
-
"github.com/icyphox/bild/routes/auth"
15
+
"github.com/icyphox/bild/routes/middleware"
15
16
"github.com/icyphox/bild/routes/tmpl"
16
17
)
17
18
···
77
78
})
78
79
79
80
r.Route("/@{user}", func(r chi.Router) {
81
+
r.Use(middleware.AddDID)
80
82
r.Get("/", h.Index)
81
83
82
84
// Repo routes
+61
routes/middleware/did.go
+61
routes/middleware/did.go
···
1
+
package middleware
2
+
3
+
import (
4
+
"context"
5
+
"log"
6
+
"net/http"
7
+
"sync"
8
+
"time"
9
+
10
+
"github.com/bluesky-social/indigo/atproto/identity"
11
+
"github.com/icyphox/bild/auth"
12
+
)
13
+
14
+
type cachedIdent struct {
15
+
ident *identity.Identity
16
+
expiry time.Time
17
+
}
18
+
19
+
var (
20
+
identCache = make(map[string]cachedIdent)
21
+
cacheMutex sync.RWMutex
22
+
)
23
+
24
+
// Only use this middleware for routes that require a handle
25
+
// /@{user}/...
26
+
func AddDID(next http.Handler) http.Handler {
27
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
28
+
user := r.PathValue("user")
29
+
30
+
// Check cache first
31
+
cacheMutex.RLock()
32
+
if cached, ok := identCache[user]; ok && time.Now().Before(cached.expiry) {
33
+
cacheMutex.RUnlock()
34
+
ctx := context.WithValue(r.Context(), "did", cached.ident.DID.String())
35
+
r = r.WithContext(ctx)
36
+
next.ServeHTTP(w, r)
37
+
return
38
+
}
39
+
cacheMutex.RUnlock()
40
+
41
+
// Cache miss - resolve and cache
42
+
ident, err := auth.ResolveIdent(r.Context(), user)
43
+
if err != nil {
44
+
log.Println("error resolving identity", err)
45
+
http.Error(w, "error resolving identity", http.StatusNotFound)
46
+
return
47
+
}
48
+
49
+
cacheMutex.Lock()
50
+
identCache[user] = cachedIdent{
51
+
ident: ident,
52
+
expiry: time.Now().Add(24 * time.Hour),
53
+
}
54
+
cacheMutex.Unlock()
55
+
56
+
ctx := context.WithValue(r.Context(), "did", ident.DID.String())
57
+
r = r.WithContext(ctx)
58
+
59
+
next.ServeHTTP(w, r)
60
+
})
61
+
}
+25
-36
routes/routes.go
+25
-36
routes/routes.go
···
22
22
"github.com/google/uuid"
23
23
"github.com/gorilla/sessions"
24
24
shbild "github.com/icyphox/bild/api/bild"
25
+
"github.com/icyphox/bild/auth"
25
26
"github.com/icyphox/bild/config"
26
27
"github.com/icyphox/bild/db"
27
28
"github.com/icyphox/bild/git"
28
-
"github.com/icyphox/bild/routes/auth"
29
29
"github.com/russross/blackfriday/v2"
30
30
"golang.org/x/crypto/ssh"
31
31
)
···
39
39
}
40
40
41
41
func (h *Handle) Index(w http.ResponseWriter, r *http.Request) {
42
-
user := chi.URLParam(r, "user")
43
-
path := filepath.Join(h.c.Repo.ScanPath, user)
42
+
name := displayRepoName(r)
43
+
path := filepath.Join(h.c.Repo.ScanPath, name)
44
44
dirs, err := os.ReadDir(path)
45
45
if err != nil {
46
46
h.Write500(w)
···
75
75
}
76
76
77
77
infos = append(infos, info{
78
-
DisplayName: getDisplayName(name),
78
+
DisplayName: trimDotGit(name),
79
79
Name: name,
80
80
Desc: getDescription(path),
81
81
Idle: humanize.Time(c.Author.When),
···
98
98
}
99
99
100
100
func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) {
101
-
name := uniqueName(r)
101
+
name := displayRepoName(r)
102
102
if h.isIgnored(name) {
103
103
h.Write404(w)
104
104
return
105
105
}
106
106
107
-
name = filepath.Clean(name)
108
-
path := filepath.Join(h.c.Repo.ScanPath, name)
107
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
109
108
110
109
gr, err := git.Open(path, "")
111
110
if err != nil {
···
164
163
165
164
data := make(map[string]any)
166
165
data["name"] = name
167
-
data["displayname"] = getDisplayName(name)
166
+
data["displayname"] = trimDotGit(name)
168
167
data["ref"] = mainBranch
169
168
data["readme"] = readmeContent
170
169
data["commits"] = commits
···
182
181
}
183
182
184
183
func (h *Handle) RepoTree(w http.ResponseWriter, r *http.Request) {
185
-
name := uniqueName(r)
184
+
name := displayRepoName(r)
186
185
if h.isIgnored(name) {
187
186
h.Write404(w)
188
187
return
···
190
189
treePath := chi.URLParam(r, "*")
191
190
ref := chi.URLParam(r, "ref")
192
191
193
-
name = filepath.Clean(name)
194
-
path := filepath.Join(h.c.Repo.ScanPath, name)
192
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
195
193
gr, err := git.Open(path, ref)
196
194
if err != nil {
197
195
h.Write404(w)
···
207
205
208
206
data := make(map[string]any)
209
207
data["name"] = name
210
-
data["displayname"] = getDisplayName(name)
208
+
data["displayname"] = trimDotGit(name)
211
209
data["ref"] = ref
212
210
data["parent"] = treePath
213
211
data["desc"] = getDescription(path)
···
223
221
raw = rawParam
224
222
}
225
223
226
-
name := uniqueName(r)
224
+
name := displayRepoName(r)
227
225
228
226
if h.isIgnored(name) {
229
227
h.Write404(w)
···
232
230
treePath := chi.URLParam(r, "*")
233
231
ref := chi.URLParam(r, "ref")
234
232
235
-
name = filepath.Clean(name)
236
-
path := filepath.Join(h.c.Repo.ScanPath, name)
233
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
237
234
gr, err := git.Open(path, ref)
238
235
if err != nil {
239
236
h.Write404(w)
···
247
244
}
248
245
data := make(map[string]any)
249
246
data["name"] = name
250
-
data["displayname"] = getDisplayName(name)
247
+
data["displayname"] = trimDotGit(name)
251
248
data["ref"] = ref
252
249
data["desc"] = getDescription(path)
253
250
data["path"] = treePath
···
266
263
}
267
264
268
265
func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) {
269
-
name := uniqueName(r)
266
+
name := displayRepoName(r)
270
267
if h.isIgnored(name) {
271
268
h.Write404(w)
272
269
return
···
288
285
setContentDisposition(w, filename)
289
286
setGZipMIME(w)
290
287
291
-
path := filepath.Join(h.c.Repo.ScanPath, name)
288
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
292
289
gr, err := git.Open(path, ref)
293
290
if err != nil {
294
291
h.Write404(w)
···
317
314
}
318
315
319
316
func (h *Handle) Log(w http.ResponseWriter, r *http.Request) {
320
-
name := uniqueName(r)
317
+
name := displayRepoName(r)
321
318
if h.isIgnored(name) {
322
319
h.Write404(w)
323
320
return
324
321
}
325
322
ref := chi.URLParam(r, "ref")
326
323
327
-
path := filepath.Join(h.c.Repo.ScanPath, name)
324
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
328
325
gr, err := git.Open(path, ref)
329
326
if err != nil {
330
327
h.Write404(w)
···
342
339
data["commits"] = commits
343
340
data["meta"] = h.c.Meta
344
341
data["name"] = name
345
-
data["displayname"] = getDisplayName(name)
342
+
data["displayname"] = trimDotGit(name)
346
343
data["ref"] = ref
347
344
data["desc"] = getDescription(path)
348
345
data["log"] = true
···
354
351
}
355
352
356
353
func (h *Handle) Diff(w http.ResponseWriter, r *http.Request) {
357
-
name := uniqueName(r)
354
+
name := displayRepoName(r)
358
355
if h.isIgnored(name) {
359
356
h.Write404(w)
360
357
return
361
358
}
362
359
ref := chi.URLParam(r, "ref")
363
360
364
-
path := filepath.Join(h.c.Repo.ScanPath, name)
361
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
365
362
gr, err := git.Open(path, ref)
366
363
if err != nil {
367
364
h.Write404(w)
···
382
379
data["diff"] = diff.Diff
383
380
data["meta"] = h.c.Meta
384
381
data["name"] = name
385
-
data["displayname"] = getDisplayName(name)
382
+
data["displayname"] = trimDotGit(name)
386
383
data["ref"] = ref
387
384
data["desc"] = getDescription(path)
388
385
···
399
396
return
400
397
}
401
398
402
-
path := filepath.Join(h.c.Repo.ScanPath, name)
399
+
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
403
400
gr, err := git.Open(path, "")
404
401
if err != nil {
405
402
h.Write404(w)
···
423
420
424
421
data["meta"] = h.c.Meta
425
422
data["name"] = name
426
-
data["displayname"] = getDisplayName(name)
423
+
data["displayname"] = trimDotGit(name)
427
424
data["branches"] = branches
428
425
data["tags"] = tags
429
426
data["desc"] = getDescription(path)
···
550
547
name := r.FormValue("name")
551
548
description := r.FormValue("description")
552
549
553
-
repoPath := filepath.Join(h.c.Repo.ScanPath, handle, name)
550
+
repoPath := filepath.Join(h.c.Repo.ScanPath, did, name)
554
551
err := git.InitBare(repoPath)
555
-
if err != nil {
556
-
h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.")
557
-
return
558
-
}
559
-
560
-
// For use by repoguard
561
-
didPath := filepath.Join(repoPath, "did")
562
-
err = os.WriteFile(didPath, []byte(did), 0644)
563
552
if err != nil {
564
553
h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.")
565
554
return
···
571
560
return
572
561
}
573
562
574
-
w.Header().Set("HX-Redirect", fmt.Sprintf("/@example.com/%s", name))
563
+
w.Header().Set("HX-Redirect", fmt.Sprintf("/@%s/%s", handle, name))
575
564
w.WriteHeader(http.StatusOK)
576
565
}
577
566
}
+19
-4
routes/util.go
+19
-4
routes/util.go
···
10
10
"strings"
11
11
12
12
"github.com/go-chi/chi/v5"
13
+
"github.com/icyphox/bild/auth"
13
14
"github.com/icyphox/bild/git"
14
15
"github.com/microcosm-cc/bluemonday"
15
16
)
···
23
24
return err == nil
24
25
}
25
26
26
-
func uniqueName(r *http.Request) string {
27
-
user := chi.URLParam(r, "user")
27
+
func displayRepoName(r *http.Request) string {
28
+
user := r.Context().Value("did").(string)
28
29
name := chi.URLParam(r, "name")
29
-
return fmt.Sprintf("%s/%s", user, name)
30
+
31
+
handle, err := auth.ResolveIdent(r.Context(), user)
32
+
if err != nil {
33
+
log.Printf("failed to resolve ident: %s: %s", user, err)
34
+
return fmt.Sprintf("%s/%s", user, name)
35
+
}
36
+
37
+
return fmt.Sprintf("@%s/%s", handle.Handle.String(), name)
38
+
}
39
+
40
+
func didPath(r *http.Request) string {
41
+
did := r.Context().Value("did").(string)
42
+
path := filepath.Join(did, chi.URLParam(r, "name"))
43
+
filepath.Clean(path)
44
+
return path
30
45
}
31
46
32
-
func getDisplayName(name string) string {
47
+
func trimDotGit(name string) string {
33
48
return strings.TrimSuffix(name, ".git")
34
49
}
35
50