From 3aefbf7bd78594158af575a7512961e85b42e212 Mon Sep 17 00:00:00 2001 From: Vicente Ferrari Smith Date: Tue, 14 May 2024 15:45:09 +0000 Subject: [PATCH] added logout and others git-svn-id: svn://losandesgames.com/alfheim-website@4 15359d88-9307-4e75-a9c1-e5686e5897df --- account/index.html | 8 +-- base.html | 4 ++ handlers.go | 128 ++++++++++++++++++++++++++++----------------- login/index.html | 8 +-- logout/index.html | 11 ++++ main.go | 27 ++++++---- models/models.go | 3 +- 7 files changed, 122 insertions(+), 67 deletions(-) create mode 100644 logout/index.html diff --git a/account/index.html b/account/index.html index 98141cd..5d50e6e 100644 --- a/account/index.html +++ b/account/index.html @@ -1,8 +1,8 @@ {{define "body"}}
-
Username: {{.Username}}
-
First name: {{.Firstname}}
-
Last name: {{.Lastname}}
-
Color: {{.Color}}
+
Username: {{.Account.Username}}
+
First name: {{.Account.Firstname}}
+
Last name: {{.Account.Lastname}}
+
Color: {{.Account.Color}}
{{end}} diff --git a/base.html b/base.html index 7e336e7..50af8a3 100644 --- a/base.html +++ b/base.html @@ -19,8 +19,12 @@ diff --git a/handlers.go b/handlers.go index 4d4469b..5d4a14d 100644 --- a/handlers.go +++ b/handlers.go @@ -12,13 +12,33 @@ import "errors" import "runtime/debug" type templatedata struct { - Formerrors map[string]string + AuthenticatedUser int32 + FormErrors map[string]string + Account models.Account } func favicon(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "favicon.ico") } +func authenticated_user(r *http.Request) int32 { + session, err := store.Get(r, "id") + if err != nil { + fmt.Println(err) + return 0 + } + + id, ok := session.Values["id"].(int32) + if !ok { + trace := fmt.Sprintf("%s\n%s", errors.New("type assertion to int32 failed").Error(), debug.Stack()) + _ = trace + //log.Println(trace) + return 0 + } + + return id +} + func home(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r); @@ -34,16 +54,14 @@ func home(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: - err = text.Execute(w, true) + err = text.Execute(w, templatedata{}) if err != nil { log.Fatal(err) http.Error(w, "Internal Server Error", 500) } case http.MethodPost: - data := LoginData{username: r.FormValue("username"), password: r.FormValue("password")} - fmt.Println(data) - err = text.Execute(w, false) + err = text.Execute(w, templatedata{}) if err != nil { log.Fatal(err) http.Error(w, "Internal Server Error", 500) @@ -69,40 +87,66 @@ func login(w http.ResponseWriter, r *http.Request) { case http.MethodPost: session, _ := store.Get(r, "id"); - logindata := LoginData{username: r.FormValue("username"), password: r.FormValue("password")} - + password := r.FormValue("password") + username := r.FormValue("username") errors := make(map[string]string) - if strings.TrimSpace(logindata.username) == "" { + if strings.TrimSpace(username) == "" { errors["username"] = "This field cannot be blank" - } else if utf8.RuneCountInString(logindata.username) > 20 { + } else if utf8.RuneCountInString(username) > 20 { errors["username"] = "This field is too long (the maximum is 20 characters)" } - if strings.TrimSpace(logindata.password) == "" { + if strings.TrimSpace(password) == "" { errors["password"] = "This field cannot be blank" - } else if utf8.RuneCountInString(logindata.password) < 8 { + } else if utf8.RuneCountInString(password) < 8 { errors["password"] = "This field is too short (the minimum is 8 characters)" } if len(errors) > 0 { - text.Execute(w, templatedata{errors}) + text.Execute(w, templatedata{AuthenticatedUser: authenticated_user(r), FormErrors: errors}) if err != nil { log.Fatal(err) http.Error(w, "Internal Server Error", 500) } } - id, _ := users.Authenticate(logindata.username, logindata.password) + id, _ := users.Authenticate(username, password) if id > 0 { session.Values["id"] = id + fmt.Println("Logged in with id:", id) session.Save(r, w) http.Redirect(w, r, "/account", http.StatusSeeOther) } } } +func logout(w http.ResponseWriter, r *http.Request) { + text, err := template.ParseFiles("base.html", "logout/index.html") + if err != nil { + http.Error(w, "Internal Server Error", 500) + log.Fatal(err) + } + + switch r.Method { + case http.MethodGet: + + text.Execute(w, templatedata{}) + if err != nil { + log.Fatal(err) + http.Error(w, "Internal Server Error", 500) + } + + case http.MethodPost: + session, _ := store.Get(r, "id"); + + session.Values["id"] = 0; + session.Save(r, w) + http.Redirect(w, r, "/", http.StatusSeeOther) + } +} + func register(w http.ResponseWriter, r *http.Request) { text, err := template.ParseFiles("base.html", "register/index.html") if err != nil { @@ -138,22 +182,19 @@ func register(w http.ResponseWriter, r *http.Request) { if len(errors) > 0 { - text.Execute(w, templatedata{errors}) + text.Execute(w, templatedata{AuthenticatedUser: authenticated_user(r), FormErrors: errors}) if err != nil { log.Fatal(err) http.Error(w, "Internal Server Error", 500) } } - fmt.Println(account) - users.Insert(account.Username, string(account.Password), account.Firstname, account.Lastname, account.Email) http.Redirect(w, r, "/login", http.StatusSeeOther) } } func account(w http.ResponseWriter, r *http.Request) { - session, _ := store.Get(r, "id") //id, err := strconv.Atoi(r.URL.Query().Get("id")) //if err != nil || id < 1 { // http.NotFound(w, r) @@ -164,38 +205,29 @@ func account(w http.ResponseWriter, r *http.Request) { // log.Fatal(err); //} - id, ok := session.Values["id"].(int32) - if !ok { - trace := fmt.Sprintf("%s\n%s", errors.New("type assertion to int32 failed").Error(), debug.Stack()) - log.Println(trace) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - } else { - account, err := users.Get_account(id) - fmt.Println(account) + id := authenticated_user(r) + account, err := users.Get_account(id) - text, err := template.ParseFiles("base.html", "account/index.html") + text, err := template.ParseFiles("base.html", "account/index.html") - if err != nil { - http.Error(w, "Internal Server Error", 500) - log.Fatal(err) - } - - switch r.Method { - case http.MethodGet: - text.Execute(w, account) - if err != nil { - log.Fatal(err) - http.Error(w, "Internal Server Error", 500) - } - } - - //case http.MethodPost: - // data := LoginData{username: r.FormValue("username"), password: r.FormValue("password")} - // fmt.Println(data) - // text.Execute(w, false) - // if err != nil { - // log.Fatal(err) - // http.Error(w, "Internal Server Error", 500) - // } + if err != nil { + http.Error(w, "Internal Server Error", 500) + log.Fatal(err) } + + switch r.Method { + case http.MethodGet: + text.Execute(w, templatedata{AuthenticatedUser: id, Account: account}) + if err != nil { + log.Fatal(err) + http.Error(w, "Internal Server Error", 500) + } + } + + //case http.MethodPost: + // text.Execute(w, false) + // if err != nil { + // log.Fatal(err) + // http.Error(w, "Internal Server Error", 500) + // } } diff --git a/login/index.html b/login/index.html index 78ed925..8d3c3fe 100644 --- a/login/index.html +++ b/login/index.html @@ -3,20 +3,20 @@

Log in

- {{with .Formerrors.username}} + {{with .FormErrors.username}} {{end}} -
+

- {{with .Formerrors.password}} + {{with .FormErrors.password}} {{end}} -
+

diff --git a/logout/index.html b/logout/index.html new file mode 100644 index 0000000..690d0bc --- /dev/null +++ b/logout/index.html @@ -0,0 +1,11 @@ +{{define "body"}} +
+ +

Log out

+ + + +
+{{end}} diff --git a/main.go b/main.go index 8a7cb17..16e9a55 100644 --- a/main.go +++ b/main.go @@ -18,13 +18,7 @@ var store = sessions.NewCookieStore(key) var emailrx = regexp.MustCompile("/^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/"); -type LoginData struct { - username string - password string -} - - -func secureheaders(next http.Handler) http.Handler { +func secure_headers(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-XSS-Protection", "1; mode=block") w.Header().Set("X-Frame-Options", "deny") @@ -35,6 +29,20 @@ func secureheaders(next http.Handler) http.Handler { return http.HandlerFunc(fn) } +func require_authenticated_user(next http.HandlerFunc) http.HandlerFunc { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // If the user is not authenticated, redirect them to the login page and + // return from the middleware chain so that no subsequent handlers in + // the chain are executed. + if authenticated_user(r) == 0 { + http.Redirect(w, r, "/login", http.StatusSeeOther) + return + } + // Otherwise call the next handler in the chain. + next.ServeHTTP(w, r) + }) +} + func main() { addr := flag.String("addr", ":8080", "HTTP network address") flag.Parse() @@ -82,12 +90,13 @@ func main() { mux.HandleFunc("/", home) mux.HandleFunc("/login", login) + mux.HandleFunc("/logout", logout) mux.HandleFunc("/register", register) - mux.HandleFunc("/account", account) + mux.HandleFunc("/account", require_authenticated_user(account)) - log.Fatal(http.ListenAndServe(*addr, secureheaders(mux))) + log.Fatal(http.ListenAndServe(*addr, secure_headers(mux))) } //cookie := http.Cookie{ diff --git a/models/models.go b/models/models.go index 42c026b..8cc9f14 100644 --- a/models/models.go +++ b/models/models.go @@ -5,7 +5,7 @@ import "time" import "golang.org/x/crypto/bcrypt" import "database/sql" import _ "github.com/lib/pq" -import "fmt" +import _ "fmt" var Errnorecord = errors.New("no matching record found") var Errinvalidcredentials = errors.New("invalid credentials") @@ -44,7 +44,6 @@ func (m *Usermodel) Get_account(id int32) (Account, error) { row := m.DB.QueryRow(stmt, id) var account Account err := row.Scan(&account.Id, &account.Username, &account.Password, &account.Color, &account.Firstname, &account.Lastname, &account.Email, &account.Created) - fmt.Println(err) if err == sql.ErrNoRows { return Account{}, sql.ErrNoRows } else if err != nil {