Alternative contextpath is now supported.

This will simplify hosting in cases where you have no control over DNS but only over one domain.
This commit is contained in:
Erik Brakkee 2024-08-03 23:10:57 +02:00
parent 9456665a6f
commit 75e1bd77ba
5 changed files with 45 additions and 24 deletions

View File

@ -27,9 +27,10 @@ func parsePublicId(path string) (publicId string, _ error) {
return matches[1], nil return matches[1], nil
} }
func catchAllHandler(w http.ResponseWriter, r *http.Request) { func catchAllHandler(contextPath string) func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/docs", http.StatusFound) return func(w http.ResponseWriter, r *http.Request) {
return http.Redirect(w, r, contextPath+"/docs", http.StatusFound)
}
} }
func printHelp(msg string) { func printHelp(msg string) {
@ -48,8 +49,13 @@ func printHelp(msg string) {
"an embedded SSH server to provide interactive access to the end-user. This works\n" + "an embedded SSH server to provide interactive access to the end-user. This works\n" +
"both on linux and on windows.\n" + "both on linux and on windows.\n" +
"\n" + "\n" +
"-s <contentdir>: directory where static content of converge is placed\n" + "Options\n" +
"-d <downloaddir>: directory where downloads of converge are placed\n" "-s <contentdir>: directory where static content of converge is placed\n" +
"-d <downloaddir>: directory where downloads of converge are placed\n" +
"-c <contextpath>: by default all content is served at /. Use this option to specify\n" +
" a different context path. For instance to host converge at a base\n" +
" URL of https://example.com/converge, specify /converg (and without\n" +
" trailing slash. "
fmt.Fprintln(os.Stderr, helpText) fmt.Fprintln(os.Stderr, helpText)
os.Exit(1) os.Exit(1)
} }
@ -58,6 +64,7 @@ func main() {
downloaddir := "." downloaddir := "."
staticdir := "../static" staticdir := "../static"
contextpath := ""
args := os.Args[1:] args := os.Args[1:]
for len(args) > 0 && strings.HasPrefix(args[0], "-") { for len(args) > 0 && strings.HasPrefix(args[0], "-") {
@ -74,6 +81,12 @@ func main() {
} }
staticdir = args[1] staticdir = args[1]
args = args[1:] args = args[1:]
case "-c":
if len(args) <= 1 {
printHelp("The -c option expects an argument")
}
contextpath = args[1]
args = args[1:]
default: default:
printHelp("Unknown option " + args[0]) printHelp("Unknown option " + args[0])
} }
@ -162,7 +175,6 @@ func main() {
// TODO remove, simulate contextpath // TODO remove, simulate contextpath
contextpath := ""
http.HandleFunc(contextpath+"/agent/", registrationService.Handle) http.HandleFunc(contextpath+"/agent/", registrationService.Handle)
http.HandleFunc(contextpath+"/client/", clientService.Handle) http.HandleFunc(contextpath+"/client/", clientService.Handle)
http.HandleFunc(contextpath+"/ws/sessions", sessionService.Handle) http.HandleFunc(contextpath+"/ws/sessions", sessionService.Handle)
@ -176,11 +188,7 @@ func main() {
// TODO remove for testing contextpath // TODO remove for testing contextpath
catchAllHandler2 := func(w http.ResponseWriter, r *http.Request) { http.HandleFunc(contextpath+"/", catchAllHandler(contextpath))
http.Redirect(w, r, contextpath+"/docs", http.StatusFound)
return
}
http.HandleFunc(contextpath+"/", catchAllHandler2)
// create usage generator // create usage generator
http.HandleFunc(contextpath+"/usage", generateCLIExammple) http.HandleFunc(contextpath+"/usage", generateCLIExammple)

View File

@ -3,11 +3,23 @@ package main
import ( import (
"converge/pkg/models" "converge/pkg/models"
"converge/pkg/server/converge" "converge/pkg/server/converge"
"log"
"net/http" "net/http"
"regexp"
"strings" "strings"
) )
func getConvergeAccess(r *http.Request, sshRemoteUser string) models.ConvergeAccess { func getConvergeAccess(r *http.Request, sshRemoteUser string) models.ConvergeAccess {
pattern := regexp.MustCompile("^(.*)/usage$")
matches := pattern.FindStringSubmatch(r.URL.Path)
contextPath := ""
if len(matches) != 2 {
log.Printf("Cannot determine context path for %s, assumming it is empty", r.URL.Path)
} else {
contextPath = matches[1]
}
secure := "" secure := ""
if r.TLS == nil { if r.TLS == nil {
secure = "" secure = ""
@ -27,9 +39,10 @@ func getConvergeAccess(r *http.Request, sshRemoteUser string) models.ConvergeAcc
if err != nil { if err != nil {
panic(err) panic(err)
} }
baseUrl := strings.ReplaceAll(r.Host+contextPath, "//", "/")
return models.ConvergeAccess{ return models.ConvergeAccess{
Secure: secure, Secure: secure,
HostPort: r.Host, BaseUrl: baseUrl,
Location: location, Location: location,
Username: sshRemoteUser, Username: sshRemoteUser,
} }

View File

@ -39,7 +39,7 @@ func main() {
access := models.ConvergeAccess{ access := models.ConvergeAccess{
Secure: "s", Secure: "s",
HostPort: "example.com", BaseUrl: "example.com",
Location: netherlands, Location: netherlands,
Username: "converge", Username: "converge",
} }

View File

@ -5,7 +5,7 @@ import "time"
type ConvergeAccess struct { type ConvergeAccess struct {
// 's" when secure, "" otherwise // 's" when secure, "" otherwise
Secure string Secure string
HostPort string BaseUrl string
Location *time.Location Location *time.Location
Username string Username string
} }

View File

@ -13,23 +13,23 @@ templ AgentUsage(access models.ConvergeAccess, usageInputs UsageInputs) {
if usageInputs.RemoteShells[BASH] { if usageInputs.RemoteShells[BASH] {
<pre>{addSshKeys(BASH, usageInputs.SshKeys)} <pre>{addSshKeys(BASH, usageInputs.SshKeys)}
curl --fail-with-body http{access.Secure}://{access.HostPort}/downloads/agent > agent{` curl --fail-with-body http{access.Secure}://{access.BaseUrl}/downloads/agent > agent{`
chmod 755 agent chmod 755 agent
`}./agent --id {usageInputs.Id} ws{access.Secure}://{access.HostPort}{` `}./agent --id {usageInputs.Id} ws{access.Secure}://{access.BaseUrl}{`
rm -f agent rm -f agent
`}</pre> `}</pre>
} }
if usageInputs.RemoteShells[CMD] { if usageInputs.RemoteShells[CMD] {
<pre>{addSshKeys(CMD, usageInputs.SshKeys)} <pre>{addSshKeys(CMD, usageInputs.SshKeys)}
curl --fail-with-body http{access.Secure}://{access.HostPort}/downloads/agent.exe > agent.exe{` curl --fail-with-body http{access.Secure}://{access.BaseUrl}/downloads/agent.exe > agent.exe{`
`}agent --id {usageInputs.Id} ws{access.Secure}://{access.HostPort}{` `}agent --id {usageInputs.Id} ws{access.Secure}://{access.BaseUrl}{`
del agent.exe del agent.exe
`}</pre> `}</pre>
} }
if usageInputs.RemoteShells[POWERSHELL] { if usageInputs.RemoteShells[POWERSHELL] {
<pre>{addSshKeys(POWERSHELL, usageInputs.SshKeys)} <pre>{addSshKeys(POWERSHELL, usageInputs.SshKeys)}
curl --fail-with-body http{access.Secure}://{access.HostPort}/downloads/agent.exe > agent.exe{` curl --fail-with-body http{access.Secure}://{access.BaseUrl}/downloads/agent.exe > agent.exe{`
`}agent --id {usageInputs.Id} ws{access.Secure}://{access.HostPort}{` `}agent --id {usageInputs.Id} ws{access.Secure}://{access.BaseUrl}{`
del agent.exe del agent.exe
`}</pre> `}</pre>
} }
@ -55,8 +55,8 @@ templ AgentUsage(access models.ConvergeAccess, usageInputs UsageInputs) {
</p> </p>
<pre>{` <pre>{`
`}ssh -oServerAliveInterval=10 -oProxyCommand="wsproxy ws{access.Secure}://{access.HostPort}/client/{usageInputs.Id}" { access.Username }{"@localhost"} {` `}ssh -oServerAliveInterval=10 -oProxyCommand="wsproxy ws{access.Secure}://{access.BaseUrl}/client/{usageInputs.Id}" { access.Username }{"@localhost"} {`
`}sftp -oServerAliveInterval=10 -oProxyCommand="wsproxy ws{access.Secure}://{access.HostPort}/client/{usageInputs.Id}" { access.Username }{"@localhost"} {` `}sftp -oServerAliveInterval=10 -oProxyCommand="wsproxy ws{access.Secure}://{access.BaseUrl}/client/{usageInputs.Id}" { access.Username }{"@localhost"} {`
`}</pre> `}</pre>
<p>This requires the <code>wsproxy</code> utility which is available in the <p>This requires the <code>wsproxy</code> utility which is available in the
@ -79,8 +79,8 @@ templ AgentUsage(access models.ConvergeAccess, usageInputs UsageInputs) {
using: using:
</p> </p>
<pre>{` <pre>{`
`}tcptows ws{access.Secure}://{access.HostPort}/client/{usageInputs.Id} {` `}tcptows ws{access.Secure}://{access.BaseUrl}/client/{usageInputs.Id} {`
`}tcptows ws{access.Secure}://{access.HostPort}/client/{usageInputs.Id} {` `}tcptows ws{access.Secure}://{access.BaseUrl}/client/{usageInputs.Id} {`
`}</pre> `}</pre>
<h2>Working with the agent</h2> <h2>Working with the agent</h2>