Login fully working (via HTMX and Cookies)
Moved code bits around for more Exported functions Fixed JWT validation
This commit is contained in:
@@ -15,7 +15,7 @@ import (
|
|||||||
var editorFS embed.FS
|
var editorFS embed.FS
|
||||||
|
|
||||||
const loginPage = `
|
const loginPage = `
|
||||||
<form id="loginForm" hx-post="/login">
|
<form id="loginForm" hx-post="/login" hx-target="#formResult">
|
||||||
<label for="username">Username:</label>
|
<label for="username">Username:</label>
|
||||||
<input name="username" id="usernameInput" onkeydown="return event.key != 'Enter';"></input>
|
<input name="username" id="usernameInput" onkeydown="return event.key != 'Enter';"></input>
|
||||||
<label for="password">Password:</label>
|
<label for="password">Password:</label>
|
||||||
@@ -25,19 +25,25 @@ const loginPage = `
|
|||||||
</form>
|
</form>
|
||||||
`
|
`
|
||||||
|
|
||||||
func LoginPage(w http.ResponseWriter, r *http.Request) {
|
func loginPageRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
sendContent(w, r, loginPage, "", "")
|
sendContent(w, r, loginPage, "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TrueLogin(w http.ResponseWriter, r *http.Request) {
|
func trueLoginRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Header.Get("HX-Request") != "true" {
|
if r.Header.Get("HX-Request") != "true" {
|
||||||
sendContent(w, r, "<p>Bad request</p>", "", "")
|
sendContent(w, r, "<p>Bad request</p>", "", "")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
u, err := back.TryLogin(r.Context(), r.URL.Query().Get("username"), r.URL.Query().Get("password"))
|
err := r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
sendContent(w, r, "<p>Bad request</p>", "", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u, err := back.TryLogin(r.Context(), r.FormValue("username"), r.FormValue("password"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == backend.ErrLoginTimeout {
|
if err == backend.ErrLoginTimeout {
|
||||||
sendContent(w, r, fmt.Sprint("<p>Timed out for", time.Unix(u.Timeout, 0).Sub(time.Now()), "</p>"), "", "")
|
sendContent(w, r, fmt.Sprint("<p>Timed out for", time.Unix(u.Timeout, 0).Sub(time.Now()), "</p>"), "", "")
|
||||||
} else if err == backend.ErrLoginTimeout {
|
} else if err == backend.ErrLoginIncorrect {
|
||||||
sendContent(w, r, "<p>Username or password invalid</p>", "", "")
|
sendContent(w, r, "<p>Username or password invalid</p>", "", "")
|
||||||
} else {
|
} else {
|
||||||
log.Println("error trying to login:", err)
|
log.Println("error trying to login:", err)
|
||||||
@@ -55,10 +61,9 @@ func TrueLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
sendContent(w, r, "<p hx-get='/editor' hx-push-url='true' hx-trigger='load' hx-target='#content'>Successful Login</p>", "", "")
|
sendContent(w, r, "<p hx-get='/editor' hx-push-url='true' hx-trigger='load' hx-target='#content'>Successful Login</p>", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Editor(w http.ResponseWriter, r *http.Request) {
|
func editorRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
authCookie, err := r.Cookie("blogAuthToken")
|
authCookie, err := r.Cookie("blogAuthToken")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
if err != http.ErrNoCookie {
|
if err != http.ErrNoCookie {
|
||||||
log.Println("error getting auth cookie:", err)
|
log.Println("error getting auth cookie:", err)
|
||||||
}
|
}
|
||||||
@@ -67,7 +72,6 @@ func Editor(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
usr, err := back.VerifyUser(r.Context(), authCookie.Value)
|
usr, err := back.VerifyUser(r.Context(), authCookie.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
if err != backend.ErrTokenUnauthorized {
|
if err != backend.ErrTokenUnauthorized {
|
||||||
log.Println("error authorizing JWT token:", err)
|
log.Println("error authorizing JWT token:", err)
|
||||||
}
|
}
|
||||||
@@ -95,5 +99,5 @@ func editorRedirect(w http.ResponseWriter, r *http.Request, path string) {
|
|||||||
w.Header().Set("HX-Location", `{"path": "`+path+`", "target":"#content"}`)
|
w.Header().Set("HX-Location", `{"path": "`+path+`", "target":"#content"}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "https://darkstorm.tech"+path, http.StatusSeeOther)
|
http.Redirect(w, r, "https://darkstorm.tech"+path, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func (b *Backend) ParseHeader(r *http.Request) (*ParsedHeader, error) {
|
|||||||
if apiKey.Death > 0 && time.Unix(apiKey.Death, 0).Before(time.Now()) {
|
if apiKey.Death > 0 && time.Unix(apiKey.Death, 0).Before(time.Now()) {
|
||||||
return nil, ErrApiKeyUnauthorized
|
return nil, ErrApiKeyUnauthorized
|
||||||
}
|
}
|
||||||
out.Key = apiKey
|
out.Key = &apiKey
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("origin:", r.Header.Get("origin"))
|
fmt.Println("origin:", r.Header.Get("origin"))
|
||||||
keys, err := b.keyTable.Find(r.Context(), map[string]any{"allowedOrigins": r.Header.Get("origin")})
|
keys, err := b.keyTable.Find(r.Context(), map[string]any{"allowedOrigins": r.Header.Get("origin")})
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ func (b *Backend) GenerateJWT(r *ReqestUser) (string, error) {
|
|||||||
return "", errors.New("user management not enabled")
|
return "", errors.New("user management not enabled")
|
||||||
}
|
}
|
||||||
return jwt.NewWithClaims(jwt.SigningMethodEdDSA, jwt.RegisteredClaims{
|
return jwt.NewWithClaims(jwt.SigningMethodEdDSA, jwt.RegisteredClaims{
|
||||||
ID: r.ID,
|
|
||||||
Issuer: "darkstorm.tech",
|
Issuer: "darkstorm.tech",
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(12 * time.Hour)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(12 * time.Hour)),
|
||||||
|
Subject: r.ID,
|
||||||
}).SignedString(b.jwtPriv)
|
}).SignedString(b.jwtPriv)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ func (b *Backend) TryLogin(ctx context.Context, username, password string) (User
|
|||||||
if err == ErrNotFound {
|
if err == ErrNotFound {
|
||||||
return User{}, ErrLoginIncorrect
|
return User{}, ErrLoginIncorrect
|
||||||
}
|
}
|
||||||
if len(users) > 0 {
|
if len(users) > 1 {
|
||||||
log.Println("duplicate username detected, fix immediately:", username)
|
log.Println("duplicate username detected, fix immediately:", username)
|
||||||
}
|
}
|
||||||
user := users[0]
|
user := users[0]
|
||||||
@@ -106,7 +106,7 @@ func (b *Backend) VerifyUser(ctx context.Context, token string) (*User, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
usr, err := b.userTable.Get(ctx, sub)
|
usr, err := b.userTable.Get(ctx, sub)
|
||||||
if err == jwt.ErrInvalidKey {
|
if err == ErrNotFound {
|
||||||
return nil, ErrTokenUnauthorized
|
return nil, ErrTokenUnauthorized
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -120,7 +120,7 @@ func (b *Backend) VerifyUser(ctx context.Context, token string) (*User, error) {
|
|||||||
if usr.PasswordChange > 0 && iss.Time.Before(time.Unix(usr.PasswordChange, 0)) {
|
if usr.PasswordChange > 0 && iss.Time.Before(time.Unix(usr.PasswordChange, 0)) {
|
||||||
return nil, ErrTokenUnauthorized
|
return nil, ErrTokenUnauthorized
|
||||||
}
|
}
|
||||||
return usr, nil
|
return &usr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUser(username, password, email string) (User, error) {
|
func NewUser(username, password, email string) (User, error) {
|
||||||
|
|||||||
@@ -147,13 +147,12 @@ func setupWebsite(mux *http.ServeMux) {
|
|||||||
url, _ := url.Parse("https://localhost:30000")
|
url, _ := url.Parse("https://localhost:30000")
|
||||||
mux.Handle("rpg.darkstorm.tech/", httputil.NewSingleHostReverseProxy(url))
|
mux.Handle("rpg.darkstorm.tech/", httputil.NewSingleHostReverseProxy(url))
|
||||||
}
|
}
|
||||||
edit := NewBlogEditor(blogApp, back)
|
|
||||||
mux.HandleFunc("GET /files/{w...}", filesRequest)
|
mux.HandleFunc("GET /files/{w...}", filesRequest)
|
||||||
mux.HandleFunc("GET /portfolio", portfolioRequest)
|
mux.HandleFunc("GET /portfolio", portfolioRequest)
|
||||||
mux.HandleFunc("GET /list", blogListHandle)
|
mux.HandleFunc("GET /list", blogListHandle)
|
||||||
mux.HandleFunc("GET /login", edit.LoginPage)
|
mux.HandleFunc("GET /login", loginPageRequest)
|
||||||
mux.HandleFunc("GET /editor", edit.Editor)
|
mux.HandleFunc("GET /editor/", editorRequest)
|
||||||
mux.HandleFunc("POST /login", edit.TrueLogin)
|
mux.HandleFunc("POST /login", trueLoginRequest)
|
||||||
mux.HandleFunc("/", mainHandle)
|
mux.HandleFunc("/", mainHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user