added setting to turn off login/edits - LOGIN_AND_EDITS

This commit is contained in:
2026-04-23 06:19:45 +00:00
parent 3c70cb99a3
commit a30eb4d42d
6 changed files with 33 additions and 6 deletions
+1
View File
@@ -80,6 +80,7 @@ PATH = data/gobsidian.db
REQUIRE_ADMIN_ACTIVATION = true REQUIRE_ADMIN_ACTIVATION = true
REQUIRE_EMAIL_CONFIRMATION = false REQUIRE_EMAIL_CONFIRMATION = false
MFA_ENABLED_BY_DEFAULT = false MFA_ENABLED_BY_DEFAULT = false
LOGIN_AND_EDITS = true
[SECURITY] [SECURITY]
PWD_FAILURES_THRESHOLD = 5 PWD_FAILURES_THRESHOLD = 5
+5
View File
@@ -45,6 +45,7 @@ type Config struct {
RequireAdminActivation bool RequireAdminActivation bool
RequireEmailConfirmation bool RequireEmailConfirmation bool
MFAEnabledByDefault bool MFAEnabledByDefault bool
LoginAndEdits bool
// Security settings (failed-login thresholds and auto-ban config) // Security settings (failed-login thresholds and auto-ban config)
PwdFailuresThreshold int PwdFailuresThreshold int
@@ -92,6 +93,7 @@ var defaultConfig = map[string]map[string]string{
"REQUIRE_ADMIN_ACTIVATION": "true", "REQUIRE_ADMIN_ACTIVATION": "true",
"REQUIRE_EMAIL_CONFIRMATION": "false", "REQUIRE_EMAIL_CONFIRMATION": "false",
"MFA_ENABLED_BY_DEFAULT": "false", "MFA_ENABLED_BY_DEFAULT": "false",
"LOGIN_AND_EDITS": "true",
}, },
"SECURITY": { "SECURITY": {
"PWD_FAILURES_THRESHOLD": "5", "PWD_FAILURES_THRESHOLD": "5",
@@ -219,6 +221,7 @@ func Load() (*Config, error) {
config.RequireAdminActivation, _ = authSection.Key("REQUIRE_ADMIN_ACTIVATION").Bool() config.RequireAdminActivation, _ = authSection.Key("REQUIRE_ADMIN_ACTIVATION").Bool()
config.RequireEmailConfirmation, _ = authSection.Key("REQUIRE_EMAIL_CONFIRMATION").Bool() config.RequireEmailConfirmation, _ = authSection.Key("REQUIRE_EMAIL_CONFIRMATION").Bool()
config.MFAEnabledByDefault, _ = authSection.Key("MFA_ENABLED_BY_DEFAULT").Bool() config.MFAEnabledByDefault, _ = authSection.Key("MFA_ENABLED_BY_DEFAULT").Bool()
config.LoginAndEdits, _ = authSection.Key("LOGIN_AND_EDITS").Bool()
// Load SECURITY section // Load SECURITY section
secSection := cfg.Section("SECURITY") secSection := cfg.Section("SECURITY")
@@ -395,6 +398,8 @@ func (c *Config) SaveSetting(section, key, value string) error {
c.RequireEmailConfirmation = value == "true" c.RequireEmailConfirmation = value == "true"
case "MFA_ENABLED_BY_DEFAULT": case "MFA_ENABLED_BY_DEFAULT":
c.MFAEnabledByDefault = value == "true" c.MFAEnabledByDefault = value == "true"
case "LOGIN_AND_EDITS":
c.LoginAndEdits = value == "true"
} }
case "SECURITY": case "SECURITY":
switch key { switch key {
+1
View File
@@ -972,6 +972,7 @@ func (h *Handlers) IndexHandler(c *gin.Context) {
"breadcrumbs": utils.GenerateBreadcrumbs(""), "breadcrumbs": utils.GenerateBreadcrumbs(""),
"allowed_image_extensions": h.config.AllowedImageExtensions, "allowed_image_extensions": h.config.AllowedImageExtensions,
"allowed_file_extensions": h.config.AllowedFileExtensions, "allowed_file_extensions": h.config.AllowedFileExtensions,
"LoginAndEdits": h.config.LoginAndEdits,
"Authenticated": isAuthenticated(c), "Authenticated": isAuthenticated(c),
"IsAdmin": isAdmin(c), "IsAdmin": isAdmin(c),
"ContentTemplate": "folder_content", "ContentTemplate": "folder_content",
+12
View File
@@ -13,6 +13,18 @@ import (
const csrfSessionKey = "csrf_token" const csrfSessionKey = "csrf_token"
// RequireLoginAndEdits blocks access if LoginAndEdits setting is false.
func (s *Server) RequireLoginAndEdits() gin.HandlerFunc {
return func(c *gin.Context) {
if !s.config.LoginAndEdits {
c.Redirect(http.StatusFound, s.config.URLPrefix+"/?error=not_found")
c.Abort()
return
}
c.Next()
}
}
func (s *Server) randomToken(n int) (string, error) { func (s *Server) randomToken(n int) (string, error) {
b := make([]byte, n) b := make([]byte, n)
if _, err := rand.Read(b); err != nil { if _, err := rand.Read(b); err != nil {
+6 -6
View File
@@ -105,15 +105,15 @@ func (s *Server) setupRoutes() {
r.GET("/view_text/*path", h.ViewTextHandler) r.GET("/view_text/*path", h.ViewTextHandler)
// Auth routes // Auth routes
r.GET("/editor/login", h.LoginPage) r.GET("/editor/login", s.RequireLoginAndEdits(), h.LoginPage)
r.POST("/editor/login", s.CSRFRequire(), h.LoginPost) r.POST("/editor/login", s.RequireLoginAndEdits(), s.CSRFRequire(), h.LoginPost)
r.POST("/editor/logout", s.RequireAuth(), s.CSRFRequire(), h.LogoutPost) r.POST("/editor/logout", s.RequireAuth(), s.CSRFRequire(), h.LogoutPost)
// MFA challenge routes (no auth yet, but CSRF) // MFA challenge routes (no auth yet, but CSRF)
r.GET("/editor/mfa", s.CSRFRequire(), h.MFALoginPage) r.GET("/editor/mfa", s.RequireLoginAndEdits(), s.CSRFRequire(), h.MFALoginPage)
r.POST("/editor/mfa", s.CSRFRequire(), h.MFALoginVerify) r.POST("/editor/mfa", s.RequireLoginAndEdits(), s.CSRFRequire(), h.MFALoginVerify)
// New /editor group protected by auth + CSRF // New /editor group protected by auth + CSRF + LoginAndEdits
editor := r.Group("/editor", s.RequireAuth(), s.CSRFRequire()) editor := r.Group("/editor", s.RequireLoginAndEdits(), s.RequireAuth(), s.CSRFRequire())
{ {
editor.GET("/create", h.CreateNotePageHandler) editor.GET("/create", h.CreateNotePageHandler)
editor.POST("/create", h.CreateNoteHandler) editor.POST("/create", h.CreateNoteHandler)
+8
View File
@@ -308,10 +308,12 @@
<i class="fas fa-right-from-bracket"></i> <i class="fas fa-right-from-bracket"></i>
</button> </button>
{{else}} {{else}}
{{if .LoginAndEdits}}
<a href="{{url "/editor/login"}}" class="text-gray-400 hover:text-white transition-colors" title="Login"> <a href="{{url "/editor/login"}}" class="text-gray-400 hover:text-white transition-colors" title="Login">
<i class="fas fa-right-to-bracket"></i> <i class="fas fa-right-to-bracket"></i>
</a> </a>
{{end}} {{end}}
{{end}}
</div> </div>
<button id="sidebar-toggle" class="toggle-btn" title="Toggle sidebar" aria-label="Toggle sidebar"> <button id="sidebar-toggle" class="toggle-btn" title="Toggle sidebar" aria-label="Toggle sidebar">
<i id="sidebar-toggle-icon" class="fas fa-chevron-left"></i> <i id="sidebar-toggle-icon" class="fas fa-chevron-left"></i>
@@ -582,6 +584,12 @@
const collapsed = localStorage.getItem('sidebarCollapsed') === 'true'; const collapsed = localStorage.getItem('sidebarCollapsed') === 'true';
applySidebarState(collapsed); applySidebarState(collapsed);
// Check for error in query params
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('error') === 'not_found') {
showNotification('The page does not exist', 'error', 5000);
}
// Wire toggle button // Wire toggle button
const toggleBtn = document.getElementById('sidebar-toggle'); const toggleBtn = document.getElementById('sidebar-toggle');
if (toggleBtn) { if (toggleBtn) {