user authentication

This commit is contained in:
nahakubuilde
2025-08-25 21:19:15 +01:00
parent 6c82e2014c
commit e21a0b5b10
23 changed files with 2479 additions and 189 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gorilla/sessions"
"gobsidian/internal/auth"
"gobsidian/internal/config"
"gobsidian/internal/handlers"
"gobsidian/internal/models"
@@ -18,6 +19,7 @@ type Server struct {
config *config.Config
router *gin.Engine
store *sessions.CookieStore
auth *auth.Service
}
func New(cfg *config.Config) *Server {
@@ -28,12 +30,22 @@ func New(cfg *config.Config) *Server {
router := gin.Default()
store := sessions.NewCookieStore([]byte(cfg.SecretKey))
// Initialize auth service (panic on error during startup)
authSvc, err := auth.Open(cfg)
if err != nil {
panic(fmt.Errorf("failed to initialize auth: %w", err))
}
s := &Server{
config: cfg,
router: router,
store: store,
auth: authSvc,
}
// Global middlewares: session user + template setup
s.router.Use(s.SessionUser())
s.setupRoutes()
s.setupStaticFiles()
s.setupTemplates()
@@ -62,7 +74,7 @@ func (s *Server) Start() error {
}
func (s *Server) setupRoutes() {
h := handlers.New(s.config, s.store)
h := handlers.New(s.config, s.store, s.auth)
// Main routes
s.router.GET("/", h.IndexHandler)
@@ -74,27 +86,68 @@ func (s *Server) setupRoutes() {
s.router.GET("/serve_stored_image/:filename", h.ServeStoredImageHandler)
s.router.GET("/download/*path", h.DownloadHandler)
s.router.GET("/view_text/*path", h.ViewTextHandler)
s.router.GET("/edit_text/*path", h.EditTextPageHandler)
s.router.POST("/edit_text/*path", h.PostEditTextHandler)
// Upload routes
s.router.POST("/upload", h.UploadHandler)
// Auth routes
s.router.GET("/editor/login", h.LoginPage)
s.router.POST("/editor/login", s.CSRFRequire(), h.LoginPost)
s.router.POST("/editor/logout", s.RequireAuth(), s.CSRFRequire(), h.LogoutPost)
// MFA challenge routes (no auth yet, but CSRF)
s.router.GET("/editor/mfa", s.CSRFRequire(), h.MFALoginPage)
s.router.POST("/editor/mfa", s.CSRFRequire(), h.MFALoginVerify)
// Settings routes
s.router.GET("/settings", h.SettingsPageHandler)
s.router.GET("/settings/image_storage", h.GetImageStorageSettingsHandler)
s.router.POST("/settings/image_storage", h.PostImageStorageSettingsHandler)
s.router.GET("/settings/notes_dir", h.GetNotesDirSettingsHandler)
s.router.POST("/settings/notes_dir", h.PostNotesDirSettingsHandler)
s.router.GET("/settings/file_extensions", h.GetFileExtensionsSettingsHandler)
s.router.POST("/settings/file_extensions", h.PostFileExtensionsSettingsHandler)
// New /editor group protected by auth + CSRF
editor := s.router.Group("/editor", s.RequireAuth(), s.CSRFRequire())
{
editor.GET("/create", h.CreateNotePageHandler)
editor.POST("/create", h.CreateNoteHandler)
editor.GET("/edit/*path", h.EditNotePageHandler)
editor.POST("/edit/*path", h.EditNoteHandler)
editor.DELETE("/delete/*path", h.DeleteHandler)
// Editor routes
s.router.GET("/create", h.CreateNotePageHandler)
s.router.POST("/create", h.CreateNoteHandler)
s.router.GET("/edit/*path", h.EditNotePageHandler)
s.router.POST("/edit/*path", h.EditNoteHandler)
s.router.DELETE("/delete/*path", h.DeleteHandler)
// Text editor routes under /editor
editor.GET("/edit_text/*path", h.EditTextPageHandler)
editor.POST("/edit_text/*path", h.PostEditTextHandler)
// Upload under /editor (secured)
editor.POST("/upload", h.UploadHandler)
// Settings under /editor
editor.GET("/settings", h.SettingsPageHandler)
editor.GET("/settings/image_storage", h.GetImageStorageSettingsHandler)
editor.POST("/settings/image_storage", h.PostImageStorageSettingsHandler)
editor.GET("/settings/notes_dir", h.GetNotesDirSettingsHandler)
editor.POST("/settings/notes_dir", h.PostNotesDirSettingsHandler)
editor.GET("/settings/file_extensions", h.GetFileExtensionsSettingsHandler)
editor.POST("/settings/file_extensions", h.PostFileExtensionsSettingsHandler)
// Profile
editor.GET("/profile", h.ProfilePage)
editor.POST("/profile/password", h.PostProfileChangePassword)
editor.POST("/profile/email", h.PostProfileChangeEmail)
editor.POST("/profile/mfa/enable", h.PostProfileEnableMFA)
editor.POST("/profile/mfa/disable", h.PostProfileDisableMFA)
// MFA setup during enrollment
editor.GET("/profile/mfa/setup", h.ProfileMFASetupPage)
editor.POST("/profile/mfa/verify", h.ProfileMFASetupVerify)
// Admin dashboard
editor.GET("/admin", s.RequireAdmin(), h.AdminPage)
// Admin CRUD API under /editor/admin
admin := editor.Group("/admin", s.RequireAdmin())
{
admin.POST("/users", h.AdminCreateUser)
admin.DELETE("/users/:id", h.AdminDeleteUser)
admin.POST("/users/:id/active", h.AdminSetUserActive)
admin.POST("/users/:id/mfa/enable", h.AdminEnableUserMFA)
admin.POST("/users/:id/mfa/disable", h.AdminDisableUserMFA)
admin.POST("/users/:id/mfa/reset", h.AdminResetUserMFA)
admin.POST("/groups", h.AdminCreateGroup)
admin.DELETE("/groups/:id", h.AdminDeleteGroup)
admin.POST("/memberships/add", h.AdminAddUserToGroup)
admin.POST("/memberships/remove", h.AdminRemoveUserFromGroup)
}
}
// API routes
s.router.GET("/api/tree", h.TreeAPIHandler)