mirror of
https://github.com/acepanel/panel.git
synced 2026-02-05 00:39:32 +08:00
165 lines
4.1 KiB
Go
165 lines
4.1 KiB
Go
package controllers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
nethttp "net/http"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/goravel/framework/contracts/http"
|
|
"github.com/goravel/framework/facades"
|
|
"github.com/gorilla/websocket"
|
|
|
|
"panel/app/models"
|
|
"panel/app/services"
|
|
"panel/pkg/ssh"
|
|
)
|
|
|
|
type SshController struct {
|
|
AuthMethod ssh.AuthMethod
|
|
setting services.Setting
|
|
}
|
|
|
|
func NewSshController() *SshController {
|
|
return &SshController{
|
|
AuthMethod: ssh.PASSWORD,
|
|
setting: services.NewSettingImpl(),
|
|
}
|
|
}
|
|
|
|
func (r *SshController) GetInfo(ctx http.Context) {
|
|
host := r.setting.Get(models.SettingKeySshHost)
|
|
port := r.setting.Get(models.SettingKeySshPort)
|
|
user := r.setting.Get(models.SettingKeySshUser)
|
|
password := r.setting.Get(models.SettingKeySshPassword)
|
|
if len(host) == 0 || len(user) == 0 || len(password) == 0 {
|
|
Error(ctx, http.StatusInternalServerError, "SSH 配置不完整")
|
|
return
|
|
}
|
|
|
|
Success(ctx, http.Json{
|
|
"host": host,
|
|
"port": port,
|
|
"user": user,
|
|
"password": password,
|
|
})
|
|
}
|
|
|
|
func (r *SshController) UpdateInfo(ctx http.Context) {
|
|
validator, err := ctx.Request().Validate(map[string]string{
|
|
"host": "required",
|
|
"port": "required",
|
|
"user": "required",
|
|
"password": "required",
|
|
})
|
|
if err != nil {
|
|
Error(ctx, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
if validator.Fails() {
|
|
Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
|
return
|
|
}
|
|
|
|
host := ctx.Request().Input("host")
|
|
port := ctx.Request().Input("port")
|
|
user := ctx.Request().Input("user")
|
|
password := ctx.Request().Input("password")
|
|
err = r.setting.Set(models.SettingKeySshHost, host)
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 更新配置失败 ", err)
|
|
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
|
return
|
|
}
|
|
err = r.setting.Set(models.SettingKeySshPort, port)
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 更新配置失败 ", err)
|
|
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
|
return
|
|
}
|
|
err = r.setting.Set(models.SettingKeySshUser, user)
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 更新配置失败 ", err)
|
|
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
|
return
|
|
}
|
|
err = r.setting.Set(models.SettingKeySshPassword, password)
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 更新配置失败 ", err)
|
|
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
|
return
|
|
}
|
|
|
|
Success(ctx, nil)
|
|
}
|
|
|
|
func (r *SshController) Session(ctx http.Context) {
|
|
upGrader := websocket.Upgrader{
|
|
ReadBufferSize: 4096,
|
|
WriteBufferSize: 4096,
|
|
CheckOrigin: func(r *nethttp.Request) bool {
|
|
return true
|
|
},
|
|
Subprotocols: []string{ctx.Request().Header("Sec-WebSocket-Protocol")},
|
|
}
|
|
|
|
ws, err := upGrader.Upgrade(ctx.Response().Writer(), ctx.Request().Origin(), nil)
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 建立连接失败 ", err)
|
|
Error(ctx, http.StatusInternalServerError, "系统内部错误")
|
|
return
|
|
}
|
|
defer ws.Close()
|
|
|
|
config := ssh.SSHClientConfigPassword(
|
|
r.setting.Get(models.SettingKeySshHost)+":"+r.setting.Get(models.SettingKeySshPort),
|
|
r.setting.Get(models.SettingKeySshUser),
|
|
r.setting.Get(models.SettingKeySshPassword),
|
|
)
|
|
client, err := ssh.NewSSHClient(config)
|
|
if err != nil {
|
|
_ = ws.WriteControl(websocket.CloseMessage,
|
|
[]byte(err.Error()), time.Now().Add(time.Second))
|
|
return
|
|
}
|
|
defer client.Close()
|
|
|
|
turn, err := ssh.NewTurn(ws, client)
|
|
if err != nil {
|
|
_ = ws.WriteControl(websocket.CloseMessage,
|
|
[]byte(err.Error()), time.Now().Add(time.Second))
|
|
return
|
|
}
|
|
defer turn.Close()
|
|
|
|
var bufPool = sync.Pool{
|
|
New: func() interface{} {
|
|
return new(bytes.Buffer)
|
|
},
|
|
}
|
|
var logBuff = bufPool.Get().(*bytes.Buffer)
|
|
logBuff.Reset()
|
|
defer bufPool.Put(logBuff)
|
|
|
|
ctx2, cancel := context.WithCancel(context.Background())
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(2)
|
|
go func() {
|
|
defer wg.Done()
|
|
err := turn.LoopRead(logBuff, ctx2)
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 读取数据失败 ", err.Error())
|
|
}
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
err := turn.SessionWait()
|
|
if err != nil {
|
|
facades.Log().Error("[面板][SSH] 会话失败 ", err.Error())
|
|
}
|
|
cancel()
|
|
}()
|
|
wg.Wait()
|
|
}
|