package main import ( "context" "log" "net/http" "git.tuxpa.in/a/gosora/common" "git.tuxpa.in/a/gosora/routes" "git.tuxpa.in/a/gosora/routes/panel" "git.tuxpa.in/a/gosora/uutils" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) type ContextKey string var ContextKey_USER ContextKey = "gosora_user" var ContextKey_EXTRADATA ContextKey = "gosora_extradata" func AuthContextMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user_copy, ok := common.PreRoute(w, r) if !ok { return } user := &user_copy ctx := context.WithValue(r.Context(), ContextKey_USER, user) next.ServeHTTP(w, r.WithContext(ctx)) }) } func ParseFormMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { u, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := common.ParseForm(w, r, u) if err != nil { log.Println("error parsing form middleware") return } next.ServeHTTP(w, r) }) } func NoBannedMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := common.NoBanned(w, r, user) if err != nil { log.Println(err) return } next.ServeHTTP(w, r) }) } func NoSessionMismatchMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := common.NoSessionMismatch(w, r, user) if err != nil { log.Println(err) return } next.ServeHTTP(w, r) }) } func MemberOnlyMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := common.MemberOnly(w, r, user) if err != nil { log.Println(err) return } next.ServeHTTP(w, r) }) } func SuperModOnlyMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := common.SuperModOnly(w, r, user) if err != nil { log.Println(err) return } next.ServeHTTP(w, r) }) } func SuperAdminOnlyMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := common.SuperAdminOnly(w, r, user) if err != nil { log.Println(err) return } next.ServeHTTP(w, r) }) } type UserRoute = func(w http.ResponseWriter, r *http.Request, u *common.User) common.RouteError type ExtraRoute = func(w http.ResponseWriter, r *http.Request, u *common.User, s string) common.RouteError type HeaderRoute = func(w http.ResponseWriter, r *http.Request, u *common.User, h *common.Header) common.RouteError type HeaderExtraRoute = func(w http.ResponseWriter, r *http.Request, u *common.User, h *common.Header, s string) common.RouteError func ConvertUserRoute(fn UserRoute) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { u, ok := r.Context().Value(ContextKey_USER).(*common.User) if !ok { log.Println("error grabbing user from context") return } err := fn(w, r, u) if err != nil { log.Println("error handling %s %s", fn, err) } }) } func ConvertHeaderRoute(fn HeaderRoute) http.HandlerFunc { return ConvertUserRoute(func(w http.ResponseWriter, r *http.Request, u *common.User) common.RouteError { h, err := common.UserCheckNano(w, r, u, uutils.Nanotime()) if err != nil { return err } return fn(w, r, u, h) }) } func ConvertExtraRoute(fn ExtraRoute) http.HandlerFunc { return ConvertUserRoute(func(w http.ResponseWriter, r *http.Request, u *common.User) common.RouteError { s := chi.URLParam(r, "extra") return fn(w, r, u, s) }) } func ConvertHeaderExtraRoute(fn HeaderExtraRoute) http.HandlerFunc { return ConvertHeaderRoute(func(w http.ResponseWriter, r *http.Request, u *common.User, h *common.Header) common.RouteError { s := chi.URLParam(r, "extra") return fn(w, r, u, h, s) }) } func NewChiRouter() { r := chi.NewRouter() // A good base middleware stack r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(AuthContextMiddleware) r.Route("/overview", func(r chi.Router) { r.Get("/", ConvertHeaderRoute(routes.Overview)) }) r.Route("/pages", func(r chi.Router) { r.Get("/{extra}", ConvertHeaderExtraRoute(routes.CustomPage)) }) r.Route("/forums", func(r chi.Router) { r.Get("/", ConvertHeaderRoute(routes.ForumList)) }) r.Route("/forum", func(r chi.Router) { r.Get("/{extra}", ConvertHeaderExtraRoute(routes.ViewForum)) }) r.Route("/theme", func(r chi.Router) { r.Use(ParseFormMiddleware) r.Get("/", ConvertUserRoute(routes.ChangeTheme)) }) r.Route("/attachs", func(r chi.Router) { r.Use(ParseFormMiddleware) r.Get("/{extra}", ConvertExtraRoute(routes.ShowAttachment)) }) r.Route("/ws", func(r chi.Router) { r.Get("/{extra}", ConvertUserRoute(common.RouteWebsockets)) }) r.Route("/api", func(r chi.Router) { r.Get("/phrases*", ConvertUserRoute(routeAPIPhrases)) r.Get("/me*", ConvertUserRoute(routes.APIMe)) r.Get("/watches*", ConvertUserRoute(routeJSAntispam)) r.Get("/*", ConvertUserRoute(routeAPI)) }) r.Route("/report", func(r chi.Router) { r.Use(NoBannedMiddleware) r.Use(NoSessionMismatchMiddleware) r.Use(MemberOnlyMiddleware) r.Get("/submit/{extra}", ConvertExtraRoute(routes.ReportSubmit)) }) r.Route("/topics", func(r chi.Router) { r.Get("/most-viewed", ConvertHeaderRoute(routes.TopicListMostViewed)) r.Get("/week-views", ConvertHeaderRoute(routes.TopicListWeekViews)) r.Get("/create", ConvertHeaderExtraRoute(routes.CreateTopic)) r.Get("/", ConvertHeaderRoute(routes.TopicList)) }) r.Route("/panel", func(r chi.Router) { r.Use(SuperModOnlyMiddleware) r.Use(NoSessionMismatchMiddleware) r.Route("/forums", func(r chi.Router) { r.Get("/", ConvertUserRoute(panel.Forums)) r.Get("/create", ConvertUserRoute(panel.ForumsCreateSubmit)) r.Get("/delete/{extra}", ConvertExtraRoute(panel.ForumsDelete)) r.Get("/delete/submit/{extra}", ConvertExtraRoute(panel.ForumsDeleteSubmit)) r.Get("/order/edit/submit", ConvertUserRoute(panel.ForumsOrderSubmit)) r.Get("/edit/{extra}", ConvertExtraRoute(panel.ForumsEdit)) r.Get("/edit/submit/{extra}", ConvertExtraRoute(panel.ForumsEditSubmit)) r.Get("/edit/perms/submit/{extra}", ConvertExtraRoute(panel.ForumsEditPermsSubmit)) r.Get("/edit/perms/{extra}", ConvertExtraRoute(panel.ForumsEditPermsAdvance)) r.Get("/edit/perms/adv/submit/{extra}", ConvertExtraRoute(panel.ForumsEditPermsAdvanceSubmit)) r.Get("/action/create/submit/{extra}", ConvertExtraRoute(panel.ForumsEditActionCreateSubmit)) r.Get("/action/delete/submit/{extra}", ConvertExtraRoute(panel.ForumsEditActionDeleteSubmit)) }) r.Route("/settings", func(r chi.Router) { r.Get("/", ConvertUserRoute(panel.Settings)) r.Get("/edit/{extra}", ConvertExtraRoute(panel.SettingEdit)) r.Get("/edit/submit/{extra}", ConvertExtraRoute(panel.SettingEditSubmit)) r.Get("/word-filters", ConvertUserRoute(panel.WordFilters)) r.Get("/word-filters/create", ConvertUserRoute(panel.WordFiltersCreateSubmit)) r.Get("/word-filters/edit/{extra}", ConvertExtraRoute(panel.WordFiltersEdit)) r.Get("/word-filters/edit/submit/{extra}", ConvertExtraRoute(panel.WordFiltersEdit)) r.Get("/word-filters/delete/submit/{extra}", ConvertExtraRoute(panel.WordFiltersDeleteSubmit)) }) r.Route("/pages", func(r chi.Router) { r.Get("/create/submit", ConvertUserRoute(panel.PagesCreateSubmit)) r.Get("/edit/{extra}", ConvertExtraRoute(panel.PagesEdit)) r.Get("/edit/submit/{extra}", ConvertExtraRoute(panel.PagesEditSubmit)) r.Get("/delete/submit/{extra}", ConvertExtraRoute(panel.PagesDeleteSubmit)) }) r.Route("/themes", func(r chi.Router) { r.Get("/", ConvertUserRoute(panel.Themes)) r.Get("/default/{extra}", ConvertExtraRoute(panel.ThemesSetDefault)) r.Get("/menus", ConvertUserRoute(panel.ThemesMenus)) r.Get("/menus/edit/{extra}", ConvertExtraRoute(panel.ThemesMenusEdit)) r.Get("/menus/item/edit/{extra}", ConvertExtraRoute(panel.ThemesMenuItemEdit)) r.Get("/menus/item/edit/submit/{extra}", ConvertExtraRoute(panel.ThemesMenuItemEditSubmit)) r.Get("/menus/item/create/submit", ConvertUserRoute(panel.ThemesMenuItemCreateSubmit)) r.Get("/menus/item/delete/submit/{extra}", ConvertExtraRoute(panel.ThemesMenuItemDeleteSubmit)) r.Get("/menus/item/order/edit/submit/{extra}", ConvertExtraRoute(panel.ThemesMenuItemOrderSubmit)) r.Get("/widgets/edit/submit/{extra}", ConvertExtraRoute(panel.ThemesWidgetsEditSubmit)) r.Get("/widgets/create/submit", ConvertUserRoute(panel.ThemesWidgetsCreateSubmit)) r.Get("/widgets/delete/submit/{extra}", ConvertExtraRoute(panel.ThemesWidgetsDeleteSubmit)) }) r.Route("/plugins", func(r chi.Router) { r.Get("/{extra}", ConvertExtraRoute(panel.PluginsInstall)) r.Get("/activate/{extra}", ConvertExtraRoute(panel.PluginsActivate)) r.Get("/deactivate/{extra}", ConvertExtraRoute(panel.PluginsDeactivate)) r.Get("/install/{extra}", ConvertExtraRoute(panel.PluginsInstall)) }) }) r.Route("/user", func(r chi.Router) { r.Use(MemberOnlyMiddleware) r.Route("/edit", func(r chi.Router) { r.Get("/", ConvertHeaderRoute(routes.AccountEdit)) r.Get("/password", ConvertHeaderRoute(routes.AccountEditPassword)) r.Get("/password/submit", ConvertUserRoute(routes.AccountEditPasswordSubmit)) r.Get("/avatar/submit", ConvertUserRoute(routes.AccountEditAvatarSubmit)) r.Get("/avatar/revoke/submit", ConvertUserRoute(routes.AccountEditRevokeAvatarSubmit)) r.Get("/username/submit", ConvertUserRoute(routes.AccountEditUsernameSubmit)) r.Get("/privacy", ConvertHeaderRoute(routes.AccountEditPrivacy)) r.Get("/privacy/submit", ConvertUserRoute(routes.AccountEditPrivacySubmit)) r.Get("/mfa", ConvertHeaderRoute(routes.AccountEditMFA)) r.Get("/mfa/setup", ConvertHeaderRoute(routes.AccountEditMFASetup)) r.Get("/mfa/setup/submit", ConvertUserRoute(routes.AccountEditMFASetupSubmit)) r.Get("/mfa/disable/submit", ConvertUserRoute(routes.AccountEditMFADisableSubmit)) r.Get("/email", ConvertHeaderRoute(routes.AccountEditEmail)) r.Get("/token", ConvertExtraRoute(routes.AccountEditEmailTokenSubmit)) r.Get("/logins", ConvertHeaderRoute(routes.AccountLogins)) r.Get("/blocked", ConvertHeaderRoute(routes.AccountBlocked)) }) r.Get("/levels", ConvertHeaderRoute(routes.LevelList)) r.Get("/convos", ConvertHeaderRoute(routes.Convos)) r.Get("/convos/create", ConvertHeaderRoute(routes.ConvosCreate)) r.Get("/convo", ConvertHeaderExtraRoute(routes.Convo)) r.Get("/convos/create/submit", ConvertUserRoute(routes.ConvosCreateSubmit)) r.Get("/convo/create/submit", ConvertUserRoute(routes.ConvosCreateSubmit)) r.Get("/convo/delete/submit", ConvertExtraRoute(routes.ConvosDeleteReplySubmit)) r.Get("/convo/edit/submit", ConvertExtraRoute(routes.ConvosEditReplySubmit)) r.Get("/block/create", ConvertHeaderExtraRoute(routes.RelationsBlockCreate)) r.Get("/block/create/submit", ConvertExtraRoute(routes.RelationsBlockCreateSubmit)) r.Get("/block/remove", ConvertHeaderExtraRoute(routes.RelationsBlockRemove)) r.Get("/block/remove/submit", ConvertExtraRoute(routes.RelationsBlockRemoveSubmit)) r.Get("/{user}", ConvertHeaderRoute(routes.ViewProfile)) }) r.Route("/users", func(r chi.Router) { r.Use(NoSessionMismatchMiddleware) r.Get("/ban/submit", ConvertExtraRoute(routes.BanUserSubmit)) r.Get("/unban", ConvertExtraRoute(routes.UnbanUser)) r.Get("/activate", ConvertExtraRoute(routes.ActivateUser)) r.Get("/ips", ConvertHeaderRoute(routes.IPSearch)) r.Get("/delete-posts/submit", ConvertExtraRoute(routes.DeletePostsSubmit)) }) r.Route("/topic", func(r chi.Router) { r.Use(MemberOnlyMiddleware) r.Use(NoSessionMismatchMiddleware) r.Get("/create/submit", ConvertUserRoute(routes.CreateTopicSubmit)) r.Get("/edit/submit", ConvertExtraRoute(routes.EditTopicSubmit)) r.Get("/delete/submit", ConvertUserRoute(routes.DeleteTopicSubmit)) r.Get("/stick/submit", ConvertExtraRoute(routes.StickTopicSubmit)) r.Get("/unstick/submit", ConvertExtraRoute(routes.UnstickTopicSubmit)) r.Get("/lock/submit", ConvertUserRoute(routes.LockTopicSubmit)) r.Get("/unlock/submit", ConvertExtraRoute(routes.UnlockTopicSubmit)) r.Get("/move/submit", ConvertExtraRoute(routes.MoveTopicSubmit)) r.Get("/like/submit", ConvertExtraRoute(routes.LikeTopicSubmit)) r.Get("/unlike/submit", ConvertExtraRoute(routes.UnlikeTopicSubmit)) r.Get("/attach/add/submit", ConvertExtraRoute(routes.AddAttachToTopicSubmit)) r.Get("/attach/remove/submit", ConvertExtraRoute(routes.RemoveAttachFromTopicSubmit)) }) r.Route("/reply", func(r chi.Router) { r.Use(MemberOnlyMiddleware) r.Get("/create", ConvertUserRoute(routes.ProfileReplyCreateSubmit)) r.Get("/edit/submit", ConvertExtraRoute(routes.ReplyEditSubmit)) r.Get("/delete/submit", ConvertExtraRoute(routes.ReplyDeleteSubmit)) r.Get("/like/submit", ConvertExtraRoute(routes.ReplyLikeSubmit)) r.Get("/unlike/submit", ConvertExtraRoute(routes.ReplyUnlikeSubmit)) r.Get("/attach/add/submit", ConvertExtraRoute(routes.AddAttachToReplySubmit)) r.Get("/attach/remove/submit", ConvertExtraRoute(routes.RemoveAttachFromReplySubmit)) }) r.Route("/profile", func(r chi.Router) { r.Use(MemberOnlyMiddleware) r.Use(NoSessionMismatchMiddleware) r.Get("/reply/create", ConvertUserRoute(routes.ProfileReplyCreateSubmit)) r.Get("/reply/edit/submit", ConvertExtraRoute(routes.ProfileReplyEditSubmit)) r.Get("/reply/edit/delete/submit", ConvertExtraRoute(routes.ProfileReplyDeleteSubmit)) }) r.Route("/poll", func(r chi.Router) { r.Use(MemberOnlyMiddleware) r.Use(NoSessionMismatchMiddleware) r.Get("/poll/vote", ConvertExtraRoute(routes.PollVote)) r.Get("/poll/results", ConvertExtraRoute(routes.PollResults)) }) r.Route("/accounts", func(r chi.Router) { r.Get("/login", ConvertHeaderRoute(routes.AccountLogin)) r.Get("/create", ConvertHeaderRoute(routes.AccountRegister)) r.Get("/logout", ConvertUserRoute(routes.AccountLogout)) r.Get("/login/submit", ConvertUserRoute(routes.AccountLoginSubmit)) r.Get("/mfa_verify", ConvertHeaderRoute(routes.AccountLoginMFAVerify)) r.Get("/mfa_verify/submit", ConvertUserRoute(routes.AccountLoginMFAVerifySubmit)) r.Get("/create/submit", ConvertUserRoute(routes.AccountRegisterSubmit)) r.Get("/password-reset", ConvertHeaderRoute(routes.AccountPasswordReset)) r.Get("/password-reset/submit", ConvertUserRoute(routes.AccountPasswordResetSubmit)) r.Get("/password-reset/token", ConvertHeaderRoute(routes.AccountPasswordResetToken)) r.Get("/password-reset/token/submit", ConvertUserRoute(routes.AccountPasswordResetTokenSubmit)) }) r.Route("/static", func(r chi.Router) {}) r.Route("/uploads", func(r chi.Router) {}) http.ListenAndServe(":3333", r) }