diff --git a/cmd/converge/pagehandler.go b/cmd/converge/pagehandler.go index bdc256e..bcc46d7 100644 --- a/cmd/converge/pagehandler.go +++ b/cmd/converge/pagehandler.go @@ -3,11 +3,10 @@ package main import ( templates2 "converge/pkg/server/templates" "net/http" - "os" ) func pageHandler(w http.ResponseWriter, r *http.Request) { - username, _ := os.LookupEnv("CONVERGE_USERNAME") + username := getAgentSshUser() access := getConvergeAccess(r, username) switch r.URL.Path { diff --git a/cmd/converge/usage.go b/cmd/converge/usage.go index 63304ff..dc53a2a 100644 --- a/cmd/converge/usage.go +++ b/cmd/converge/usage.go @@ -1,9 +1,12 @@ package main import ( + "converge/pkg/server/templates" "log" + "math/rand" "net/http" - "time" + "os" + "strconv" ) func generateCLIExammple(w http.ResponseWriter, r *http.Request) { @@ -14,11 +17,31 @@ func generateCLIExammple(w http.ResponseWriter, r *http.Request) { http.Error(w, "Error parsing form", http.StatusBadRequest) return } - remote_shells := r.Form["remote-shell"] - local_shells := r.Form["local-shhell"] + ids := r.Form["rendez-vous-id"] + id := "" + if len(ids) > 0 { + id = ids[0] + } + if id == "" { + id = strconv.Itoa(rand.Int() % 1000000) + } + remoteShells := r.Form["remote-shell"] + localShells := r.Form["local-shell"] keys := r.FormValue("ssh-keys") - log.Printf("remote_shells %v", remote_shells) - log.Printf("local_shells %v", local_shells) + log.Printf("remote_shells %v", remoteShells) + log.Printf("local_shells %v", localShells) log.Printf("ssh-keys %v", keys) - w.Write([]byte(time.Now().Format(time.DateTime))) + + access := getConvergeAccess(r, getAgentSshUser()) + + usageInputs := templates.NewUsageInputs(id, remoteShells, localShells) + err = templates.ShellUsage(access, usageInputs).Render(r.Context(), w) + if err != nil { + http.Error(w, err.Error(), 500) + } +} + +func getAgentSshUser() string { + username, _ := os.LookupEnv("CONVERGE_USERNAME") + return username } diff --git a/pkg/server/templates/about.templ b/pkg/server/templates/about.templ index dddd15b..90ee0bf 100644 --- a/pkg/server/templates/about.templ +++ b/pkg/server/templates/about.templ @@ -39,6 +39,49 @@ templ About() { When the timeout of a session is near the user is informed about this with messages in the shell.

+ +

end-to-end encryoption

+

ssh keys

+

agent options

+

client access

+ +

Local clients: using ssh with a proxy command

+ +

+ wsproxy is a command that can be used as a proxy command for SSH which performs the connection to the + remote server. This command needs to be downloaded only once (see downloads). It does not depend on + the converge implementation but only on the websocket standards. Other tools that + provide a mapping of stdio to a websocket can also be used instead of wsproxy. +

+ +

Local clients: using SSH with a local TCP forwarding proxy

+ +

+ This option is less convenient than the proxy command because it requires two separate + commands to execute. +

+ +

+ Local clients can connect using regular ssh and sftp commands through a tunnel that + translates a local TCP port to a websocket connection in converge. See + the downloads section. + This runs a local client that allows SSH to port 10000 and connects to converge using + a websocket connection. +

+ +

Remote shell usage

+ +

+ The agent supports a --shells command-line option by which a comma-separated + list of shells can be prepended to the default search path for shells, e.g. + --shells zsh,csh,sh (linux) or cmd,powershell for + windows. +

+ +

+ The agent sets a agentdir environment variable that points to + the directory where the agent is running. +

} diff --git a/pkg/server/templates/constants.go b/pkg/server/templates/constants.go index dac8432..6bf968a 100644 --- a/pkg/server/templates/constants.go +++ b/pkg/server/templates/constants.go @@ -1 +1,5 @@ package templates + +const BASH = "*.sh" +const CMD = "cmd" +const POWERSHELL = "powershell" diff --git a/pkg/server/templates/usage.templ b/pkg/server/templates/usage.templ index 4fe25d8..2c830e3 100644 --- a/pkg/server/templates/usage.templ +++ b/pkg/server/templates/usage.templ @@ -2,10 +2,118 @@ package templates import "converge/pkg/models" + +templ AgentUsage(access models.ConvergeAccess, shells map[string]bool, usageInputs UsageInputs) { +
+

Downloading and running the agent

+ +

+ This is what you run on a remote server, typically in your continuous integration job. +

+ + if shells[BASH] { +
{`
+        `}curl http{access.Secure}://{access.HostPort}/static/agent > agent{`
+        chmod 755 agent
+        `}./agent --id {usageInputs.Id} ws{access.Secure}://{access.HostPort}{`
+        rm -f agent
+        `}
+ } + if shells[CMD] || shells[POWERSHELL] { +
{`
+        `}curl http{access.Secure}://{access.HostPort}/static/agent.exe > agent.exe{`
+        `}agent --id {usageInputs.Id} ws{access.Secure}://{access.HostPort}{`
+        del agent.exe
+        `}
+ } + +

+ The agent has more command-line options than shown here. + Download the agent and run it without arguments to + see all options. +

+

+ Tip: Run the above command locally in a similar shell (for instance in a + docker container) then try to connect to the shell using the commands below. If that + works, then you are all set. +

+ + +

Connecting to the agent

+ +
{`
+          `}ssh -oServerAliveInterval=10 -oProxyCommand="wsproxy ws{access.Secure}://{access.HostPort}/client/{usageInputs.Id}"  { access.Username }{"@localhost"}   {`
+          `}sftp -oServerAliveInterval=10 -oProxyCommand="wsproxy ws{access.Secure}://{access.HostPort}/client/{usageInputs.Id}" { access.Username }{"@localhost"}   {`
+          `}
+ +

Working with the agent

+ + if shells[BASH] { +
{`
+        # cd back to the agent directory
+        cd $agentdir
+
+        # prevent logout when last user exits
+        touch $agentdir/.hold
+       `}
+ + } + if shells[CMD] { +
{`
+        # cd back to the agent directory
+        cd %agentdir%
+
+        # prevent logout when last user exits
+        echo > %agentdir%\.hold
+        `}
+ } + if shells[POWERSHELL] { +
{`
+        # cd back to the agent directory
+        cd $env:agentdir
+
+        # prevent logout when last user exits
+        $null > $env:agentdir\.hold
+        `}
+ } + if shells[CMD] || shells[POWERSHELL] { +

windows

+

+ NOTE: When running the agent on windows, an exit of the remote session using + exit in powershell or command prompt does not terminate the shell completely. + To terminate the client ssh session must be killed by closing the terminal. + Cleanup of remote processes on the agent appears to work properly despite this + problem. It is just that exit of the windows shell (powershell or command prompt) + is not detected properly. +

+ } +
+} + +templ LocalShellUsage(access models.ConvergeAccess, shells map[string]bool, usageInput UsageInputs) { +
+ if shells[BASH] { +

bash

+ } + if shells[CMD] { +

cmd

+ } + if shells[POWERSHELL] { +

powershell

+ } +
+} + +templ ShellUsage(access models.ConvergeAccess, usageInputs UsageInputs) { +
+ @AgentUsage(access, usageInputs.RemoteShells, usageInputs) +
+ @LocalShellUsage(access, usageInputs.LocalShells, usageInputs) +} + + templ Usage(access models.ConvergeAccess) {
- -

Usage