github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/routes/attachments.go (about) 1 package routes 2 3 import ( 4 "database/sql" 5 "net/http" 6 "path/filepath" 7 "strconv" 8 "strings" 9 10 c "github.com/Azareal/Gosora/common" 11 ) 12 13 var maxAgeYear = "max-age=" + strconv.Itoa(int(c.Year)) 14 15 func ShowAttachment(w http.ResponseWriter, r *http.Request, u *c.User, filename string) c.RouteError { 16 sid, err := strconv.Atoi(r.FormValue("sid")) 17 if err != nil { 18 return c.LocalError("The sid is not an integer", w, r, u) 19 } 20 sectionTable := r.FormValue("stype") 21 22 filename = c.Stripslashes(filename) 23 if filename == "" { 24 return c.LocalError("Bad filename", w, r, u) 25 } 26 ext := filepath.Ext(filename) 27 if ext == "" || !c.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { 28 return c.LocalError("Bad extension", w, r, u) 29 } 30 31 // TODO: Use the same hook table as upstream 32 hTbl := c.GetHookTable() 33 skip, rerr := c.H_route_attach_start_hook(hTbl, w, r, u, filename) 34 if skip || rerr != nil { 35 return rerr 36 } 37 38 a, err := c.Attachments.GetForRenderRoute(filename, sid, sectionTable) 39 // ErrCorruptAttachPath is a possibility now 40 if err == sql.ErrNoRows { 41 return c.NotFound(w, r, nil) 42 } else if err != nil { 43 return c.InternalError(err, w, r) 44 } 45 46 skip, rerr = c.H_route_attach_post_get_hook(hTbl, w, r, u, a) 47 if skip || rerr != nil { 48 return rerr 49 } 50 51 if a.SectionTable == "forums" { 52 _, ferr := c.SimpleForumUserCheck(w, r, u, sid) 53 if ferr != nil { 54 return ferr 55 } 56 if !u.Perms.ViewTopic { 57 return c.NoPermissions(w, r, u) 58 } 59 } else { 60 return c.LocalError("Unknown section", w, r, u) 61 } 62 63 if a.OriginTable != "topics" && a.OriginTable != "replies" { 64 return c.LocalError("Unknown origin", w, r, u) 65 } 66 67 if !u.Loggedin { 68 w.Header().Set("Cache-Control", maxAgeYear) 69 } else { 70 guest := c.GuestUser 71 _, ferr := c.SimpleForumUserCheck(w, r, &guest, sid) 72 if ferr != nil { 73 return ferr 74 } 75 h := w.Header() 76 if guest.Perms.ViewTopic { 77 h.Set("Cache-Control", maxAgeYear) 78 } else { 79 h.Set("Cache-Control", "private") 80 } 81 } 82 83 // TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side 84 http.ServeFile(w, r, "./attachs/"+filename) 85 return nil 86 } 87 88 func deleteAttachment(w http.ResponseWriter, r *http.Request, u *c.User, aid int, js bool) c.RouteError { 89 e := c.DeleteAttachment(aid) 90 if e == sql.ErrNoRows { 91 return c.NotFoundJSQ(w, r, nil, js) 92 } else if e != nil { 93 return c.InternalErrorJSQ(e, w, r, js) 94 } 95 return nil 96 } 97 98 // TODO: Stop duplicating this code 99 // TODO: Use a transaction here 100 // TODO: Move this function to neutral ground 101 func uploadAttachment(w http.ResponseWriter, r *http.Request, u *c.User, sid int, stable string, oid int, otable, extra string) (pathMap map[string]string, rerr c.RouteError) { 102 pathMap = make(map[string]string) 103 files, rerr := uploadFilesWithHash(w, r, u, "./attachs/") 104 if rerr != nil { 105 return nil, rerr 106 } 107 108 for _, filename := range files { 109 aid, err := c.Attachments.Add(sid, stable, oid, otable, u.ID, filename, extra) 110 if err != nil { 111 return nil, c.InternalError(err, w, r) 112 } 113 114 _, ok := pathMap[filename] 115 if ok { 116 pathMap[filename] += "," + strconv.Itoa(aid) 117 } else { 118 pathMap[filename] = strconv.Itoa(aid) 119 } 120 121 err = c.Attachments.AddLinked(otable, oid) 122 if err != nil { 123 return nil, c.InternalError(err, w, r) 124 } 125 } 126 127 return pathMap, nil 128 }