147 lines
2.8 KiB
Go
147 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)
|
||
|
}
|