An OIDC-protected index page for your homeserver.
1package main
2
3import (
4 "embed"
5 "errors"
6 "log"
7 "log/slog"
8 "net/http"
9 "os"
10
11 _ "github.com/joho/godotenv/autoload"
12 gonanoid "github.com/matoous/go-nanoid/v2"
13 "github.com/sblinch/kdl-go"
14 "github.com/zitadel/logging"
15
16 "github.com/a-h/templ"
17
18 "ladon/auth"
19 "ladon/views"
20)
21
22//go:embed static
23var content embed.FS
24
25func ServeRoot(am *auth.AuthManager) http.Handler {
26 f, err := os.Open("./data/links.kdl")
27 if err != nil {
28 am.Log.Error("ladon: failed to open KDL config")
29 panic(err)
30 }
31
32 doc, err := kdl.Parse(f)
33 if err != nil {
34 am.Log.Error("ladon: failed to pase KDL config")
35 panic(err)
36 }
37
38 return http.HandlerFunc(
39 func(w http.ResponseWriter, r *http.Request) {
40 claims, err := am.GetSession(r)
41
42 if errors.Is(err, auth.ErrNoSession) {
43 templ.Handler(views.Authenticate()).ServeHTTP(w, r)
44 return
45 } else if errors.Is(err, auth.ErrSessionExpired) {
46 am.DeleteSession(w)
47 am.HandleLogin().ServeHTTP(w, r)
48 return
49 } else if err != nil {
50 http.Error(w, err.Error(), http.StatusInternalServerError)
51 return
52 }
53
54 templ.Handler(views.Links(claims.PreferredUsername, doc)).ServeHTTP(w, r)
55 },
56 )
57}
58
59func main() {
60 logger := slog.New(
61 slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
62 AddSource: true,
63 Level: slog.LevelDebug,
64 }),
65 )
66
67 am := auth.NewAuthManager(logger)
68
69 // Handle static assets
70 fs := http.FileServer(http.FS(content))
71 http.Handle("/static/", fs)
72
73 // Serve pages
74 http.Handle("/", ServeRoot(am))
75
76 // Handle authentication
77 http.Handle("/login", am.HandleLogin())
78 http.Handle("/logout", am.HandleLogout())
79 http.Handle("/callback", am.HandleCallback())
80
81 mw := logging.Middleware(
82 logging.WithLogger(logger),
83 logging.WithGroup("server"),
84 logging.WithIDFunc(func() slog.Attr {
85 return slog.String("id", gonanoid.Must())
86 }),
87 )
88
89 log.Println("Listening on port 4000")
90 if err := http.ListenAndServe(":4000", mw(http.DefaultServeMux)); err != nil {
91 panic(err)
92 }
93}