mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-12 22:28:31 +00:00
The bootstrap token security requirement was added proactively but lacked discoverability, causing user friction during first-run setup. These improvements make the token easier to find while maintaining the security benefit. Improvements: - Display bootstrap token prominently in startup logs with ASCII box (previously: single line log message) - Add `pulse bootstrap-token` CLI command to display token on demand (Docker: docker exec <container> /app/pulse bootstrap-token) - Improve error messages in quick-setup API to show exact commands for retrieving token when missing or invalid - Error messages now include both Docker and bare metal examples User experience improvements: - Token visible in `docker logs` output immediately - Clear instructions printed with token - Helpful error messages if token is wrong/missing - CLI helper for operators who need to retrieve token later Security unchanged: - Bootstrap token still required for first-run setup - Token still auto-deleted after successful setup - No bypass mechanism added Related to discussion about bootstrap token UX friction.
78 lines
4.2 KiB
Go
78 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var bootstrapTokenCmd = &cobra.Command{
|
|
Use: "bootstrap-token",
|
|
Short: "Display the bootstrap setup token",
|
|
Long: `Display the bootstrap setup token required for first-time setup.
|
|
|
|
This token is generated on first boot and must be entered in the web UI
|
|
to unlock the initial setup wizard. The token is automatically deleted
|
|
after successful setup completion.`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
showBootstrapToken()
|
|
},
|
|
}
|
|
|
|
func showBootstrapToken() {
|
|
// Determine data path (same logic as main server)
|
|
dataPath := os.Getenv("PULSE_DATA_PATH")
|
|
if dataPath == "" {
|
|
if os.Getenv("PULSE_DOCKER") == "true" {
|
|
dataPath = "/data"
|
|
} else {
|
|
dataPath = "/var/lib/pulse"
|
|
}
|
|
}
|
|
|
|
tokenPath := filepath.Join(dataPath, ".bootstrap_token")
|
|
|
|
// Read token file
|
|
data, err := os.ReadFile(tokenPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
fmt.Println("╔═══════════════════════════════════════════════════════════════════════╗")
|
|
fmt.Println("║ NO BOOTSTRAP TOKEN FOUND ║")
|
|
fmt.Println("╠═══════════════════════════════════════════════════════════════════════╣")
|
|
fmt.Println("║ Possible reasons: ║")
|
|
fmt.Println("║ • Initial setup has already been completed ║")
|
|
fmt.Println("║ • Authentication is configured (token auto-deleted) ║")
|
|
fmt.Println("║ • Server hasn't started yet (token not generated) ║")
|
|
fmt.Printf("║ • Token file not found: %-44s║\n", tokenPath)
|
|
fmt.Println("╚═══════════════════════════════════════════════════════════════════════╝")
|
|
os.Exit(1)
|
|
}
|
|
fmt.Printf("Error reading bootstrap token: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
token := strings.TrimSpace(string(data))
|
|
if token == "" {
|
|
fmt.Println("Error: Bootstrap token file is empty")
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Display token prominently
|
|
fmt.Println("╔═══════════════════════════════════════════════════════════════════════╗")
|
|
fmt.Println("║ BOOTSTRAP TOKEN FOR FIRST-TIME SETUP ║")
|
|
fmt.Println("╠═══════════════════════════════════════════════════════════════════════╣")
|
|
fmt.Printf("║ Token: %-61s ║\n", token)
|
|
fmt.Printf("║ File: %-61s ║\n", tokenPath)
|
|
fmt.Println("╠═══════════════════════════════════════════════════════════════════════╣")
|
|
fmt.Println("║ Instructions: ║")
|
|
fmt.Println("║ 1. Copy the token above ║")
|
|
fmt.Println("║ 2. Open Pulse in your web browser ║")
|
|
fmt.Println("║ 3. Paste the token into the unlock screen ║")
|
|
fmt.Println("║ 4. Complete the admin account setup ║")
|
|
fmt.Println("║ ║")
|
|
fmt.Println("║ This token will be automatically deleted after successful setup. ║")
|
|
fmt.Println("╚═══════════════════════════════════════════════════════════════════════╝")
|
|
}
|