Files
portfolio/main.go
2025-02-13 08:35:26 +01:00

115 lines
2.9 KiB
Go

package main
import (
_ "embed"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/a-h/templ"
"github.com/moh682/portfolio/components"
"github.com/moh682/portfolio/domain"
"github.com/moh682/portfolio/middlewares"
)
func templHandlerWithOptions(component templ.Component) http.Handler {
t := templ.Handler(component, templ.WithStatus(200), templ.WithContentType("text/html"))
log.Println("templHandlerWithOptions: ", t.Status)
return t
}
func rootHandler(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handler.ServeHTTP(w, r)
})
}
// SafeFileServer wraps http.FileServer to only serve specific file types from specific directories
func SafeFileServer(root http.FileSystem) http.Handler {
fileServer := http.FileServer(root)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Set security headers
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-XSS-Protection", "1; mode=block")
log.Println("path", r.URL.Path)
// Only allow specific file extensions
if allowed := func(path string) bool {
allowedExts := map[string]bool{
".js": true,
".css": true,
".png": true,
".jpg": true,
".jpeg": true,
".svg": true,
".ico": true,
}
for ext := range allowedExts {
if strings.HasSuffix(path, ext) {
return true
}
}
return false
}(r.URL.Path); !allowed {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
fileServer.ServeHTTP(w, r)
})
}
//go:embed assets/json/experiences.json
var embeddedExperiences []byte
//go:embed assets/json/projects.json
var embeddedProjects []byte
func main() {
server := http.NewServeMux()
// Serve static files with restrictions
staticFS := http.Dir("static")
server.Handle("GET /assets/", http.StripPrefix("/assets/", SafeFileServer(staticFS)))
server.Handle("GET /about", templHandlerWithOptions(components.AboutPage()))
var exps []domain.Experience
err := json.Unmarshal(embeddedExperiences, &exps)
if err != nil {
log.Panic(err)
}
server.Handle("GET /experiences", templHandlerWithOptions(components.ExperiencesPage(exps)))
var projects []domain.Project
err = json.Unmarshal(embeddedProjects, &projects)
if err != nil {
log.Panic(err)
}
server.Handle("GET /projects", templHandlerWithOptions(components.ProjectsPage(projects)))
server.Handle("GET /contact", templHandlerWithOptions(components.ContactPage()))
server.Handle("GET /{$}", templHandlerWithOptions(components.LandingPage()))
// 404 fallback page
server.Handle("GET /", templHandlerWithOptions(components.NotFound()))
// TODO: add Blogs to my portfolio website
// server.Handle("GET /blogs", templHandlerWithOptions(components.AboutPage()))
fmt.Println("Listening on :8080")
log.Panic(
http.ListenAndServe(":8080",
middlewares.Combine(
middlewares.Logger(server),
),
),
)
}