mirror of
https://github.com/khairul169/vaulterm.git
synced 2025-04-28 16:49:39 +07:00
160 lines
3.8 KiB
Go
160 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/coder/websocket"
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
// Replace with actual SSH server credentials
|
|
var sshHost = "10.0.0.102"
|
|
var sshUser = "root"
|
|
var sshPassword = "ausya2"
|
|
|
|
func sshWebSocketHandler(w http.ResponseWriter, r *http.Request) {
|
|
wsConn, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
|
OriginPatterns: []string{"*"}, // Adjust origin policy as needed
|
|
})
|
|
if err != nil {
|
|
log.Printf("failed to accept websocket: %v", err)
|
|
return
|
|
}
|
|
|
|
// Set up SSH client configuration
|
|
sshConfig := &ssh.ClientConfig{
|
|
User: sshUser,
|
|
Auth: []ssh.AuthMethod{
|
|
ssh.Password(sshPassword),
|
|
},
|
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
|
}
|
|
|
|
// Connect to SSH server
|
|
sshConn, err := ssh.Dial("tcp", sshHost+":22", sshConfig)
|
|
if err != nil {
|
|
wsConn.Write(context.Background(), websocket.MessageText, []byte(err.Error()))
|
|
wsConn.Close(websocket.StatusInternalError, "failed to connect to SSH")
|
|
return
|
|
}
|
|
defer sshConn.Close()
|
|
|
|
// Start an SSH shell session
|
|
session, err := sshConn.NewSession()
|
|
if err != nil {
|
|
wsConn.Write(context.Background(), websocket.MessageText, []byte(err.Error()))
|
|
wsConn.Close(websocket.StatusInternalError, "failed to start SSH session")
|
|
return
|
|
}
|
|
defer session.Close()
|
|
|
|
stdoutPipe, err := session.StdoutPipe()
|
|
if err != nil {
|
|
wsConn.Close(websocket.StatusInternalError, "failed to get stdout pipe")
|
|
return
|
|
}
|
|
|
|
stderrPipe, err := session.StderrPipe()
|
|
if err != nil {
|
|
wsConn.Close(websocket.StatusInternalError, "failed to get stderr pipe")
|
|
return
|
|
}
|
|
|
|
stdinPipe, err := session.StdinPipe()
|
|
if err != nil {
|
|
wsConn.Close(websocket.StatusInternalError, "failed to get stdin pipe")
|
|
return
|
|
}
|
|
|
|
err = session.RequestPty("xterm-256color", 80, 24, ssh.TerminalModes{})
|
|
if err != nil {
|
|
wsConn.Close(websocket.StatusInternalError, "failed to request pty")
|
|
return
|
|
}
|
|
|
|
if err := session.Shell(); err != nil {
|
|
wsConn.Close(websocket.StatusInternalError, "failed to start shell")
|
|
return
|
|
}
|
|
|
|
// Goroutine to send SSH stdout to WebSocket
|
|
go func() {
|
|
buf := make([]byte, 1024)
|
|
for {
|
|
n, err := stdoutPipe.Read(buf)
|
|
if err != nil {
|
|
if err != io.EOF {
|
|
log.Printf("error reading from SSH stdout: %v", err)
|
|
}
|
|
break
|
|
}
|
|
|
|
if writeErr := wsConn.Write(context.Background(), websocket.MessageBinary, buf[:n]); writeErr != nil {
|
|
log.Printf("error writing to websocket: %v", writeErr)
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Goroutine to handle SSH stderr
|
|
go func() {
|
|
buf := make([]byte, 1024)
|
|
for {
|
|
n, err := stderrPipe.Read(buf)
|
|
if err != nil {
|
|
if err != io.EOF {
|
|
log.Printf("error reading from SSH stderr: %v", err)
|
|
}
|
|
break
|
|
}
|
|
if writeErr := wsConn.Write(context.Background(), websocket.MessageBinary, buf[:n]); writeErr != nil {
|
|
log.Printf("error writing to websocket: %v", writeErr)
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Handle WebSocket to SSH data streaming
|
|
go func() {
|
|
for {
|
|
_, msg, err := wsConn.Read(context.Background())
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if strings.HasPrefix(string(msg), "\x01") {
|
|
parts := strings.Split(string(msg[1:]), ",")
|
|
if len(parts) == 2 {
|
|
width, _ := strconv.Atoi(parts[0])
|
|
height, _ := strconv.Atoi(parts[1])
|
|
session.WindowChange(height, width)
|
|
}
|
|
} else {
|
|
stdinPipe.Write(msg)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Wait for the SSH session to close
|
|
if err := session.Wait(); err != nil {
|
|
log.Printf("SSH session ended with error: %v", err)
|
|
wsConn.Write(context.Background(), websocket.MessageText, []byte(err.Error()))
|
|
} else {
|
|
log.Println("SSH session ended normally")
|
|
}
|
|
|
|
// Ensure WebSocket is closed after SSH logout
|
|
wsConn.Close(websocket.StatusNormalClosure, "SSH session closed")
|
|
}
|
|
|
|
func main() {
|
|
http.HandleFunc("/ws", sshWebSocketHandler)
|
|
log.Println("Server started on :3000")
|
|
log.Fatal(http.ListenAndServe(":3000", nil))
|
|
}
|