added login referer
This commit is contained in:
parent
2e70a95bcd
commit
4e5d554105
7 changed files with 55 additions and 15 deletions
|
|
@ -8,6 +8,7 @@ const (
|
||||||
|
|
||||||
IndexURI = WikiSection + "/" + IndexPage
|
IndexURI = WikiSection + "/" + IndexPage
|
||||||
|
|
||||||
LoginURI = "/login"
|
LoginURI = "/login"
|
||||||
TotpURI = "/totp"
|
LogoutURI = "/logout"
|
||||||
|
TotpURI = "/totp"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -23,6 +24,7 @@ const (
|
||||||
titleClaim = "title"
|
titleClaim = "title"
|
||||||
totpClaim = "totp"
|
totpClaim = "totp"
|
||||||
rememberClaim = "remember"
|
rememberClaim = "remember"
|
||||||
|
refererClaim = "referer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) (ctx *Context) {
|
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-Frame-Options", "DENY")
|
||||||
h.Set("X-Content-Type-Options", "nosniff")
|
h.Set("X-Content-Type-Options", "nosniff")
|
||||||
h.Set("X-XSS-Protection", "1; mode=block")
|
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{
|
ctx = &Context{
|
||||||
Request: r,
|
Request: r,
|
||||||
Response: w,
|
Response: w,
|
||||||
|
|
@ -53,7 +56,7 @@ func newContext(w http.ResponseWriter, r *http.Request, s *HTTPServer) (ctx *Con
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Claims.GetString(totpClaim) != "" {
|
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
|
ctx.Token = *t
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -107,6 +110,11 @@ type webData struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type loginData struct {
|
||||||
|
User string
|
||||||
|
Referer string
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) Exec() {
|
func (c *Context) Exec() {
|
||||||
defer c.log()
|
defer c.log()
|
||||||
if c.T == nil {
|
if c.T == nil {
|
||||||
|
|
@ -201,6 +209,14 @@ func (c *Context) Path() string {
|
||||||
return c.Request.URL.Path
|
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 {
|
func (c *Context) FormSlice(name string) []string {
|
||||||
// does nothing if called twice
|
// does nothing if called twice
|
||||||
c.Request.ParseForm()
|
c.Request.ParseForm()
|
||||||
|
|
@ -286,6 +302,10 @@ func (c *Context) Remember() string {
|
||||||
return c.Token.Claims.GetString(rememberClaim)
|
return c.Token.Claims.GetString(rememberClaim)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) Referer() string {
|
||||||
|
return c.Token.Claims.GetString(refererClaim)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) Admin() bool {
|
func (c *Context) Admin() bool {
|
||||||
return c.Token.Claims.GetBool(adminClaim)
|
return c.Token.Claims.GetBool(adminClaim)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,23 +93,28 @@ func loginHandler(ctx *Context) {
|
||||||
Title: "Login",
|
Title: "Login",
|
||||||
BodyTitle: "Login",
|
BodyTitle: "Login",
|
||||||
}
|
}
|
||||||
var user string
|
var data loginData
|
||||||
switch ctx.Method() {
|
switch ctx.Method() {
|
||||||
case "GET":
|
case "GET":
|
||||||
ctx.Data.Data = user
|
data.Referer = ctx.RefererURI()
|
||||||
|
ctx.Data.Data = data
|
||||||
ctx.Exec()
|
ctx.Exec()
|
||||||
case "POST":
|
case "POST":
|
||||||
if !ctx.CheckXsrf() {
|
if !ctx.CheckXsrf() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user = ctx.Form("user")
|
data.User = ctx.Form("user")
|
||||||
ctx.Data.Data = user
|
data.Referer = ctx.Form("referer")
|
||||||
|
ctx.Data.Data = data
|
||||||
|
if data.Referer == "" {
|
||||||
|
data.Referer = core.IndexURI
|
||||||
|
}
|
||||||
password := ctx.Form("password")
|
password := ctx.Form("password")
|
||||||
if user == "" || password == "" {
|
if data.User == "" || password == "" {
|
||||||
ctx.Error("empty user or password")
|
ctx.Error("empty user or password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u, err := ctx.Srv.DB.Login(user, password)
|
u, err := ctx.Srv.DB.Login(data.User, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
return
|
return
|
||||||
|
|
@ -117,12 +122,13 @@ func loginHandler(ctx *Context) {
|
||||||
if u.Secret == "" {
|
if u.Secret == "" {
|
||||||
log.Println("login:", u.Username)
|
log.Println("login:", u.Username)
|
||||||
ctx.Login(u, ctx.Form("remember"))
|
ctx.Login(u, ctx.Form("remember"))
|
||||||
ctx.Redirect(core.IndexURI, http.StatusFound)
|
ctx.Redirect(data.Referer, http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SetCookie(jwt.Claims{
|
ctx.SetCookie(jwt.Claims{
|
||||||
totpClaim: u.Username,
|
totpClaim: u.Username,
|
||||||
rememberClaim: ctx.Form("remember"),
|
rememberClaim: ctx.Form("remember"),
|
||||||
|
refererClaim: data.Referer,
|
||||||
}, time.Minute)
|
}, time.Minute)
|
||||||
ctx.Redirect(core.TotpURI, http.StatusFound)
|
ctx.Redirect(core.TotpURI, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
@ -155,9 +161,10 @@ func loginTotpHandler(ctx *Context) {
|
||||||
ctx.Error(err)
|
ctx.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ref := ctx.Referer()
|
||||||
log.Println("login:", u.Username)
|
log.Println("login:", u.Username)
|
||||||
ctx.Login(u, ctx.Remember())
|
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) {
|
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.Srv.JWT.Invalidate(&ctx.Token)
|
||||||
ctx.SetCookie(nil, 0)
|
ctx.SetCookie(nil, 0)
|
||||||
ctx.Redirect(core.IndexURI, http.StatusFound)
|
ctx.Redirect(core.IndexURI, http.StatusFound)
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ const (
|
||||||
<title>GoWiki | {{.Title}}</title>
|
<title>GoWiki | {{.Title}}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
||||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-/SZfW8eVqFuioMg+QXacvK1Zc3XLtT5LGu9tMle65Jc="></link>
|
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-/SZfW8eVqFuioMg+QXacvK1Zc3XLtT5LGu9tMle65Jc="></link>
|
||||||
|
<meta name="theme-color" content="#375a7f">
|
||||||
|
<meta name="description" content="{{.Title}}">
|
||||||
</head>
|
</head>
|
||||||
<body id="top">
|
<body id="top">
|
||||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||||
|
|
@ -114,9 +116,10 @@ const (
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="form-horizontal" action="/login" method="post">
|
<form class="form-horizontal" action="/login" method="post">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
|
<input type="hidden" name="referer" value="{{.Data.Referer}}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="user">Username</label>
|
<label class="col-form-label" for="user">Username</label>
|
||||||
<input class="form-control input-sm" type="text" id="user" name="user" value="{{.Data}}" autofocus required>
|
<input class="form-control input-sm" type="text" id="user" name="user" value="{{.Data.User}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="password">Password</label>
|
<label class="col-form-label" for="password">Password</label>
|
||||||
|
|
@ -152,6 +155,7 @@ const (
|
||||||
<input class="form-control input-sm" type="text" id="pin" name="pin" autocomplete="off" autofocus required>
|
<input class="form-control input-sm" type="text" id="pin" name="pin" autocomplete="off" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Verify</button>
|
<button class="btn btn-sm btn-primary" type="submit">Verify</button>
|
||||||
|
<a href="/logout" class="btn btn-sm btn-primary">Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
<title>GoWiki | {{.Title}}</title>
|
<title>GoWiki | {{.Title}}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
<link rel="stylesheet" type="text/css" href="/bootstrap.css" media="screen" integrity="sha256-NeLmQ7cX66J4MdtgGlG3O/TgvsSyP1b9WbaQtxYZUbQ="></link>
|
||||||
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-/SZfW8eVqFuioMg+QXacvK1Zc3XLtT5LGu9tMle65Jc="></link>
|
<link rel="stylesheet" type="text/css" href="/custom.css" media="screen" integrity="sha256-/SZfW8eVqFuioMg+QXacvK1Zc3XLtT5LGu9tMle65Jc="></link>
|
||||||
|
<meta name="theme-color" content="#375a7f">
|
||||||
|
<meta name="description" content="{{.Title}}">
|
||||||
</head>
|
</head>
|
||||||
<body id="top">
|
<body id="top">
|
||||||
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
<div class="navbar navbar-expand fixed-top navbar-dark bg-primary">
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,10 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="form-horizontal" action="/login" method="post">
|
<form class="form-horizontal" action="/login" method="post">
|
||||||
<input type="hidden" name="token" value="{{.Token}}">
|
<input type="hidden" name="token" value="{{.Token}}">
|
||||||
|
<input type="hidden" name="referer" value="{{.Data.Referer}}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="user">Username</label>
|
<label class="col-form-label" for="user">Username</label>
|
||||||
<input class="form-control input-sm" type="text" id="user" name="user" value="{{.Data}}" autofocus required>
|
<input class="form-control input-sm" type="text" id="user" name="user" value="{{.Data.User}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-form-label" for="password">Password</label>
|
<label class="col-form-label" for="password">Password</label>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
<input class="form-control input-sm" type="text" id="pin" name="pin" autocomplete="off" autofocus required>
|
<input class="form-control input-sm" type="text" id="pin" name="pin" autocomplete="off" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" type="submit">Verify</button>
|
<button class="btn btn-sm btn-primary" type="submit">Verify</button>
|
||||||
|
<a href="/logout" class="btn btn-sm btn-primary">Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue