Some checks failed
Docker Build and Push / build-and-push (push) Has been cancelled
177 lines
3.6 KiB
Go
177 lines
3.6 KiB
Go
package session
|
|
|
|
import (
|
|
"bytes"
|
|
"log"
|
|
"net"
|
|
"sync"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
const (
|
|
INITIALIZING Status = "INITIALIZING"
|
|
RUNNING Status = "RUNNING"
|
|
SETUP Status = "SETUP"
|
|
)
|
|
|
|
type TunnelType string
|
|
|
|
const (
|
|
HTTP TunnelType = "http"
|
|
TCP TunnelType = "tcp"
|
|
)
|
|
|
|
type SessionLifecycle interface {
|
|
Close() error
|
|
WaitForRunningStatus()
|
|
}
|
|
|
|
type SessionCloser interface {
|
|
Close() error
|
|
}
|
|
|
|
type InteractionController interface {
|
|
SendMessage(message string)
|
|
HandleUserInput()
|
|
HandleCommand(conn ssh.Channel, command string, inSlugEditMode *bool, editSlug *string, buf *bytes.Buffer)
|
|
HandleSlugEditMode(conn ssh.Channel, inSlugEditMode *bool, editSlug *string, char byte, buf *bytes.Buffer)
|
|
HandleSlugSave(conn ssh.Channel, inSlugEditMode *bool, editSlug *string, buf *bytes.Buffer)
|
|
HandleSlugCancel(conn ssh.Channel, inSlugEditMode *bool, buf *bytes.Buffer)
|
|
HandleSlugUpdateError()
|
|
ShowWelcomeMessage()
|
|
DisplaySlugEditor()
|
|
}
|
|
|
|
type ForwardingController interface {
|
|
HandleGlobalRequest(ch <-chan *ssh.Request)
|
|
HandleTCPIPForward(req *ssh.Request)
|
|
HandleHTTPForward(req *ssh.Request, port uint16)
|
|
HandleTCPForward(req *ssh.Request, addr string, port uint16)
|
|
AcceptTCPConnections()
|
|
}
|
|
|
|
type Session interface {
|
|
SessionLifecycle
|
|
InteractionController
|
|
ForwardingController
|
|
}
|
|
|
|
type Lifecycle struct {
|
|
Status Status
|
|
}
|
|
|
|
type Forwarder struct {
|
|
Listener net.Listener
|
|
TunnelType TunnelType
|
|
ForwardedPort uint16
|
|
|
|
getSlug func() string
|
|
setSlug func(string)
|
|
}
|
|
|
|
type ForwarderInfo interface {
|
|
GetTunnelType() TunnelType
|
|
GetForwardedPort() uint16
|
|
}
|
|
|
|
func (f *Forwarder) GetTunnelType() TunnelType {
|
|
return f.TunnelType
|
|
}
|
|
|
|
func (f *Forwarder) GetForwardedPort() uint16 {
|
|
return f.ForwardedPort
|
|
}
|
|
|
|
type Interaction struct {
|
|
CommandBuffer *bytes.Buffer
|
|
EditMode bool
|
|
EditSlug string
|
|
channel ssh.Channel
|
|
|
|
getSlug func() string
|
|
setSlug func(string)
|
|
|
|
session SessionCloser
|
|
|
|
forwarder ForwarderInfo
|
|
}
|
|
type SSHSession struct {
|
|
Lifecycle *Lifecycle
|
|
Interaction *Interaction
|
|
Forwarder *Forwarder
|
|
|
|
Conn *ssh.ServerConn
|
|
channel ssh.Channel
|
|
|
|
slug string
|
|
slugMu sync.RWMutex
|
|
}
|
|
|
|
func New(conn *ssh.ServerConn, forwardingReq <-chan *ssh.Request, sshChan <-chan ssh.NewChannel) {
|
|
session := SSHSession{
|
|
Lifecycle: &Lifecycle{
|
|
Status: INITIALIZING,
|
|
},
|
|
Interaction: &Interaction{
|
|
CommandBuffer: new(bytes.Buffer),
|
|
EditMode: false,
|
|
EditSlug: "",
|
|
channel: nil,
|
|
getSlug: nil,
|
|
setSlug: nil,
|
|
session: nil,
|
|
forwarder: nil,
|
|
},
|
|
Forwarder: &Forwarder{
|
|
Listener: nil,
|
|
TunnelType: "",
|
|
ForwardedPort: 0,
|
|
getSlug: nil,
|
|
setSlug: nil,
|
|
},
|
|
Conn: conn,
|
|
channel: nil,
|
|
slug: "",
|
|
}
|
|
|
|
session.Forwarder.getSlug = session.GetSlug
|
|
session.Forwarder.setSlug = session.SetSlug
|
|
session.Interaction.getSlug = session.GetSlug
|
|
session.Interaction.setSlug = session.SetSlug
|
|
session.Interaction.session = &session
|
|
session.Interaction.forwarder = session.Forwarder
|
|
|
|
go func() {
|
|
go session.waitForRunningStatus()
|
|
|
|
for channel := range sshChan {
|
|
ch, reqs, _ := channel.Accept()
|
|
if session.channel == nil {
|
|
session.channel = ch
|
|
session.Interaction.channel = ch
|
|
session.Lifecycle.Status = SETUP
|
|
go session.HandleGlobalRequest(forwardingReq)
|
|
}
|
|
go session.HandleGlobalRequest(reqs)
|
|
}
|
|
err := session.Close()
|
|
if err != nil {
|
|
log.Printf("failed to close session: %v", err)
|
|
}
|
|
return
|
|
}()
|
|
}
|
|
|
|
func (s *SSHSession) GetSlug() string {
|
|
s.slugMu.RLock()
|
|
defer s.slugMu.RUnlock()
|
|
return s.slug
|
|
}
|
|
|
|
func (s *SSHSession) SetSlug(slug string) {
|
|
s.slugMu.Lock()
|
|
s.slug = slug
|
|
s.slugMu.Unlock()
|
|
}
|