154 lines
3.9 KiB
PHP
154 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace Zura\HostingerDeploy\Services;
|
|
|
|
use Illuminate\Support\Facades\Process;
|
|
use Illuminate\Process\Exceptions\ProcessFailedException;
|
|
|
|
class SshConnectionService
|
|
{
|
|
protected string $host;
|
|
protected string $username;
|
|
protected int $port;
|
|
protected int $timeout;
|
|
|
|
public function __construct(string $host, string $username, int $port = 22, int $timeout = 30)
|
|
{
|
|
$this->host = $host;
|
|
$this->username = $username;
|
|
$this->port = $port;
|
|
$this->timeout = $timeout;
|
|
}
|
|
|
|
/**
|
|
* Execute a command on the remote server via SSH.
|
|
*/
|
|
public function execute(string $command): string
|
|
{
|
|
$sshCommand = $this->buildSshCommand($command);
|
|
|
|
try {
|
|
$result = Process::timeout($this->timeout)
|
|
->run($sshCommand);
|
|
|
|
if (!$result->successful()) {
|
|
throw new ProcessFailedException($result);
|
|
}
|
|
|
|
return $result->output();
|
|
} catch (ProcessFailedException $e) {
|
|
throw new \Exception("SSH command failed: " . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute multiple commands on the remote server.
|
|
*/
|
|
public function executeMultiple(array $commands): string
|
|
{
|
|
$combinedCommand = implode(' && ', $commands);
|
|
return $this->execute($combinedCommand);
|
|
}
|
|
|
|
/**
|
|
* Check if SSH connection is working.
|
|
*/
|
|
public function testConnection(): bool
|
|
{
|
|
try {
|
|
$this->execute('echo "SSH connection test successful"');
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the public key from the server.
|
|
*/
|
|
public function getPublicKey(): ?string
|
|
{
|
|
try {
|
|
return trim($this->execute('cat ~/.ssh/id_rsa.pub 2>/dev/null || echo ""'));
|
|
} catch (\Exception $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the private key from the server.
|
|
*/
|
|
public function getPrivateKey(): ?string
|
|
{
|
|
try {
|
|
return trim($this->execute('cat ~/.ssh/id_rsa 2>/dev/null || echo ""'));
|
|
} catch (\Exception $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate SSH key pair on the server if it doesn't exist.
|
|
*/
|
|
public function generateSshKey(): bool
|
|
{
|
|
try {
|
|
$this->execute('ssh-keygen -t rsa -b 4096 -C "github-deploy-key" -N "" -f ~/.ssh/id_rsa');
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a public key to authorized_keys.
|
|
*/
|
|
public function addToAuthorizedKeys(string $publicKey): bool
|
|
{
|
|
try {
|
|
$this->execute("echo '{$publicKey}' >> ~/.ssh/authorized_keys");
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if SSH key exists on the server.
|
|
*/
|
|
public function sshKeyExists(): bool
|
|
{
|
|
try {
|
|
$result = $this->execute('test -f ~/.ssh/id_rsa && echo "exists" || echo "not_exists"');
|
|
return trim($result) === 'exists';
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build the SSH command string.
|
|
*/
|
|
protected function buildSshCommand(string $command): string
|
|
{
|
|
$sshOptions = [
|
|
'-p ' . $this->port,
|
|
'-o ConnectTimeout=' . $this->timeout,
|
|
'-o StrictHostKeyChecking=no',
|
|
'-o UserKnownHostsFile=/dev/null',
|
|
];
|
|
|
|
$sshCommand = 'ssh ' . implode(' ', $sshOptions) . ' ' . $this->username . '@' . $this->host . ' "' . addslashes($command) . '"';
|
|
|
|
return $sshCommand;
|
|
}
|
|
|
|
/**
|
|
* Get connection details for display.
|
|
*/
|
|
public function getConnectionString(): string
|
|
{
|
|
return "ssh -p {$this->port} {$this->username}@{$this->host}";
|
|
}
|
|
}
|