Ferreteria/v0.6/clade/IO/Aspect/Connx/Plug/Shell/Remote/SSH: Difference between revisions
Jump to navigation
Jump to search
(Created page with "{{page/clade/v2 |fam= {{!}} align=right {{!}} <code>{{l/ver/clade|IO\Aspect\Connx\Plug|Shell}}</code> {{!}} align=center {{!}} ⇒ <code>{{l/ver/clade|IO\Aspect\Connx\Plug\Shell|SSH}}</code> {{!}} align=left {{!}} ''(none)'' |alia= {{!-!}} '''ActionIface''' {{!!}} <code>{{l/ver/clade/full|Sys\Events|ItWent}}</code> {{!-!}} '''Base'''* [ca,i] {{!!}} <code>{{l/ver/clade/full|IO\Aspect\Connx\Plug\Shell|Remote}}</code> {{!-!}} '''BufferIface''' {{!!}} <code>{{l/v...") |
(No difference)
|
Revision as of 22:56, 10 December 2025
| ||||||||||||||||||||||||||||||
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;
}
}