this repo has no description
1package routes 2 3import ( 4 "compress/gzip" 5 "fmt" 6 "html/template" 7 "log" 8 "net/http" 9 "os" 10 "path/filepath" 11 "sort" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/dustin/go-humanize" 17 "github.com/go-chi/chi/v5" 18 "github.com/icyphox/bild/legit/config" 19 "github.com/icyphox/bild/legit/db" 20 "github.com/icyphox/bild/legit/git" 21 "github.com/russross/blackfriday/v2" 22) 23 24type Handle struct { 25 c *config.Config 26 t *template.Template 27 db *db.DB 28} 29 30func (h *Handle) Index(w http.ResponseWriter, r *http.Request) { 31 user := chi.URLParam(r, "user") 32 path := filepath.Join(h.c.Repo.ScanPath, user) 33 dirs, err := os.ReadDir(path) 34 if err != nil { 35 h.Write500(w) 36 log.Printf("reading scan path: %s", err) 37 return 38 } 39 40 type info struct { 41 DisplayName, Name, Desc, Idle string 42 d time.Time 43 } 44 45 infos := []info{} 46 47 for _, dir := range dirs { 48 name := dir.Name() 49 if !dir.IsDir() || h.isIgnored(name) || h.isUnlisted(name) { 50 continue 51 } 52 53 gr, err := git.Open(path, "") 54 if err != nil { 55 log.Println(err) 56 continue 57 } 58 59 c, err := gr.LastCommit() 60 if err != nil { 61 h.Write500(w) 62 log.Println(err) 63 return 64 } 65 66 infos = append(infos, info{ 67 DisplayName: getDisplayName(name), 68 Name: name, 69 Desc: getDescription(path), 70 Idle: humanize.Time(c.Author.When), 71 d: c.Author.When, 72 }) 73 } 74 75 sort.Slice(infos, func(i, j int) bool { 76 return infos[j].d.Before(infos[i].d) 77 }) 78 79 data := make(map[string]interface{}) 80 data["meta"] = h.c.Meta 81 data["info"] = infos 82 83 if err := h.t.ExecuteTemplate(w, "index", data); err != nil { 84 log.Println(err) 85 return 86 } 87} 88 89func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) { 90 name := uniqueName(r) 91 if h.isIgnored(name) { 92 h.Write404(w) 93 return 94 } 95 96 name = filepath.Clean(name) 97 path := filepath.Join(h.c.Repo.ScanPath, name) 98 99 fmt.Println(path) 100 gr, err := git.Open(path, "") 101 if err != nil { 102 h.Write404(w) 103 return 104 } 105 commits, err := gr.Commits() 106 if err != nil { 107 h.Write500(w) 108 log.Println(err) 109 return 110 } 111 112 var readmeContent template.HTML 113 for _, readme := range h.c.Repo.Readme { 114 ext := filepath.Ext(readme) 115 content, _ := gr.FileContent(readme) 116 if len(content) > 0 { 117 switch ext { 118 case ".md", ".mkd", ".markdown": 119 unsafe := blackfriday.Run( 120 []byte(content), 121 blackfriday.WithExtensions(blackfriday.CommonExtensions), 122 ) 123 html := sanitize(unsafe) 124 readmeContent = template.HTML(html) 125 default: 126 safe := sanitize([]byte(content)) 127 readmeContent = template.HTML( 128 fmt.Sprintf(`<pre>%s</pre>`, safe), 129 ) 130 } 131 break 132 } 133 } 134 135 if readmeContent == "" { 136 log.Printf("no readme found for %s", name) 137 } 138 139 mainBranch, err := gr.FindMainBranch(h.c.Repo.MainBranch) 140 if err != nil { 141 h.Write500(w) 142 log.Println(err) 143 return 144 } 145 146 if len(commits) >= 3 { 147 commits = commits[:3] 148 } 149 150 data := make(map[string]any) 151 data["name"] = name 152 data["displayname"] = getDisplayName(name) 153 data["ref"] = mainBranch 154 data["readme"] = readmeContent 155 data["commits"] = commits 156 data["desc"] = getDescription(path) 157 data["servername"] = h.c.Server.Name 158 data["meta"] = h.c.Meta 159 data["gomod"] = isGoModule(gr) 160 161 if err := h.t.ExecuteTemplate(w, "repo", data); err != nil { 162 log.Println(err) 163 return 164 } 165 166 return 167} 168 169func (h *Handle) RepoTree(w http.ResponseWriter, r *http.Request) { 170 name := uniqueName(r) 171 if h.isIgnored(name) { 172 h.Write404(w) 173 return 174 } 175 treePath := chi.URLParam(r, "*") 176 ref := chi.URLParam(r, "ref") 177 178 name = filepath.Clean(name) 179 path := filepath.Join(h.c.Repo.ScanPath, name) 180 fmt.Println(path) 181 gr, err := git.Open(path, ref) 182 if err != nil { 183 h.Write404(w) 184 return 185 } 186 187 files, err := gr.FileTree(treePath) 188 if err != nil { 189 h.Write500(w) 190 log.Println(err) 191 return 192 } 193 194 data := make(map[string]any) 195 data["name"] = name 196 data["displayname"] = getDisplayName(name) 197 data["ref"] = ref 198 data["parent"] = treePath 199 data["desc"] = getDescription(path) 200 data["dotdot"] = filepath.Dir(treePath) 201 202 h.listFiles(files, data, w) 203 return 204} 205 206func (h *Handle) FileContent(w http.ResponseWriter, r *http.Request) { 207 var raw bool 208 if rawParam, err := strconv.ParseBool(r.URL.Query().Get("raw")); err == nil { 209 raw = rawParam 210 } 211 212 name := uniqueName(r) 213 214 if h.isIgnored(name) { 215 h.Write404(w) 216 return 217 } 218 treePath := chi.URLParam(r, "*") 219 ref := chi.URLParam(r, "ref") 220 221 name = filepath.Clean(name) 222 path := filepath.Join(h.c.Repo.ScanPath, name) 223 gr, err := git.Open(path, ref) 224 if err != nil { 225 h.Write404(w) 226 return 227 } 228 229 contents, err := gr.FileContent(treePath) 230 if err != nil { 231 h.Write500(w) 232 return 233 } 234 data := make(map[string]any) 235 data["name"] = name 236 data["displayname"] = getDisplayName(name) 237 data["ref"] = ref 238 data["desc"] = getDescription(path) 239 data["path"] = treePath 240 241 safe := sanitize([]byte(contents)) 242 243 if raw { 244 h.showRaw(string(safe), w) 245 } else { 246 if h.c.Meta.SyntaxHighlight == "" { 247 h.showFile(string(safe), data, w) 248 } else { 249 h.showFileWithHighlight(treePath, string(safe), data, w) 250 } 251 } 252} 253 254func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { 255 name := uniqueName(r) 256 if h.isIgnored(name) { 257 h.Write404(w) 258 return 259 } 260 261 file := chi.URLParam(r, "file") 262 263 // TODO: extend this to add more files compression (e.g.: xz) 264 if !strings.HasSuffix(file, ".tar.gz") { 265 h.Write404(w) 266 return 267 } 268 269 ref := strings.TrimSuffix(file, ".tar.gz") 270 271 // This allows the browser to use a proper name for the file when 272 // downloading 273 filename := fmt.Sprintf("%s-%s.tar.gz", name, ref) 274 setContentDisposition(w, filename) 275 setGZipMIME(w) 276 277 path := filepath.Join(h.c.Repo.ScanPath, name) 278 gr, err := git.Open(path, ref) 279 if err != nil { 280 h.Write404(w) 281 return 282 } 283 284 gw := gzip.NewWriter(w) 285 defer gw.Close() 286 287 prefix := fmt.Sprintf("%s-%s", name, ref) 288 err = gr.WriteTar(gw, prefix) 289 if err != nil { 290 // once we start writing to the body we can't report error anymore 291 // so we are only left with printing the error. 292 log.Println(err) 293 return 294 } 295 296 err = gw.Flush() 297 if err != nil { 298 // once we start writing to the body we can't report error anymore 299 // so we are only left with printing the error. 300 log.Println(err) 301 return 302 } 303} 304 305func (h *Handle) Log(w http.ResponseWriter, r *http.Request) { 306 name := uniqueName(r) 307 if h.isIgnored(name) { 308 h.Write404(w) 309 return 310 } 311 ref := chi.URLParam(r, "ref") 312 313 path := filepath.Join(h.c.Repo.ScanPath, name) 314 gr, err := git.Open(path, ref) 315 if err != nil { 316 h.Write404(w) 317 return 318 } 319 320 commits, err := gr.Commits() 321 if err != nil { 322 h.Write500(w) 323 log.Println(err) 324 return 325 } 326 327 data := make(map[string]interface{}) 328 data["commits"] = commits 329 data["meta"] = h.c.Meta 330 data["name"] = name 331 data["displayname"] = getDisplayName(name) 332 data["ref"] = ref 333 data["desc"] = getDescription(path) 334 data["log"] = true 335 336 if err := h.t.ExecuteTemplate(w, "log", data); err != nil { 337 log.Println(err) 338 return 339 } 340} 341 342func (h *Handle) Diff(w http.ResponseWriter, r *http.Request) { 343 name := uniqueName(r) 344 if h.isIgnored(name) { 345 h.Write404(w) 346 return 347 } 348 ref := chi.URLParam(r, "ref") 349 350 path := filepath.Join(h.c.Repo.ScanPath, name) 351 gr, err := git.Open(path, ref) 352 if err != nil { 353 h.Write404(w) 354 return 355 } 356 357 diff, err := gr.Diff() 358 if err != nil { 359 h.Write500(w) 360 log.Println(err) 361 return 362 } 363 364 data := make(map[string]interface{}) 365 366 data["commit"] = diff.Commit 367 data["stat"] = diff.Stat 368 data["diff"] = diff.Diff 369 data["meta"] = h.c.Meta 370 data["name"] = name 371 data["displayname"] = getDisplayName(name) 372 data["ref"] = ref 373 data["desc"] = getDescription(path) 374 375 if err := h.t.ExecuteTemplate(w, "commit", data); err != nil { 376 log.Println(err) 377 return 378 } 379} 380 381func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { 382 name := chi.URLParam(r, "name") 383 if h.isIgnored(name) { 384 h.Write404(w) 385 return 386 } 387 388 path := filepath.Join(h.c.Repo.ScanPath, name) 389 gr, err := git.Open(path, "") 390 if err != nil { 391 h.Write404(w) 392 return 393 } 394 395 tags, err := gr.Tags() 396 if err != nil { 397 // Non-fatal, we *should* have at least one branch to show. 398 log.Println(err) 399 } 400 401 branches, err := gr.Branches() 402 if err != nil { 403 log.Println(err) 404 h.Write500(w) 405 return 406 } 407 408 data := make(map[string]interface{}) 409 410 data["meta"] = h.c.Meta 411 data["name"] = name 412 data["displayname"] = getDisplayName(name) 413 data["branches"] = branches 414 data["tags"] = tags 415 data["desc"] = getDescription(path) 416 417 if err := h.t.ExecuteTemplate(w, "refs", data); err != nil { 418 log.Println(err) 419 return 420 } 421} 422 423func (h *Handle) ServeStatic(w http.ResponseWriter, r *http.Request) { 424 f := chi.URLParam(r, "file") 425 f = filepath.Clean(filepath.Join(h.c.Dirs.Static, f)) 426 427 http.ServeFile(w, r, f) 428} 429 430func (h *Handle) Login(w http.ResponseWriter, r *http.Request) { 431 if err := h.t.ExecuteTemplate(w, "login", nil); err != nil { 432 log.Println(err) 433 return 434 } 435} 436 437func (h *Handle) Keys(w http.ResponseWriter, r *http.Request) { 438 switch r.Method { 439 case http.MethodGet: 440 // TODO: fetch keys from db 441 if err := h.t.ExecuteTemplate(w, "keys", nil); err != nil { 442 log.Println(err) 443 return 444 } 445 case http.MethodPut: 446 key := r.FormValue("key") 447 name := r.FormValue("name") 448 // TODO: add did here 449 if err := h.db.AddPublicKey("did:ashtntnashtx", name, key); err != nil { 450 h.WriteOOBNotice(w, "keys", "Failed to add key") 451 log.Printf("adding public key: %s", err) 452 return 453 } 454 455 h.WriteOOBNotice(w, "keys", "Key added!") 456 return 457 } 458}