Ferreteria/v0.6/clade/IO/Aspect/Connx/Plug/Shell/Remote/SSH
Jump to navigation
Jump to search
| ||||||||||||||||||||||||||||||
About
- Purpose: a secure shell (ssh) connection to a remote machine
History
- 2024-11-02 started
- 2024-11-19 moved from [WFe]
Config\Def\Connex\Shell-> [WFe]IO\Connex\Shell - 2024-11-26 moved from [WFe]
IO\Connex\Shell\xSecure-> [WFe]IO\Connex\Aux\ssh\xShell - 2025-03-15 moved from [WFe]
IO\Connx\Aux\ssh\xRemote-> [WFe]IO\Connx\Shell\Remote\xSSH- ...and re-parented from [WFe]
IO\Connx\xShell⇒ [WFe]IO\Connx\Shell\Remote
- ...and re-parented from [WFe]
- 2025-03-16 Removing the
$oICredsparameter fromNewTunnel(), because as far as I can tell it's just supposed to be the same creds stored inCreds()- Also not sure if the
$nPortLocalparameter still makes sense... shouldn't that be in the Creds data as well?
- Also not sure if the
- 2025-05-27 more re-namespacing
Code
interface iSSH extends BaseIface {
// OBJECTS
function OCred() : CredsIface;
}
class cSSH extends BaseClass implements iSSH {
// ++ CONFIG ++ //
public function SType() : string { return 'ssh plug'; }
// -- CONFIG -- //
// ++ OBJECTS ++ //
public function OCred() : CredsIface { return $this->OSock()->OCred(); }
// -- OBJECTS -- //
// ++ LIFECYCLE ++ //
protected function ActualOpen() : ActionIface {
$oAct = $this->HowItWent();
// [+STANDARD CODE]: get connection specs
$oCred = $this->OCred();
$oSock = $this->OSock();
$oHost = $oSock->OHost();
$sUser = $oCred->QSUser()->GetIt();
$sHost = $oHost->QSAddr()->GetIt();
$onPort = $oHost->QIPort();
// [-STANDARD CODE]
if ($onPort->HasIt()) {
$nPort = $onPort->GetIt();
$ftRem = "$sUser@$sHost:$nPort";
} else {
$ftRem = "$sUser@$sHost";
}
echo "Opening SSH connection to [$ftRem]...".CRLF;
try {
if ($onPort->HasIt()) {
$rSSH = @ssh2_connect($sHost, $nPort);
} else {
$rSSH = @ssh2_connect($sHost); // use ssh2_connect's default port
}
} catch (\Exception $e) {
$rSSH = FALSE;
echo $e;
$this->AmHere('TODO 2025-12-07: better diagnostics');
}
if ($rSSH === FALSE) {
$arErr = error_get_last();
$oScrn = self::Screen();
echo $oScrn->ErrorIt('Connection error').': '.$arErr['message'].CRLF;
die();
}
$this->QNative()->SetIt($rSSH);
$ftUser = self::Screen()->GreenIt($sUser);
echo "Authenticating remote user '$ftUser'...".CRLF;
@$rok = ssh2_auth_agent($rSSH,$sUser);
$ok = ($rok !== FALSE);
$oAct->SetOkay($ok);
if ($ok) {
$oAct->AddMsgString("User authenticated.");
} else {
$oAct->AddMsgString("SSH connection failed.");
}
return $oAct;
}
protected function ActualShut() : ActionIface {
$rConn = $this->QNative()->GetIt();
$ok = ssh2_disconnect($rConn);
$oAct = $this->HowItWent();
$oAct->SetOkay($ok);
return $oAct;
}
// -- LIFECYCLE -- //
// ++ UI ++ //
public function DescribeInline() : string { return 'ssh'; }
// -- UI -- //
// ++ OBJECTS ++ //
private $osNat = NULL; protected function QNative() : QResIface { return $this->osNat ?? ($this->osNat = QResClass::AsNew()); }
public function NewTunnel(CredsIface $oICreds, ?int $nPortLocal=NULL) : TunnelIface {
return new TunnelClass($this->Creds(),$oICreds,$nPortLocal);
}
// -- OBJECTS -- //
// ++ ACTION ++ //
public function DoCommand(string|array $saCmd, BufferIface $oBuff, ?CommOpIface $oAct=NULL) : CommOpIface {
$sCmdFull = $this->WrapCommand($saCmd);
$oAct = parent::DoCommand($sCmdFull,$oBuff,$oAct);
return $oAct;
}
public function RunProcess(string|array $saCmd) : ProcIface {
$sCmdFull = $this->WrapCommand($saCmd);
return parent::RunProcess($sCmdFull);
}
// -- ACTION -- //
// ++ FIGURING ++ //
// 2025-03-29 FUTURE: maybe this should always return an array -- but that's harder to debug.
protected function WrapCommand(string|array $saCmd) : string {
// [+STANDARD CODE]: get connection specs
$oCred = $this->OCred();
$oSock = $this->OSock();
$oHost = $oSock->OHost();
$sUser = $oCred->QSUser()->GetIt();
$sHost = $oHost->QSAddr()->GetIt();
$onPort = $oHost->QIPort();
// [-STANDARD CODE]
if ($onPort->HasIt()) {
$nPort = $onPort->GetIt();
$sPort = ' -p '.$nPort;
} else {
$sPort = '';
}
$sCmdSafe = escapeshellarg($saCmd);
$sCmdFull = "ssh$sPort $sUser@$sHost $sCmdSafe";
return $sCmdFull;
}
}