diff --git a/VERSION b/VERSION index 93d7d00ec..81dd1e5cc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.7.5 \ No newline at end of file +4.7.6 \ No newline at end of file diff --git a/internal/api/config_handlers.go b/internal/api/config_handlers.go index 82bf36e99..a1aea1d01 100644 --- a/internal/api/config_handlers.go +++ b/internal/api/config_handlers.go @@ -2515,8 +2515,16 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque // First check for setup code/auth token in the request if authCode != "" { codeHash := internalauth.HashAPIToken(authCode) + log.Debug(). + Str("authCode", authCode). + Str("codeHash", codeHash[:8]+"..."). + Msg("Checking auth token") h.codeMutex.Lock() setupCode, exists := h.setupCodes[codeHash] + log.Debug(). + Bool("exists", exists). + Int("totalCodes", len(h.setupCodes)). + Msg("Setup code lookup result") if exists && !setupCode.Used && time.Now().Before(setupCode.ExpiresAt) { // Validate that the code matches the node type // Note: We don't validate the host anymore as it may differ between @@ -2556,8 +2564,15 @@ func (h *ConfigHandlers) HandleAutoRegister(w http.ResponseWriter, r *http.Reque } // If still not authenticated and auth is required, reject - if !authenticated && h.config.APIToken != "" { - log.Warn().Str("ip", r.RemoteAddr).Msg("Unauthorized auto-register attempt - invalid or missing setup code") + // BUT: Always allow if a valid setup code/auth token was provided (even if expired/used) + // This ensures the error message is accurate + if !authenticated && h.config.APIToken != "" && authCode == "" { + log.Warn().Str("ip", r.RemoteAddr).Msg("Unauthorized auto-register attempt - no authentication provided") + http.Error(w, "Pulse requires authentication", http.StatusUnauthorized) + return + } else if !authenticated && h.config.APIToken != "" { + // Had a code but it didn't validate + log.Warn().Str("ip", r.RemoteAddr).Msg("Unauthorized auto-register attempt - invalid or expired setup code") http.Error(w, "Invalid or expired setup code", http.StatusUnauthorized) return } diff --git a/internal/api/router.go b/internal/api/router.go index 955632897..bd0137f90 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -796,6 +796,12 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { isPublic = true } + // Auto-register endpoint needs to be public (validates tokens internally) + // BUT the tokens must be generated by authenticated users via setup-script-url + if req.URL.Path == "/api/auto-register" { + isPublic = true + } + // Special case: quick-setup should be accessible to check if already configured // The handler itself will verify if setup should be skipped if req.URL.Path == "/api/security/quick-setup" && req.Method == http.MethodPost { diff --git a/internal/updates/version.go b/internal/updates/version.go index 8b7dbd768..8c0485ed9 100644 --- a/internal/updates/version.go +++ b/internal/updates/version.go @@ -164,7 +164,7 @@ func GetCurrentVersion() (*VersionInfo, error) { } // Final fallback - version := "4.7.5" + version := "4.7.6" channel := "stable" if strings.Contains(strings.ToLower(version), "rc") { channel = "rc"