An experimental IndieWeb site built in Go.
1package main
2
3//go:generate templ generate
4//go:generate deno run --allow-all npm:tailwindcss -i config/main.css -o static/styles.css -c config/tailwind.config.js --minify
5
6import (
7 "os"
8 "time"
9
10 "log"
11 "net/http"
12 "strconv"
13
14 "github.com/puregarlic/space/handlers"
15 "github.com/puregarlic/space/storage"
16
17 "github.com/go-chi/chi/v5"
18 "github.com/go-chi/chi/v5/middleware"
19 "github.com/go-chi/cors"
20 "github.com/go-chi/httprate"
21
22 "go.hacdias.com/indielib/indieauth"
23
24 _ "github.com/joho/godotenv/autoload"
25)
26
27func main() {
28 port, profileURL := validateRuntimeConfiguration()
29 defer storage.CleanupAuthCache()
30
31 r := chi.NewRouter()
32
33 r.Use(middleware.RequestID)
34 r.Use(middleware.RealIP)
35 r.Use(middleware.Logger)
36 r.Use(middleware.Recoverer)
37 r.Use(httprate.LimitByIP(100, 1*time.Minute))
38
39 // CORS be enabled for browser-based agents to fetch `rel` elements.
40 // We'll enable it just on the root route since it should be used as the profile URL
41 r.With(cors.AllowAll().Handler).Get("/", handlers.ServeHomePage)
42
43 // Content pages
44 r.Get("/posts/{slug}", handlers.ServePostPage)
45
46 // Static asset handlers
47 r.Get("/media/*", handlers.ServeMedia)
48 r.Get("/static/*", http.StripPrefix(
49 "/static",
50 http.FileServer(http.Dir("static")),
51 ).ServeHTTP)
52
53 // Service handlers
54 handlers.AttachIndieAuth(r, "/authorization", profileURL)
55 handlers.AttachMicropub(r, "/micropub", profileURL)
56
57 // Start it!
58 log.Printf("Listening on http://localhost:%d", port)
59 log.Printf("Listening on %s", profileURL)
60 if err := http.ListenAndServe(":"+strconv.Itoa(port), r); err != nil {
61 log.Fatal(err)
62 }
63}
64
65func validateRuntimeConfiguration() (portNumber int, profileURL string) {
66 var port int
67 if portStr, ok := os.LookupEnv("PORT"); !ok {
68 port = 80
69 } else {
70 portInt, err := strconv.Atoi(portStr)
71 if err != nil {
72 log.Fatal(err)
73 }
74
75 port = portInt
76 }
77
78 profileURL, ok := os.LookupEnv("PROFILE_URL")
79 if !ok {
80 profileURL = "http://localhost/"
81 }
82
83 // Validate the given Client ID before starting the HTTP server.
84 err := indieauth.IsValidProfileURL(profileURL)
85 if err != nil {
86 log.Fatal(err)
87 }
88
89 return port, profileURL
90}