Ctrl K
ComunidadGuías…

sshmuxer/httphandler.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package sshmuxer

import (
	"encoding/base64"
	"fmt"
	"log/slog"
	"net/url"
	"strings"

	"github.com/antoniomika/sish/httpmuxer"
	"github.com/antoniomika/sish/utils"
	"github.com/antoniomika/syncmap"
	"github.com/logrusorgru/aurora"
	"github.com/spf13/viper"
	"github.com/vulcand/oxy/v2/roundrobin"
)

// handleHTTPListener handles the creation of the httpHandler
// (or addition for load balancing) and set's up the underlying listeners.
func handleHTTPListener(check *channelForwardMsg, _ string, requestMessages string, listenerHolder *utils.ListenerHolder, state *utils.State, sshConn *utils.SSHConnection, scheme string) (*utils.HTTPHolder, *url.URL, string, error) {
	hostUrl, pH := utils.GetOpenHost(check.Addr, state, sshConn)

	if (hostUrl == nil || !strings.HasPrefix(hostUrl.Host, check.Addr)) && viper.GetBool("force-requested-subdomains") {
		return nil, nil, "", fmt.Errorf("error assigning requested subdomain to tunnel")
	}

	if pH == nil {
		fwd := httpmuxer.NewForwarder()

		lb, err := roundrobin.New(fwd)

		if err != nil {
			slog.Error(
				"error initializing http balancer",
				"err", err,
			)
			return nil, nil, "", err
		}

		hostUrl.Scheme = scheme

		pH = &utils.HTTPHolder{
			HTTPUrl:        hostUrl,
			SSHConnections: syncmap.New[string, *utils.SSHConnection](),
			Forward:        fwd,
			Balancer:       lb,
		}

		state.HTTPListeners.Store(pH.HTTPUrl.String(), pH)
	}

	pH.SSHConnections.Store(listenerHolder.Addr().String(), sshConn)

	serverURL := &url.URL{
		Host:   base64.StdEncoding.EncodeToString([]byte(listenerHolder.Addr().String())),
		Scheme: pH.HTTPUrl.Scheme,
	}

	err := pH.Balancer.UpsertServer(serverURL)
	if err != nil {
		slog.Error(
			"error adding server to balancer",
			"err", err,
		)
	}

	var userPass string
	password, _ := pH.HTTPUrl.User.Password()
	if pH.HTTPUrl.User.Username() != "" || password != "" {
		userPass = fmt.Sprintf("%s:%s@", pH.HTTPUrl.User.Username(), password)
	}

	if viper.GetBool("admin-console") || viper.GetBool("service-console") {
		routeToken := viper.GetString("service-console-token")
		sendToken := false
		routeExists := state.Console.RouteExists(pH.HTTPUrl.String())

		if routeToken == "" {
			sendToken = true

			if routeExists {
				routeToken, _ = state.Console.RouteToken(pH.HTTPUrl.String())
			} else {
				routeToken = utils.RandStringBytesMaskImprSrc(20)
			}
		}

		if !routeExists {
			state.Console.AddRoute(pH.HTTPUrl.String(), routeToken)
		}

		if viper.GetBool("service-console") && sendToken {
			scheme := "http"
			portString := ""
			if state.Ports.HTTPPort != 80 {
				portString = fmt.Sprintf(":%d", state.Ports.HTTPPort)
			}

			if viper.GetBool("https") {
				scheme = "https"
				if state.Ports.HTTPSPort != 443 {
					portString = fmt.Sprintf(":%d", state.Ports.HTTPSPort)
				}
			}

			pathParam := ""
			if pH.HTTPUrl.Path != "/" {
				pathParam = pH.HTTPUrl.Path
			}

			consoleURL := fmt.Sprintf("%s://%s%s%s%s", scheme, userPass, pH.HTTPUrl.Host, portString, pathParam)

			consoleURL = fmt.Sprintf("%s/_sish/console?x-authorization=%s", consoleURL, routeToken)
			requestMessages += sshConn.FormatLog(
				slog.LevelInfo,
				fmt.Sprintf("Service console can be accessed here: %s\r\n", consoleURL),
				"service console",
				"url", consoleURL,
			)
		}
	}

	if !viper.GetBool("proxy-ssl-termination") {
		httpPortString := ""
		if state.Ports.HTTPPort != 80 {
			httpPortString = fmt.Sprintf(":%d", state.Ports.HTTPPort)
		}

		httpURL := fmt.Sprintf("http://%s%s%s%s", userPass, pH.HTTPUrl.Host, httpPortString, pH.HTTPUrl.Path)
		requestMessages += sshConn.FormatLog(
			slog.LevelInfo,
			fmt.Sprintf("%s: %s\r\n", aurora.BgBlue("HTTP"), httpURL),
			"forwarding started",
			"forwardingType", "HTTP",
			"url", httpURL,
		)
		sshConn.Logger().Info(
			"forwarding started",
			"forwardingType", "HTTP",
			"url", fmt.Sprintf("http://%s%s%s", pH.HTTPUrl.Host, httpPortString, pH.HTTPUrl.Path),
			"listenerAddr", listenerHolder.Addr().String(),
		)
	}

	if viper.GetBool("https") || viper.GetBool("proxy-ssl-termination") {
		httpsPortString := ""
		if state.Ports.HTTPSPort != 443 {
			httpsPortString = fmt.Sprintf(":%d", state.Ports.HTTPSPort)
		}

		httpsURL := fmt.Sprintf("https://%s%s%s%s", userPass, pH.HTTPUrl.Host, httpsPortString, pH.HTTPUrl.Path)
		requestMessages += sshConn.FormatLog(
			slog.LevelInfo,
			fmt.Sprintf("%s: %s\r\n", aurora.BgBlue("HTTPS"), httpsURL),
			"forwarding started",
			"forwardingType", "HTTPS",
			"url", httpsURL,
		)
		sshConn.Logger().Info(
			"forwarding started",
			"forwardingType", "HTTPS",
			"url", fmt.Sprintf("https://%s%s%s", pH.HTTPUrl.Host, httpsPortString, pH.HTTPUrl.Path),
			"listenerAddr", listenerHolder.Addr().String(),
		)
	}

	return pH, serverURL, requestMessages, nil
}