diff --git a/pkg/core/const.go b/pkg/core/const.go index cbf6123..f3af341 100644 --- a/pkg/core/const.go +++ b/pkg/core/const.go @@ -8,6 +8,7 @@ const ( IndexURI = WikiSection + "/" + IndexPage - LoginURI = "/login" - TotpURI = "/totp" + LoginURI = "/login" + LogoutURI = "/logout" + TotpURI = "/totp" ) diff --git a/pkg/server/context.go b/pkg/server/context.go index deb264d..cefdcf1 100644 --- a/pkg/server/context.go +++ b/pkg/server/context.go @@ -10,6 +10,7 @@ import ( "github.com/gorilla/mux" "html/template" "net/http" + "net/url" "time" ) @@ -23,6 +24,7 @@ const ( titleClaim = "title" totpClaim = "totp" rememberClaim = "remember" + refererClaim = "referer" ) func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) (ctx *Context) { @@ -30,7 +32,8 @@ func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) (ctx *Con h.Set("X-Frame-Options", "DENY") h.Set("X-Content-Type-Options", "nosniff") h.Set("X-XSS-Protection", "1; mode=block") - h.Set("Content-Security-Policy", "default-src 'none';style-src 'self';img-src 'self' data:;frame-ancestors 'none'") + h.Set("Content-Security-Policy", "default-src 'none';style-src 'self';img-src 'self' https: data:;connect-src 'self';frame-ancestors 'none'") + h.Set("Referrer-Policy", "same-origin") ctx = &Context{ Request: r, Response: w, @@ -53,7 +56,7 @@ func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) (ctx *Con return } if t.Claims.GetString(totpClaim) != "" { - if path == core.TotpURI || path == core.LoginURI { + if path == core.TotpURI || path == core.LoginURI || path == core.LogoutURI { ctx.Token = *t return } @@ -107,6 +110,11 @@ type webData struct { Data interface{} } +type loginData struct { + User string + Referer string +} + func (c *Context) Exec() { defer c.log() if c.T == nil { @@ -201,6 +209,14 @@ func (c *Context) Path() string { return c.Request.URL.Path } +func (c *Context) RefererURI() string { + u, err := url.Parse(c.Request.Header.Get("Referer")) + if err != nil { + return "" + } + return u.RequestURI() +} + func (c *Context) FormSlice(name string) []string { // does nothing if called twice c.Request.ParseForm() @@ -286,6 +302,10 @@ func (c *Context) Remember() string { return c.Token.Claims.GetString(rememberClaim) } +func (c *Context) Referer() string { + return c.Token.Claims.GetString(refererClaim) +} + func (c *Context) Admin() bool { return c.Token.Claims.GetBool(adminClaim) } diff --git a/pkg/server/handler.go b/pkg/server/handler.go index f4718f5..9a5866f 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -93,23 +93,28 @@ func loginHandler(ctx *Context) { Title: "Login", BodyTitle: "Login", } - var user string + var data loginData switch ctx.Method() { case "GET": - ctx.Data.Data = user + data.Referer = ctx.RefererURI() + ctx.Data.Data = data ctx.Exec() case "POST": if !ctx.CheckXsrf() { return } - user = ctx.Form("user") - ctx.Data.Data = user + data.User = ctx.Form("user") + data.Referer = ctx.Form("referer") + ctx.Data.Data = data + if data.Referer == "" { + data.Referer = core.IndexURI + } password := ctx.Form("password") - if user == "" || password == "" { + if data.User == "" || password == "" { ctx.Error("empty user or password") return } - u, err := ctx.Srv.DB.Login(user, password) + u, err := ctx.Srv.DB.Login(data.User, password) if err != nil { ctx.Error(err) return @@ -117,12 +122,13 @@ func loginHandler(ctx *Context) { if u.Secret == "" { log.Println("login:", u.Username) ctx.Login(u, ctx.Form("remember")) - ctx.Redirect(core.IndexURI, http.StatusFound) + ctx.Redirect(data.Referer, http.StatusFound) return } ctx.SetCookie(jwt.Claims{ totpClaim: u.Username, rememberClaim: ctx.Form("remember"), + refererClaim: data.Referer, }, time.Minute) ctx.Redirect(core.TotpURI, http.StatusFound) } @@ -155,9 +161,10 @@ func loginTotpHandler(ctx *Context) { ctx.Error(err) return } + ref := ctx.Referer() log.Println("login:", u.Username) ctx.Login(u, ctx.Remember()) - ctx.Redirect(core.IndexURI, http.StatusFound) + ctx.Redirect(ref, http.StatusFound) } } @@ -682,7 +689,11 @@ func userDelHandler(ctx *Context) { } func logoutHandler(ctx *Context) { - log.Println("logout:", ctx.User()) + user := ctx.User() + if user == "" { + user = ctx.Totp() + " (totp)" + } + log.Println("logout:", user) ctx.Srv.JWT.Invalidate(&ctx.Token) ctx.SetCookie(nil, 0) ctx.Redirect(core.IndexURI, http.StatusFound) diff --git a/pkg/server/templates.go b/pkg/server/templates.go index 972c6cd..6f26004 100644 --- a/pkg/server/templates.go +++ b/pkg/server/templates.go @@ -66,6 +66,8 @@ const ( GoWiki | {{.Title}} + + diff --git a/templates/index.html b/templates/index.html index 938db14..e2fb677 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,6 +4,8 @@ GoWiki | {{.Title}} + +