From 04aeccdeb58313234489eae7df74a77a2b9ca268 Mon Sep 17 00:00:00 2001 From: Lewis Larsen Date: Tue, 23 Jul 2024 20:14:22 +0100 Subject: [PATCH] refactor: Wip key removal --- .../Contracts/KeyRemovalNotifierInterface.php | 14 -- .../Contracts/SSHClientInterface.php | 12 -- .../Contracts/SSHKeyProviderInterface.php | 12 -- .../RemoveSSHKey/RemoveSSHKeyService.php | 156 ++++++++++++------ app/helpers.php | 4 + 5 files changed, 108 insertions(+), 90 deletions(-) delete mode 100644 app/Services/RemoveSSHKey/Contracts/KeyRemovalNotifierInterface.php delete mode 100644 app/Services/RemoveSSHKey/Contracts/SSHClientInterface.php delete mode 100644 app/Services/RemoveSSHKey/Contracts/SSHKeyProviderInterface.php diff --git a/app/Services/RemoveSSHKey/Contracts/KeyRemovalNotifierInterface.php b/app/Services/RemoveSSHKey/Contracts/KeyRemovalNotifierInterface.php deleted file mode 100644 index 24dda5eb..00000000 --- a/app/Services/RemoveSSHKey/Contracts/KeyRemovalNotifierInterface.php +++ /dev/null @@ -1,14 +0,0 @@ -logger = $logger; + } /** * Handle the SSH key removal process for a given remote server. * + * This method orchestrates the process of removing an SSH key from a remote server, + * including establishing a connection, executing the removal command, and notifying + * the user of the result. + * * @param RemoteServer $remoteServer The remote server to remove the SSH key from */ public function handle(RemoteServer $remoteServer): void { - Log::info('Initiating SSH key removal process.', ['server_id' => $remoteServer->getAttribute('id')]); + $this->logger->info("Initiating SSH key removal for server: {$remoteServer->label}"); try { - $this->connectToServer($remoteServer); - $this->removeKeyFromServer($remoteServer); - $this->notifySuccess($remoteServer); - } catch (SSHConnectionException $e) { + $connection = $this->establishConnection($remoteServer); + $publicKey = $this->getSSHPublicKey(); + + if (!$this->determineKeyExistence($connection, $publicKey)) { + $this->logger->info("SSH key does not exist on server: {$remoteServer->label}"); + $this->handleSuccessfulRemoval($remoteServer); + return; + } + + $result = $this->executeRemovalCommand($connection, $publicKey); + $this->processRemovalResult($remoteServer, $result); + + } catch (ConnectionException $e) { $this->handleConnectionFailure($remoteServer, $e); } } /** - * Establish an SSH connection to the remote server. + * Establish a connection to the remote server. * - * @param RemoteServer $remoteServer The remote server to connect to + * @return Connection The connection instance. * - * @throws SSHConnectionException If unable to connect to the remote server + * @throws ConnectionException */ - private function connectToServer(RemoteServer $remoteServer): void + private function establishConnection(RemoteServer $remoteServer): Connection { - $privateKey = $this->sshKeyProvider->getPrivateKey(); - - if (! $this->sshClient->connect( - $remoteServer->getAttribute('ip_address'), - $remoteServer->getAttribute('port'), - $remoteServer->getAttribute('username'), - $privateKey - )) { - throw new SSHConnectionException('Failed to connect to remote server'); - } + $this->logger->debug("Attempting to connect to server: {$remoteServer->label}"); + + return ServerConnection::connectFromModel($remoteServer)->establish(); + } + + /** + * Get the SSH public key. + */ + private function getSSHPublicKey(): string + { + //TODO: Replace with a ServerConnectionManager readonly implementation that gets the public key + return get_ssh_public_key(); + } + + /** + * Check if the SSH public key exists on the remote server. + */ + private function determineKeyExistence(Connection $connection, string $publicKey): bool + { + $command = sprintf("grep -q '%s' ~/.ssh/authorized_keys", preg_quote($publicKey, '/')); + $this->logger->debug("Checking if SSH key exists with command: {$command}"); + + $result = $connection->run($command); + + return $result === ''; } /** - * Remove the SSH key from the remote server. + * Execute the SSH key removal command on the remote server. * - * @param RemoteServer $remoteServer The remote server to remove the key from + * @return string The result of the command execution */ - private function removeKeyFromServer(RemoteServer $remoteServer): void + private function executeRemovalCommand(Connection $connection, string $publicKey): string { - $publicKey = $this->sshKeyProvider->getPublicKey(); $command = sprintf("sed -i -e '/^%s/d' ~/.ssh/authorized_keys", preg_quote($publicKey, '/')); + $this->logger->debug("Executing removal command: {$command}"); - $this->sshClient->executeCommand($command); + return $connection->run($command); + } - Log::info('SSH key removed from server.', ['server_id' => $remoteServer->getAttribute('id')]); + /** + * Process the result of the key removal attempt. + */ + private function processRemovalResult(RemoteServer $remoteServer, string $result): void + { + if ($this->isRemovalSuccessful($result)) { + $this->handleSuccessfulRemoval($remoteServer); + } else { + $this->handleFailedRemoval($remoteServer, $result); + } } /** - * Notify the user of successful key removal. - * - * @param RemoteServer $remoteServer The remote server the key was removed from + * Determine if the key removal was successful based on the command result. */ - private function notifySuccess(RemoteServer $remoteServer): void + private function isRemovalSuccessful(string $result): bool { - $this->keyRemovalNotifier->notifySuccess($remoteServer); - Log::info('User notified of successful key removal.', ['server_id' => $remoteServer->getAttribute('id')]); + return $result === '' || str_contains($result, 'Successfully removed'); } /** - * Handle and log connection failures, and notify the user. - * - * @param RemoteServer $remoteServer The remote server that failed to connect - * @param SSHConnectionException $sshConnectionException The exception that occurred + * Handle successful key removal. + */ + private function handleSuccessfulRemoval(RemoteServer $remoteServer): void + { + $this->logger->info("Successfully removed SSH key from server: {$remoteServer->label}"); + + Mail::to($remoteServer->user)->queue(new SuccessfullyRemovedKey($remoteServer)); + } + + /** + * Handle failed key removal. + */ + private function handleFailedRemoval(RemoteServer $remoteServer, string $result): void + { + $this->logger->error("Failed to remove SSH key from server: {$remoteServer->label}. Result: {$result}"); + + Mail::to($remoteServer->user)->queue(new FailedToRemoveKey($remoteServer)); + } + + /** + * Handle connection failure. */ - private function handleConnectionFailure(RemoteServer $remoteServer, SSHConnectionException $sshConnectionException): void + private function handleConnectionFailure(RemoteServer $remoteServer, ConnectionException $exception): void { - Log::error('Failed to connect to remote server for key removal.', [ - 'server_id' => $remoteServer->getAttribute('id'), - 'error' => $sshConnectionException->getMessage(), - ]); + $this->logger->error("Failed to connect to server: {$remoteServer->label}. Error: {$exception->getMessage()}"); - $this->keyRemovalNotifier->notifyFailure($remoteServer, $sshConnectionException->getMessage()); + Mail::to($remoteServer->user)->queue(new FailedToRemoveKey($remoteServer)); } } diff --git a/app/helpers.php b/app/helpers.php index 4cb23842..3faec501 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -16,6 +16,8 @@ function ssh_keys_exist(): bool } /** + * @deprecated Please use the ServerConnectionManager static implementation. + * * Get the contents of the SSH public key. * * @return string The contents of the SSH public key. @@ -35,6 +37,8 @@ function get_ssh_public_key(): string } /** + * @deprecated Please use the ServerConnectionManager static implementation. + * * Get the contents of the SSH private key. * * @return string The contents of the SSH private key.