diff --git a/app/Helpers/SshMultiplexingHelper.php b/app/Helpers/SshMultiplexingHelper.php index 6984dac4b..db139d110 100644 --- a/app/Helpers/SshMultiplexingHelper.php +++ b/app/Helpers/SshMultiplexingHelper.php @@ -28,15 +28,20 @@ public static function ensureMultiplexedConnection(Server $server): bool public static function removeMuxFile(Server $server): void { - $closeCommand = 'ssh -O exit -o ControlPath='.self::muxSocket($server).' '; - if (data_get($server, 'settings.is_cloudflare_tunnel')) { - $closeCommand .= '-o ProxyCommand="cloudflared access ssh --hostname %h" '; - } - $closeCommand .= self::escapedUserAtHost($server); - + $closeCommand = self::muxControlCommand($server, 'exit'); Process::run($closeCommand); } + private static function muxControlCommand(Server $server, string $operation): string + { + $command = "ssh -O {$operation} -o ControlPath=".self::muxSocket($server).' '; + if (data_get($server, 'settings.is_cloudflare_tunnel')) { + $command .= '-o ProxyCommand="cloudflared access ssh --hostname %h" '; + } + + return $command.self::escapedUserAtHost($server); + } + public static function generateScpCommand(Server $server, string $source, string $dest): string { $sshConfig = self::serverSshConfiguration($server); @@ -128,24 +133,31 @@ private static function withFirstUseMuxLock(Server $server, string $command): st $lockDirectory = self::muxLockDirectory($server); $lockTimeout = (int) config('constants.ssh.mux_lock_timeout'); + $checkCommand = self::muxControlCommand($server, 'check'); + $script = <<<'SH' cmd=$1 socket=$2 lock=$3 timeout=$4 +check=$5 run_command() { sh -c "$cmd" } -if [ -S "$socket" ]; then +mux_ready() { + [ -S "$socket" ] && sh -c "$check" >/dev/null 2>&1 +} + +if mux_ready; then run_command exit $? fi waited=0 while ! mkdir "$lock" 2>/dev/null; do - if [ -S "$socket" ]; then + if mux_ready; then run_command exit $? fi @@ -171,7 +183,7 @@ private static function withFirstUseMuxLock(Server $server, string $command): st child=$! for _ in 1 2 3 4 5 6 7 8 9 10; do - if [ -S "$socket" ] || ! kill -0 "$child" 2>/dev/null; then + if mux_ready || ! kill -0 "$child" 2>/dev/null; then break fi sleep 0.1 @@ -186,7 +198,8 @@ private static function withFirstUseMuxLock(Server $server, string $command): st .escapeshellarg($command).' ' .escapeshellarg($muxSocket).' ' .escapeshellarg($lockDirectory).' ' - .escapeshellarg((string) $lockTimeout); + .escapeshellarg((string) $lockTimeout).' ' + .escapeshellarg($checkCommand); } private static function escapedUserAtHost(Server $server): string diff --git a/tests/Feature/SshMultiplexingLockTest.php b/tests/Feature/SshMultiplexingLockTest.php index c39d5a48f..ff8ff20bc 100644 --- a/tests/Feature/SshMultiplexingLockTest.php +++ b/tests/Feature/SshMultiplexingLockTest.php @@ -71,8 +71,8 @@ function makeMuxServer(): Server ->toContain("-o ControlPath=/var/www/html/storage/app/ssh/mux/mux_{$server->uuid}") ->toContain("/var/www/html/storage/app/ssh/mux/mux_{$server->uuid}.lock") ->toContain('-o ControlPersist=3600') - ->not->toContain('ssh -fN') - ->not->toContain('-O check'); + ->toContain('-O check') + ->not->toContain('ssh -fN'); Process::assertNothingRan(); }); @@ -105,8 +105,8 @@ function makeMuxServer(): Server ->toContain("-o ControlPath=/var/www/html/storage/app/ssh/mux/mux_{$server->uuid}") ->toContain("/var/www/html/storage/app/ssh/mux/mux_{$server->uuid}.lock") ->toContain('-o ControlPersist=3600') - ->not->toContain('ssh -fN') - ->not->toContain('-O check'); + ->toContain('-O check') + ->not->toContain('ssh -fN'); Process::assertNothingRan(); });