Files
Hyperia/server/main.go
metacryst faf2041b7f signins
2025-09-30 17:44:39 -05:00

147 lines
3.2 KiB
Go

package main
import (
"fmt"
"net/http"
"path/filepath"
"hyperia/config"
"hyperia/db"
"hyperia/handlers"
"hyperia/logger"
// "runtime/debug"
"strings"
"github.com/golang-jwt/jwt/v5"
"github.com/rs/zerolog/log"
)
func main() {
config.SetConfiguration()
logger.ConfigureLogger()
err := db.InitDB()
if err != nil {
log.Fatal().Msgf("failed to connect to database: %v", err)
} else {
log.Info().Msg("successfully connected to PostgreSQL")
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Keeps server from crashing if a request fails
// defer func() {
// if r := recover(); r != nil {
// log.Error().
// Interface("panic_reason", r).
// Bytes("stack_trace", debug.Stack()).
// Msg("panic in http goroutine")
// }
// }()
if(loggedIn(w, r)) {
log.Info().Msg("logged")
handleSite(w, r)
} else {
handlePublic(w, r)
}
})
log.Info().Msgf("Server starting on http://localhost: %s", config.PORT)
err = http.ListenAndServe(":"+config.PORT, nil)
if err != nil {
log.Fatal().Msgf("failed to start server: %v", err)
}
}
func handlePublic(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/signup" {
handlers.HandleSignup(w, r)
return
}
if r.URL.Path == "/api/login" {
handlers.HandleLogin(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/_") {
handleAsset(w, r)
return
}
servePublicFile(w, r)
}
func servePublicFile(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if path == "/" {
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
path = "/index.html"
} else if !strings.Contains(path, ".") {
path = filepath.Join("/pages", path) + ".html"
}
filePath := filepath.Join("../ui/public", path)
log.Debug().Msgf("serving: %s", filePath)
http.ServeFile(w, r, filePath)
}
func handleSite(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/signout" {
handlers.HandleLogout(w, r)
return
}
if strings.HasPrefix(r.URL.Path, "/_") {
handleAsset(w, r)
return
}
serveSiteFiles(w, r)
}
func serveSiteFiles(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if path == "/" {
path = "/index.html"
} else if !strings.Contains(path, ".") {
path = filepath.Join("/pages", path) + ".html"
}
filePath := filepath.Join("../ui/site", path)
log.Debug().Msgf("serving: %s", filePath)
http.ServeFile(w, r, filePath)
}
func handleAsset(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
filePath := filepath.Join("../ui", path)
log.Debug().Msgf("serving asset: %s", filePath)
http.ServeFile(w, r, filePath)
}
func loggedIn(w http.ResponseWriter, r *http.Request) bool {
cookie, err := r.Cookie("auth_token")
if err != nil {
log.Warn().Msg("Unauthorized - missing auth token")
return false
}
jwtToken := cookie.Value
token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(config.JWT_SECRET), nil
})
if err != nil {
log.Err(err).Msg("error authenticating jwt")
return false
}
if err != nil || !token.Valid {
return false
}
return true
}