Commit 15961c4783
Verified · cmc ci/build: success ci/test: success ci/vuln: success
Layout: unified · split
internal/httpd/account.go +3 −5
| @@ -56,7 +56,7 @@ func (s *Server) accountForm(w http.ResponseWriter, r *http.Request, u store.Use | ||
| 56 | 56 | Notice string |
| 57 | 57 | Message string |
| 58 | 58 | }{s.baseFor(u), "account", keys, pgp, emails, s.cfg.SiteHost(), |
| 59 | r.URL.Query().Get("e"), r.URL.Query().Get("m")}) | |
| 59 | s.takeFlash(w, r), r.URL.Query().Get("m")}) | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | // accountSubmit routes the account forms to their commands. Everything |
| @@ -64,12 +64,10 @@ func (s *Server) accountForm(w http.ResponseWriter, r *http.Request, u store.Use | ||
| 64 | 64 | func (s *Server) accountSubmit(w http.ResponseWriter, r *http.Request, u store.User) { |
| 65 | 65 | back := func(msg, note string) { |
| 66 | 66 | q := "" |
| 67 | switch { | |
| 68 | case msg != "": | |
| 69 | q = "?e=" + url.QueryEscape(msg) | |
| 70 | case note != "": | |
| 67 | if note != "" { | |
| 71 | 68 | q = "?m=" + url.QueryEscape(note) |
| 72 | 69 | } |
| 70 | s.setFlash(w, msg) | |
| 73 | 71 | http.Redirect(w, r, "/settings"+q, http.StatusSeeOther) |
| 74 | 72 | } |
| 75 | 73 | |
internal/httpd/builds.go +1 −1
| @@ -45,7 +45,7 @@ func (s *Server) builds(w http.ResponseWriter, r *http.Request) { | ||
| 45 | 45 | Jobs []jobView |
| 46 | 46 | CanWrite bool |
| 47 | 47 | Notice string |
| 48 | }{p, builds, jobs, s.canWriteRepo(r, p.Repo), r.URL.Query().Get("e")}) | |
| 48 | }{p, builds, jobs, s.canWriteRepo(r, p.Repo), s.takeFlash(w, r)}) | |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | func (s *Server) build(w http.ResponseWriter, r *http.Request) { |
internal/httpd/flash.go added +44
| @@ -0,0 +1,44 @@ | ||
| 1 | package httpd | |
| 2 | ||
| 3 | import ( | |
| 4 | "net/http" | |
| 5 | "net/url" | |
| 6 | ) | |
| 7 | ||
| 8 | // A form action that fails redirects back to the page it came from with | |
| 9 | // the reason. The reason used to ride the URL as ?e=, so it survived a | |
| 10 | // reload and landed in history and bookmarks. It rides a one-shot cookie | |
| 11 | // now: set on the redirect, read and cleared by the page that renders it | |
| 12 | // (#119). | |
| 13 | const flashCookie = "gitbay_notice" | |
| 14 | ||
| 15 | // setFlash queues msg for the next page render. An empty msg sets | |
| 16 | // nothing. | |
| 17 | func (s *Server) setFlash(w http.ResponseWriter, msg string) { | |
| 18 | if msg == "" { | |
| 19 | return | |
| 20 | } | |
| 21 | if len(msg) > 300 { | |
| 22 | msg = msg[:300] | |
| 23 | } | |
| 24 | http.SetCookie(w, &http.Cookie{ | |
| 25 | Name: flashCookie, Value: url.QueryEscape(msg), Path: "/", | |
| 26 | HttpOnly: true, SameSite: http.SameSiteLaxMode, | |
| 27 | Secure: s.cfg.HTTP.TLS != "off", | |
| 28 | MaxAge: 60, | |
| 29 | }) | |
| 30 | } | |
| 31 | ||
| 32 | // takeFlash returns the queued message, if any, and clears it. | |
| 33 | func (s *Server) takeFlash(w http.ResponseWriter, r *http.Request) string { | |
| 34 | c, err := r.Cookie(flashCookie) | |
| 35 | if err != nil || c.Value == "" { | |
| 36 | return "" | |
| 37 | } | |
| 38 | http.SetCookie(w, &http.Cookie{Name: flashCookie, Value: "", Path: "/", MaxAge: -1}) | |
| 39 | msg, err := url.QueryUnescape(c.Value) | |
| 40 | if err != nil { | |
| 41 | return "" | |
| 42 | } | |
| 43 | return msg | |
| 44 | } | |
internal/httpd/issueactions.go +1 −7
| @@ -3,7 +3,6 @@ package httpd | ||
| 3 | 3 | import ( |
| 4 | 4 | "fmt" |
| 5 | 5 | "net/http" |
| 6 | "net/url" | |
| 7 | 6 | "strings" |
| 8 | 7 | |
| 9 | 8 | "gitbay.org/gitbay/internal/store" |
| @@ -16,12 +15,7 @@ import ( | ||
| 16 | 15 | func (s *Server) issueRedirect(w http.ResponseWriter, r *http.Request, msg string) { |
| 17 | 16 | dest := fmt.Sprintf("/%s/%s/issues/%s", |
| 18 | 17 | r.PathValue("owner"), r.PathValue("repo"), r.PathValue("n")) |
| 19 | if msg != "" { | |
| 20 | if len(msg) > 300 { | |
| 21 | msg = msg[:300] | |
| 22 | } | |
| 23 | dest += "?e=" + url.QueryEscape(msg) | |
| 24 | } | |
| 18 | s.setFlash(w, msg) | |
| 25 | 19 | http.Redirect(w, r, dest, http.StatusSeeOther) |
| 26 | 20 | } |
| 27 | 21 | |
internal/httpd/mractions.go +5 −14
| @@ -22,12 +22,7 @@ import ( | ||
| 22 | 22 | func (s *Server) mrRedirect(w http.ResponseWriter, r *http.Request, msg string) { |
| 23 | 23 | dest := fmt.Sprintf("/%s/%s/mrs/%s", |
| 24 | 24 | r.PathValue("owner"), r.PathValue("repo"), r.PathValue("n")) |
| 25 | if msg != "" { | |
| 26 | if len(msg) > 300 { | |
| 27 | msg = msg[:300] | |
| 28 | } | |
| 29 | dest += "?e=" + url.QueryEscape(msg) | |
| 30 | } | |
| 25 | s.setFlash(w, msg) | |
| 31 | 26 | http.Redirect(w, r, dest, http.StatusSeeOther) |
| 32 | 27 | } |
| 33 | 28 | |
| @@ -35,12 +30,7 @@ func (s *Server) mrRedirect(w http.ResponseWriter, r *http.Request, msg string) | ||
| 35 | 30 | func (s *Server) mrDiffRedirect(w http.ResponseWriter, r *http.Request, msg string) { |
| 36 | 31 | dest := fmt.Sprintf("/%s/%s/mrs/%s?view=diff", |
| 37 | 32 | r.PathValue("owner"), r.PathValue("repo"), r.PathValue("n")) |
| 38 | if msg != "" { | |
| 39 | if len(msg) > 300 { | |
| 40 | msg = msg[:300] | |
| 41 | } | |
| 42 | dest += "&e=" + url.QueryEscape(msg) | |
| 43 | } | |
| 33 | s.setFlash(w, msg) | |
| 44 | 34 | http.Redirect(w, r, dest, http.StatusSeeOther) |
| 45 | 35 | } |
| 46 | 36 | |
| @@ -163,7 +153,7 @@ func (s *Server) mrCreateForm(w http.ResponseWriter, r *http.Request, u store.Us | ||
| 163 | 153 | s.render(w, "mrnew.html", mrNewPage{ |
| 164 | 154 | repoPage: p, Branches: branches, |
| 165 | 155 | Source: q.Get("source"), Target: target, |
| 166 | Title: q.Get("title"), Body: q.Get("body"), Notice: q.Get("e"), | |
| 156 | Title: q.Get("title"), Body: q.Get("body"), Notice: s.takeFlash(w, r), | |
| 167 | 157 | }) |
| 168 | 158 | } |
| 169 | 159 | |
| @@ -178,7 +168,8 @@ func (s *Server) mrCreateSubmit(w http.ResponseWriter, r *http.Request, u store. | ||
| 178 | 168 | body := strings.TrimSpace(r.FormValue("body")) |
| 179 | 169 | |
| 180 | 170 | back := func(msg string) { |
| 181 | q := url.Values{"source": {source}, "target": {target}, "title": {title}, "body": {body}, "e": {msg}} | |
| 171 | q := url.Values{"source": {source}, "target": {target}, "title": {title}, "body": {body}} | |
| 172 | s.setFlash(w, msg) | |
| 182 | 173 | http.Redirect(w, r, fmt.Sprintf("/%s/mrs/new?%s", p.Repo.Path(), q.Encode()), http.StatusSeeOther) |
| 183 | 174 | } |
| 184 | 175 | if source == "" || title == "" { |
internal/httpd/orgweb.go +2 −6
| @@ -2,7 +2,6 @@ package httpd | ||
| 2 | 2 | |
| 3 | 3 | import ( |
| 4 | 4 | "net/http" |
| 5 | "net/url" | |
| 6 | 5 | "strings" |
| 7 | 6 | |
| 8 | 7 | "gitbay.org/gitbay/internal/store" |
| @@ -45,11 +44,8 @@ func (s *Server) orgAdminView(viewer store.User, kind, name string) (teams []tea | ||
| 45 | 44 | func (s *Server) orgSubmit(w http.ResponseWriter, r *http.Request, u store.User) { |
| 46 | 45 | owner := r.PathValue("owner") |
| 47 | 46 | back := func(msg string) { |
| 48 | dest := "/" + owner | |
| 49 | if msg != "" { | |
| 50 | dest += "?e=" + url.QueryEscape(msg) | |
| 51 | } | |
| 52 | http.Redirect(w, r, dest, http.StatusSeeOther) | |
| 47 | s.setFlash(w, msg) | |
| 48 | http.Redirect(w, r, "/"+owner, http.StatusSeeOther) | |
| 53 | 49 | } |
| 54 | 50 | field := r.FormValue("field") |
| 55 | 51 | team := strings.TrimSpace(r.FormValue("team")) |
internal/httpd/releaseactions.go +1 −7
| @@ -3,7 +3,6 @@ package httpd | ||
| 3 | 3 | import ( |
| 4 | 4 | "fmt" |
| 5 | 5 | "net/http" |
| 6 | "net/url" | |
| 7 | 6 | "strings" |
| 8 | 7 | |
| 9 | 8 | "gitbay.org/gitbay/internal/store" |
| @@ -15,12 +14,7 @@ import ( | ||
| 15 | 14 | |
| 16 | 15 | func (s *Server) backTo(w http.ResponseWriter, r *http.Request, page, msg string) { |
| 17 | 16 | dest := fmt.Sprintf("/%s/%s/%s", r.PathValue("owner"), r.PathValue("repo"), page) |
| 18 | if msg != "" { | |
| 19 | if len(msg) > 300 { | |
| 20 | msg = msg[:300] | |
| 21 | } | |
| 22 | dest += "?e=" + url.QueryEscape(msg) | |
| 23 | } | |
| 17 | s.setFlash(w, msg) | |
| 24 | 18 | http.Redirect(w, r, dest, http.StatusSeeOther) |
| 25 | 19 | } |
| 26 | 20 | |
internal/httpd/settings.go +2 −8
| @@ -3,7 +3,6 @@ package httpd | ||
| 3 | 3 | import ( |
| 4 | 4 | "fmt" |
| 5 | 5 | "net/http" |
| 6 | "net/url" | |
| 7 | 6 | "strings" |
| 8 | 7 | |
| 9 | 8 | "gitbay.org/gitbay/internal/gitutil" |
| @@ -39,18 +38,13 @@ func (s *Server) settingsForm(w http.ResponseWriter, r *http.Request, u store.Us | ||
| 39 | 38 | s.render(w, "settings.html", settingsPage{ |
| 40 | 39 | repoPage: p, Topics: topics, Branches: branches, |
| 41 | 40 | DepsEnabled: depsErr == nil, |
| 42 | Notice: r.URL.Query().Get("e"), | |
| 41 | Notice: s.takeFlash(w, r), | |
| 43 | 42 | }) |
| 44 | 43 | } |
| 45 | 44 | |
| 46 | 45 | func (s *Server) settingsRedirect(w http.ResponseWriter, r *http.Request, msg string) { |
| 47 | 46 | dest := fmt.Sprintf("/%s/%s/settings", r.PathValue("owner"), r.PathValue("repo")) |
| 48 | if msg != "" { | |
| 49 | if len(msg) > 300 { | |
| 50 | msg = msg[:300] | |
| 51 | } | |
| 52 | dest += "?e=" + url.QueryEscape(msg) | |
| 53 | } | |
| 47 | s.setFlash(w, msg) | |
| 54 | 48 | http.Redirect(w, r, dest, http.StatusSeeOther) |
| 55 | 49 | } |
| 56 | 50 | |
internal/httpd/web.go +4 −4
| @@ -469,7 +469,7 @@ func (s *Server) ownerPage(w http.ResponseWriter, r *http.Request) { | ||
| 469 | 469 | Notice string |
| 470 | 470 | }{s.baseFor(viewer), name, d.Kind, profile, aboutHTML(profile), |
| 471 | 471 | d.Repos, d.Members, d.Orgs, |
| 472 | weeks, activityTotal, teams, canAdmin, r.URL.Query().Get("e")}) | |
| 472 | weeks, activityTotal, teams, canAdmin, s.takeFlash(w, r)}) | |
| 473 | 473 | } |
| 474 | 474 | |
| 475 | 475 | func (s *Server) repoHome(w http.ResponseWriter, r *http.Request) { |
| @@ -665,7 +665,7 @@ func (s *Server) releases(w http.ResponseWriter, r *http.Request) { | ||
| 665 | 665 | FreeTags []string |
| 666 | 666 | CanWrite bool |
| 667 | 667 | Notice string |
| 668 | }{p, views, freeTags, s.canWriteRepo(r, p.Repo), r.URL.Query().Get("e")}) | |
| 668 | }{p, views, freeTags, s.canWriteRepo(r, p.Repo), s.takeFlash(w, r)}) | |
| 669 | 669 | } |
| 670 | 670 | |
| 671 | 671 | // releaseAsset streams one uploaded asset. Tags containing '/' are not |
| @@ -1640,7 +1640,7 @@ func (s *Server) issue(w http.ResponseWriter, r *http.Request) { | ||
| 1640 | 1640 | LabelColors map[string]template.CSS |
| 1641 | 1641 | }{p, iss, md(iss.Body, iss.BodyFormat), renderComments(comments, md), |
| 1642 | 1642 | s.canEditItem(r, p.Repo, iss.Author), s.canWriteRepo(r, p.Repo), |
| 1643 | milestones, r.URL.Query().Get("e"), s.labelColors(p.Repo.ID)}) | |
| 1643 | milestones, s.takeFlash(w, r), s.labelColors(p.Repo.ID)}) | |
| 1644 | 1644 | } |
| 1645 | 1645 | |
| 1646 | 1646 | // canEditItem: the author or anyone with write access may edit. |
| @@ -1817,7 +1817,7 @@ func (s *Server) mr(w http.ResponseWriter, r *http.Request) { | ||
| 1817 | 1817 | Stacked []store.MR |
| 1818 | 1818 | }{p, m, view, md(m.Body, m.BodyFormat), checks, combined, renderComments(comments, md), |
| 1819 | 1819 | reviews, files, diffTruncated, stat, commits, commitsTotal, branches, s.canEditItem(r, p.Repo, m.Author), |
| 1820 | canWrite, unresolved, r.URL.Query().Get("e"), detachedThreads, stackedOn, stacked}) | |
| 1820 | canWrite, unresolved, s.takeFlash(w, r), detachedThreads, stackedOn, stacked}) | |
| 1821 | 1821 | } |
| 1822 | 1822 | |
| 1823 | 1823 | func (s *Server) refs(w http.ResponseWriter, r *http.Request) { |