fix: handle permission issues in security setup gracefully

- Try automatic setup first (if sudo available)
- Fall back to generating a simple apply script
- Show single command to run: sudo bash /etc/pulse/apply-security.sh
- Script handles all systemd configuration steps
- Clear UI shows when manual step is needed
This commit is contained in:
Pulse Monitor
2025-08-12 21:11:21 +00:00
parent 62524f040a
commit 58fa977502
2 changed files with 85 additions and 31 deletions
@@ -69,12 +69,19 @@ export const QuickSecuritySetup: Component = () => {
setCredentials(newCredentials);
setShowCredentials(true);
if (result.method === 'systemd' && result.willRestart) {
// Store the command if manual action needed
if (result.command) {
(window as any).securityCommand = result.command;
}
if (result.method === 'systemd' && result.automatic) {
showSuccess('Security enabled! Pulse will restart automatically in 2 seconds...');
// Show countdown
setTimeout(() => {
showSuccess('Restarting now... You will need to log in with your new credentials.');
}, 2000);
} else if (result.method === 'systemd' && !result.automatic) {
showSuccess('Security configured! Run the command shown below to apply settings.');
} else if (result.method === 'docker') {
showSuccess('Security configured! Please restart your Docker container with the credentials shown.');
} else {
@@ -251,12 +258,32 @@ Important:
</div>
<div class="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-3">
<p class="text-sm font-semibold text-green-800 dark:text-green-200 mb-2">
✅ Security has been automatically enabled!
</p>
<p class="text-xs text-green-700 dark:text-green-300">
Pulse will restart automatically in a few seconds. You'll need to log in with these credentials.
</p>
<Show
when={(window as any).securityCommand}
fallback={
<>
<p class="text-sm font-semibold text-green-800 dark:text-green-200 mb-2">
Security configured successfully!
</p>
<p class="text-xs text-green-700 dark:text-green-300">
Save your credentials above. Pulse will apply the security settings.
</p>
</>
}
>
<p class="text-sm font-semibold text-green-800 dark:text-green-200 mb-2">
One more step to enable security:
</p>
<p class="text-xs text-green-700 dark:text-green-300 mb-2">
Run this command in your terminal:
</p>
<div class="bg-gray-900 text-green-400 p-2 rounded font-mono text-xs overflow-x-auto">
{(window as any).securityCommand}
</div>
<p class="text-xs text-green-700 dark:text-green-300 mt-2">
This will apply the settings and restart Pulse with security enabled.
</p>
</Show>
</div>
</div>
</Show>
+51 -24
View File
@@ -267,16 +267,11 @@ func (r *Router) setupRoutes() {
isDocker := os.Getenv("PULSE_DOCKER") == "true"
if isSystemd {
// We're running under systemd - create override file
overridePath := "/etc/systemd/system/pulse-backend.service.d/override.conf"
overrideDir := filepath.Dir(overridePath)
// We're running under systemd but may not have root permissions
// Write config to Pulse's data directory and provide a one-liner to apply it
// Create override directory
if err := os.MkdirAll(overrideDir, 0755); err != nil {
log.Error().Err(err).Msg("Failed to create systemd override directory")
http.Error(w, "Failed to create systemd configuration", http.StatusInternalServerError)
return
}
configPath := filepath.Join(r.config.DataPath, "security-override.conf")
scriptPath := filepath.Join(r.config.DataPath, "apply-security.sh")
// Create override content
overrideContent := fmt.Sprintf(`# Auto-generated by Pulse Quick Security Setup
@@ -288,30 +283,62 @@ Environment="API_TOKEN=%s"
Environment="ENABLE_AUDIT_LOG=true"
`, time.Now().Format(time.RFC3339), setupRequest.Username, setupRequest.Password, setupRequest.APIToken)
// Write override file
if err := os.WriteFile(overridePath, []byte(overrideContent), 0644); err != nil {
log.Error().Err(err).Msg("Failed to write systemd override")
http.Error(w, "Failed to write systemd configuration", http.StatusInternalServerError)
// Write override file to data directory
if err := os.WriteFile(configPath, []byte(overrideContent), 0644); err != nil {
log.Error().Err(err).Msg("Failed to write security config")
http.Error(w, "Failed to write security configuration", http.StatusInternalServerError)
return
}
// Reload systemd and restart service
if err := utils.RunCommand("systemctl", "daemon-reload"); err != nil {
log.Error().Err(err).Msg("Failed to reload systemd")
// Create apply script
scriptContent := fmt.Sprintf(`#!/bin/bash
# Auto-generated script to apply Pulse security settings
echo "Applying security settings to Pulse..."
sudo mkdir -p /etc/systemd/system/pulse-backend.service.d/
sudo cp %s /etc/systemd/system/pulse-backend.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart pulse-backend
echo "Security enabled! Pulse is restarting..."
echo "You will need to log in with your saved credentials."
`, configPath)
if err := os.WriteFile(scriptPath, []byte(scriptContent), 0755); err != nil {
log.Error().Err(err).Msg("Failed to write apply script")
}
// Schedule restart after response (so user gets the credentials)
go func() {
time.Sleep(2 * time.Second)
log.Info().Msg("Restarting Pulse to apply security settings...")
utils.RunCommand("systemctl", "restart", "pulse-backend")
}()
// Try to apply automatically (will only work if we have sudo permissions)
if err := utils.RunCommand("sudo", "mkdir", "-p", "/etc/systemd/system/pulse-backend.service.d/"); err == nil {
if err := utils.RunCommand("sudo", "cp", configPath, "/etc/systemd/system/pulse-backend.service.d/override.conf"); err == nil {
utils.RunCommand("sudo", "systemctl", "daemon-reload")
// Schedule restart
go func() {
time.Sleep(2 * time.Second)
log.Info().Msg("Restarting Pulse to apply security settings...")
utils.RunCommand("sudo", "systemctl", "restart", "pulse-backend")
}()
response := map[string]interface{}{
"success": true,
"method": "systemd",
"automatic": true,
"willRestart": true,
"message": "Security enabled! Pulse will restart in 2 seconds to apply settings.",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
}
// If automatic didn't work, provide manual command
response := map[string]interface{}{
"success": true,
"method": "systemd",
"willRestart": true,
"message": "Security enabled! Pulse will restart in 2 seconds to apply settings.",
"automatic": false,
"configPath": configPath,
"scriptPath": scriptPath,
"command": fmt.Sprintf("sudo bash %s", scriptPath),
"message": "Security configured! Run the command shown to apply settings.",
}
w.Header().Set("Content-Type", "application/json")