rpg/main.go
2024-09-03 22:34:04 +03:00

146 lines
2.8 KiB
Go

package main
import (
"crypto/rand"
"database/sql"
"encoding/base64"
"sync"
_ "github.com/lib/pq"
"fmt"
"net/http"
)
type UserSession struct {
AccountIDX int
Username string
}
type PageData struct {
session *UserSession
}
var sessionsMutex sync.Mutex
var sessions = map[string]*UserSession{}
var db *sql.DB
func SendError(w http.ResponseWriter, r *http.Request, code int) {
w.WriteHeader(code)
errorString := fmt.Sprintf("Error %d", code)
page := tPage(tError(errorString))
page.Render(r.Context(), w)
}
func AttemptCookieAuth(req *http.Request) *UserSession {
cookie, err := req.Cookie("session")
if err != nil {
return nil
}
sessionsMutex.Lock()
session := sessions[cookie.Value]
sessionsMutex.Unlock()
return session
}
func RootHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
SendError(w, r, http.StatusBadRequest)
return
}
session := AttemptCookieAuth(r)
if session != nil {
page := tPage(tHello(session))
page.Render(r.Context(), w)
return
} else {
page := tPage(tLoginForm(""))
page.Render(r.Context(), w)
return
}
}
func LoginHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
SendError(w, r, http.StatusBadRequest)
return
}
err := r.ParseForm()
if err != nil {
SendError(w, r, http.StatusBadRequest)
return
}
session := AttemptCookieAuth(r)
if session != nil {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
username := r.FormValue("username")
password := r.FormValue("password")
loginResult, err := DBLogin(username, password)
if err != nil {
loginForm := tLoginForm("Invalid username or password")
page := tPage(loginForm)
page.Render(r.Context(), w)
return
}
var cookieBytes [24]byte
rand.Read(cookieBytes[:])
cookie := base64.URLEncoding.EncodeToString(cookieBytes[:])
session = &UserSession{
AccountIDX: loginResult.Idx,
Username: username,
}
sessionsMutex.Lock()
sessions[cookie] = session
sessionsMutex.Unlock()
http.SetCookie(w, &http.Cookie{
Name: "session",
Value: cookie,
HttpOnly: true,
Path: "/",
})
pageContents := tHello(session)
page := tPage(pageContents)
page.Render(r.Context(), w)
}
func main() {
var err error
conninfo := "host=localhost user=postgres password=work dbname=rpg sslmode=disable"
listenEndpoint := "localhost:8000"
db, err = sql.Open("postgres", conninfo)
if err != nil {
panic(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err)
}
fmt.Println("Connected to database")
http.HandleFunc("/login", LoginHandler)
http.HandleFunc("/", RootHandler)
fmt.Printf("Listening on %s\n", listenEndpoint)
http.ListenAndServe(listenEndpoint, nil)
}