mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
2fd114b3ac
Separate PVE/PBS setup and telemetry credentials from shell source and download URLs. Use silent root/sudo input, private-file handoff, complete downloads and the agent preflight; preserve scope, TLS defaults, single-line paste and coherent rolling-upgrade metadata. Reveal tokens through the existing dialog and discard late issuance after close. Pin executable shell, history, TLS/registration and browser contracts without using real credentials. Change-source: pulse-maintainer
98 lines
4.2 KiB
Go
98 lines
4.2 KiB
Go
package configapi
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type AgentInstallCommandOptions struct {
|
|
BaseURL string
|
|
Token string
|
|
InstallType string
|
|
IncludeInstallType bool
|
|
EnableCommands bool
|
|
Insecure bool
|
|
}
|
|
|
|
type agentInstallCommandOptions = AgentInstallCommandOptions
|
|
|
|
// BuildProxmoxAgentInstallCommand never puts the credential in shell source.
|
|
// Token only selects whether private terminal input is required. The plaintext
|
|
// remains in the authenticated response's separate token field.
|
|
func BuildProxmoxAgentInstallCommand(opts AgentInstallCommandOptions) string {
|
|
baseURL := strings.TrimRight(strings.TrimSpace(opts.BaseURL), "/")
|
|
curlFlags := "-fsSL"
|
|
if opts.Insecure {
|
|
curlFlags = "-kfsSL"
|
|
}
|
|
trustArgs := ""
|
|
if opts.Insecure || strings.HasPrefix(strings.ToLower(baseURL), "http://") {
|
|
trustArgs = " --insecure"
|
|
}
|
|
args := " --url " + posixShellQuote(baseURL) + " --enable-proxmox"
|
|
if opts.IncludeInstallType {
|
|
args += " --proxmox-type " + posixShellQuote(opts.InstallType)
|
|
}
|
|
if opts.EnableCommands {
|
|
args += " --enable-commands"
|
|
}
|
|
if strings.TrimSpace(opts.Token) != "" {
|
|
args += ` --token-file "$token_file"`
|
|
}
|
|
args += trustArgs + " --non-interactive"
|
|
preflight := "bash \"$install_script\" --url " + posixShellQuote(baseURL) +
|
|
" --preflight-only --output json --non-interactive" + trustArgs + ";"
|
|
return privateBootstrapCommand(baseURL+"/install.sh", curlFlags, preflight,
|
|
"bash \"$1\""+args+";", strings.TrimSpace(opts.Token) != "", "Pulse agent token")
|
|
}
|
|
|
|
// privateBootstrapCommand uses POSIX outer grammar for single-line paste hosts.
|
|
// The privileged Bash child owns both the silent input and its 0700/0600
|
|
// handoff. Neither sudo nor a child command receives the credential in argv or
|
|
// environment. Failed/partial downloads and preflight never reach that child.
|
|
func privateBootstrapCommand(scriptURL, curlFlags, preflight, run string, needsToken bool, prompt string) string {
|
|
privileged := []string{"set +xv;", "set -eu;", "umask 077;"}
|
|
if needsToken {
|
|
privileged = append(privileged,
|
|
`token_dir=$(mktemp -d /tmp/pulse-agent-bootstrap.XXXXXX);`,
|
|
`token_file="$token_dir/token";`,
|
|
`cleanup() { unset pulse_token; rm -f -- "$token_file"; rmdir -- "$token_dir"; };`,
|
|
`trap cleanup EXIT; trap 'exit 129' HUP; trap 'exit 130' INT; trap 'exit 143' TERM;`,
|
|
`if ! IFS= read -r -s -p `+posixShellQuote(prompt+" (paste at this prompt, not in the command): ")+` pulse_token </dev/tty; then echo "A terminal is required to enter the token. No installation was attempted." >&2; exit 1; fi;`,
|
|
`printf '\n' >/dev/tty;`,
|
|
`if [ -z "$pulse_token" ] || [ "${#pulse_token}" -gt 4096 ]; then echo "A non-empty token of at most 4096 characters is required." >&2; exit 1; fi;`,
|
|
`printf %s "$pulse_token" > "$token_file"; unset pulse_token;`,
|
|
)
|
|
}
|
|
privileged = append(privileged, run)
|
|
child := "bash -c " + posixShellQuote(strings.Join(privileged, " ")) + ` pulse-bootstrap "$install_script";`
|
|
return strings.Join([]string{
|
|
"(", "set +xv;", "set -eu;", "umask 077;",
|
|
`if [ "$(id -u)" -eq 0 ]; then :; elif command -v sudo >/dev/null 2>&1; then sudo -v; else echo "Root privileges required. Run as root (su -) and retry." >&2; exit 1; fi;`,
|
|
`bootstrap_dir=$(mktemp -d /tmp/pulse-bootstrap.XXXXXX);`,
|
|
`install_script="$bootstrap_dir/install.sh";`,
|
|
`cleanup() { rm -f -- "$install_script"; rmdir -- "$bootstrap_dir"; };`,
|
|
`trap cleanup EXIT; trap 'exit 129' HUP; trap 'exit 130' INT; trap 'exit 143' TERM;`,
|
|
"curl " + curlFlags + " " + posixShellQuote(strings.TrimSpace(scriptURL)) + ` -o "$install_script";`,
|
|
preflight,
|
|
`if [ "$(id -u)" -eq 0 ]; then ` + child + " else sudo " + child + " fi;",
|
|
")",
|
|
}, " ")
|
|
}
|
|
|
|
func buildProxmoxAgentInstallCommand(opts agentInstallCommandOptions) string {
|
|
return BuildProxmoxAgentInstallCommand(opts)
|
|
}
|
|
|
|
func withPrivilegeEscalation(command string) string {
|
|
const installPipe = "| bash -s --"
|
|
idx := strings.Index(command, installPipe)
|
|
if idx == -1 {
|
|
return command
|
|
}
|
|
args := command[idx+len(installPipe):]
|
|
return command[:idx] +
|
|
`| { if [ "$(id -u)" -eq 0 ]; then bash -s --` + args +
|
|
`; elif command -v sudo >/dev/null 2>&1; then sudo bash -s --` + args +
|
|
`; else echo "Root privileges required. Run as root (su -) and retry." >&2; exit 1; fi; }`
|
|
}
|