Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

routes: resolve did to handle in middleware

So handles are now purely cosmetic and are resolved to DIDs in the middleware.
auth.ResolveIdent seems to add a lot of latency, so we cache the resolved ident
for 24 hours. It's still not as perfomant but we can come back to this later.

+110 -43
+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
··· 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 ··· 78 77 }) 79 78 80 79 r.Route("/@{user}", func(r chi.Router) { 80 + r.Use(middleware.AddDID) 81 81 r.Get("/", h.Index) 82 82 83 83 // Repo routes
+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
··· 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 { ··· 163 164 164 165 data := make(map[string]any) 165 166 data["name"] = name 166 - data["displayname"] = getDisplayName(name) 167 + data["displayname"] = trimDotGit(name) 167 168 data["ref"] = mainBranch 168 169 data["readme"] = readmeContent 169 170 data["commits"] = commits ··· 181 182 } 182 183 183 184 func (h *Handle) RepoTree(w http.ResponseWriter, r *http.Request) { 184 - name := uniqueName(r) 185 + name := displayRepoName(r) 185 186 if h.isIgnored(name) { 186 187 h.Write404(w) 187 188 return ··· 189 190 treePath := chi.URLParam(r, "*") 190 191 ref := chi.URLParam(r, "ref") 191 192 192 - name = filepath.Clean(name) 193 - path := filepath.Join(h.c.Repo.ScanPath, name) 193 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 194 194 gr, err := git.Open(path, ref) 195 195 if err != nil { 196 196 h.Write404(w) ··· 205 207 206 208 data := make(map[string]any) 207 209 data["name"] = name 208 - data["displayname"] = getDisplayName(name) 210 + data["displayname"] = trimDotGit(name) 209 211 data["ref"] = ref 210 212 data["parent"] = treePath 211 213 data["desc"] = getDescription(path) ··· 221 223 raw = rawParam 222 224 } 223 225 224 - name := uniqueName(r) 226 + name := displayRepoName(r) 225 227 226 228 if h.isIgnored(name) { 227 229 h.Write404(w) ··· 230 232 treePath := chi.URLParam(r, "*") 231 233 ref := chi.URLParam(r, "ref") 232 234 233 - name = filepath.Clean(name) 234 - path := filepath.Join(h.c.Repo.ScanPath, name) 235 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 235 236 gr, err := git.Open(path, ref) 236 237 if err != nil { 237 238 h.Write404(w) ··· 244 247 } 245 248 data := make(map[string]any) 246 249 data["name"] = name 247 - data["displayname"] = getDisplayName(name) 250 + data["displayname"] = trimDotGit(name) 248 251 data["ref"] = ref 249 252 data["desc"] = getDescription(path) 250 253 data["path"] = treePath ··· 263 266 } 264 267 265 268 func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { 266 - name := uniqueName(r) 269 + name := displayRepoName(r) 267 270 if h.isIgnored(name) { 268 271 h.Write404(w) 269 272 return ··· 285 288 setContentDisposition(w, filename) 286 289 setGZipMIME(w) 287 290 288 - path := filepath.Join(h.c.Repo.ScanPath, name) 291 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 289 292 gr, err := git.Open(path, ref) 290 293 if err != nil { 291 294 h.Write404(w) ··· 314 317 } 315 318 316 319 func (h *Handle) Log(w http.ResponseWriter, r *http.Request) { 317 - name := uniqueName(r) 320 + name := displayRepoName(r) 318 321 if h.isIgnored(name) { 319 322 h.Write404(w) 320 323 return 321 324 } 322 325 ref := chi.URLParam(r, "ref") 323 326 324 - path := filepath.Join(h.c.Repo.ScanPath, name) 327 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 325 328 gr, err := git.Open(path, ref) 326 329 if err != nil { 327 330 h.Write404(w) ··· 339 342 data["commits"] = commits 340 343 data["meta"] = h.c.Meta 341 344 data["name"] = name 342 - data["displayname"] = getDisplayName(name) 345 + data["displayname"] = trimDotGit(name) 343 346 data["ref"] = ref 344 347 data["desc"] = getDescription(path) 345 348 data["log"] = true ··· 351 354 } 352 355 353 356 func (h *Handle) Diff(w http.ResponseWriter, r *http.Request) { 354 - name := uniqueName(r) 357 + name := displayRepoName(r) 355 358 if h.isIgnored(name) { 356 359 h.Write404(w) 357 360 return 358 361 } 359 362 ref := chi.URLParam(r, "ref") 360 363 361 - path := filepath.Join(h.c.Repo.ScanPath, name) 364 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 362 365 gr, err := git.Open(path, ref) 363 366 if err != nil { 364 367 h.Write404(w) ··· 379 382 data["diff"] = diff.Diff 380 383 data["meta"] = h.c.Meta 381 384 data["name"] = name 382 - data["displayname"] = getDisplayName(name) 385 + data["displayname"] = trimDotGit(name) 383 386 data["ref"] = ref 384 387 data["desc"] = getDescription(path) 385 388 ··· 396 399 return 397 400 } 398 401 399 - path := filepath.Join(h.c.Repo.ScanPath, name) 402 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 400 403 gr, err := git.Open(path, "") 401 404 if err != nil { 402 405 h.Write404(w) ··· 420 423 421 424 data["meta"] = h.c.Meta 422 425 data["name"] = name 423 - data["displayname"] = getDisplayName(name) 426 + data["displayname"] = trimDotGit(name) 424 427 data["branches"] = branches 425 428 data["tags"] = tags 426 429 data["desc"] = getDescription(path) ··· 547 550 name := r.FormValue("name") 548 551 description := r.FormValue("description") 549 552 550 - repoPath := filepath.Join(h.c.Repo.ScanPath, handle, name) 553 + repoPath := filepath.Join(h.c.Repo.ScanPath, did, name) 551 554 err := git.InitBare(repoPath) 552 - if err != nil { 553 - h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.") 554 - return 555 - } 556 - 557 - // For use by repoguard 558 - didPath := filepath.Join(repoPath, "did") 559 - err = os.WriteFile(didPath, []byte(did), 0644) 560 555 if err != nil { 561 556 h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.") 562 557 return ··· 560 571 return 561 572 } 562 573 563 - w.Header().Set("HX-Redirect", fmt.Sprintf("/@example.com/%s", name)) 574 + w.Header().Set("HX-Redirect", fmt.Sprintf("/@%s/%s", handle, name)) 564 575 w.WriteHeader(http.StatusOK) 565 576 } 566 577 }
+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 ) ··· 24 23 return err == nil 25 24 } 26 25 27 - func uniqueName(r *http.Request) string { 28 - user := chi.URLParam(r, "user") 26 + func displayRepoName(r *http.Request) string { 27 + user := r.Context().Value("did").(string) 29 28 name := chi.URLParam(r, "name") 30 - return fmt.Sprintf("%s/%s", user, name) 29 + 30 + handle, err := auth.ResolveIdent(r.Context(), user) 31 + if err != nil { 32 + log.Printf("failed to resolve ident: %s: %s", user, err) 33 + return fmt.Sprintf("%s/%s", user, name) 34 + } 35 + 36 + return fmt.Sprintf("@%s/%s", handle.Handle.String(), name) 31 37 } 32 38 33 - func getDisplayName(name string) string { 39 + func didPath(r *http.Request) string { 40 + did := r.Context().Value("did").(string) 41 + path := filepath.Join(did, chi.URLParam(r, "name")) 42 + filepath.Clean(path) 43 + return path 44 + } 45 + 46 + func trimDotGit(name string) string { 34 47 return strings.TrimSuffix(name, ".git") 35 48 } 36 49