Ferreteria/v0.6/clade/IO/Aspect/Connx/Plug/Shell/Remote/SSH: Difference between revisions

From Woozle Writes Code
< Ferreteria‎ | v0.6‎ | clade‎ | IO‎ | Aspect‎ | Connx‎ | Plug‎ | Shell‎ | Remote
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 edit summary
 
Line 1: Line 1:
{{page/clade/v2
{{page/clade/v2
|fam=
|fam=
{{!}} align=right  {{!}} <code>{{l/ver/clade|IO\Aspect\Connx\Plug|Shell}}</code>
{{!}} align=right  {{!}} <code>{{l/ver/clade|IO\Aspect\Connx\Plug\Shell|Remote}}</code>
{{!}} align=center {{!}} &rArr; <code>{{l/ver/clade|IO\Aspect\Connx\Plug\Shell|SSH}}</code>
{{!}} align=center {{!}} &rArr; <code>{{l/ver/clade|IO\Aspect\Connx\Plug\Shell\Remote|SSH}}</code> &rArr;
{{!}} align=left  {{!}} ''(none)''
{{!}} align=left  {{!}} ''(none)''


Line 17: Line 17:


}}
}}
==About==
* '''Purpose''': a secure shell (ssh) connection to a remote machine
==History==
* '''{{fmt/date|2024|11|02}}''' started
* '''{{fmt/date|2024|11|19}}''' moved from [WFe]<code>Config\Def\Connex\Shell</code> -> [WFe]<code>IO\Connex\Shell</code>
* '''{{fmt/date|2024|11|26}}''' moved from [WFe]<code>IO\Connex\Shell\xSecure</code> -> [WFe]<code>IO\Connex\Aux\ssh\xShell</code>
* '''{{fmt/date|2025|03|15}}''' moved from [WFe]<code>IO\Connx\Aux\ssh\xRemote</code> -> [WFe]<code>IO\Connx\Shell\Remote\xSSH</code>
** ...and re-parented from [WFe]<code>IO\Connx\xShell</code> &rArr; [WFe]<code>IO\Connx\Shell\Remote</code>
* '''{{fmt/date|2025|03|16}}''' Removing the <code>$oICreds</code> parameter from <code>NewTunnel()</code>, because as far as I can tell it's just supposed to be the same creds stored in <code>Creds()</code>
** Also not sure if the <code>$nPortLocal</code> parameter still makes sense... shouldn't that be in the Creds data as well?
* '''{{fmt/date|2025|05|27}}''' more re-namespacing
==Code==
==Code==
''as of {{fmt/date|2025|12|10}}:''
* [[/removed/]]
* ''as of {{fmt/date|2025|12|10}}:''
{{fmt/php/block|1=
{{fmt/php/block|1=
interface iSSH extends BaseIface {
interface iSSH extends BaseIface {

Latest revision as of 00:23, 11 December 2025

clade: IO\Aspect\Connx\Plug\Shell\Remote\SSH
Clade Family
Remote SSH (none)
Clade Aliases
Alias Clade
ActionIface Sys\Events\ItWent
Base* [ca,i] IO\Aspect\Connx\Plug\Shell\Remote
BufferIface IO\Aspect\Connx\Buffer
CommOpIface Sys\Events\ItWent\CommOp
CredsIface IO\Aspect\Creds
ProcIface IO\Aspect\Connx\Process
QRes* [c,i] Data\Mem\QVar\Res
SockIface IO\Aspect\Socket
Tunnel* [c,i] IO\Aspect\Connx\aux\Tunnel
Subpages

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
  • 2025-03-16 Removing the $oICreds parameter from NewTunnel(), because as far as I can tell it's just supposed to be the same creds stored in Creds()
    • Also not sure if the $nPortLocal parameter still makes sense... shouldn't that be in the Creds data as well?
  • 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;
    }
}