Initial commit
This commit is contained in:
52
pkg/api/account.go
Normal file
52
pkg/api/account.go
Normal file
@ -0,0 +1,52 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"next-terminal/pkg/config"
|
||||
"next-terminal/pkg/model"
|
||||
"next-terminal/pkg/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LoginAccount struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func LoginEndpoint(c echo.Context) error {
|
||||
var loginAccount LoginAccount
|
||||
if err := c.Bind(&loginAccount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := model.FindUserByUsername(loginAccount.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := utils.Encoder.Match([]byte(user.Password), []byte(loginAccount.Password)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
token := utils.UUID()
|
||||
|
||||
config.Cache.Set(token, user, time.Minute*time.Duration(30))
|
||||
|
||||
model.UpdateUserById(&model.User{Online: true}, user.ID)
|
||||
|
||||
return Success(c, token)
|
||||
}
|
||||
|
||||
func LogoutEndpoint(c echo.Context) error {
|
||||
token := GetToken(c)
|
||||
config.Cache.Delete(token)
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func ChangePasswordEndpoint(c echo.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func InfoEndpoint(c echo.Context) error {
|
||||
account, _ := GetCurrentAccount(c)
|
||||
return Success(c, account)
|
||||
}
|
96
pkg/api/asset.go
Normal file
96
pkg/api/asset.go
Normal file
@ -0,0 +1,96 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"next-terminal/pkg/model"
|
||||
"next-terminal/pkg/utils"
|
||||
"github.com/labstack/echo/v4"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func AssetCreateEndpoint(c echo.Context) error {
|
||||
var item model.Asset
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item.ID = utils.UUID()
|
||||
item.Created = utils.NowJsonTime()
|
||||
|
||||
if err := model.CreateNewAsset(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, item)
|
||||
}
|
||||
|
||||
func AssetPagingEndpoint(c echo.Context) error {
|
||||
pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
|
||||
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
||||
name := c.QueryParam("name")
|
||||
protocol := c.QueryParam("protocol")
|
||||
|
||||
items, total, _ := model.FindPageAsset(pageIndex, pageSize, name, protocol)
|
||||
|
||||
return Success(c, H{
|
||||
"total": total,
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
|
||||
func AssetAllEndpoint(c echo.Context) error {
|
||||
protocol := c.QueryParam("protocol")
|
||||
items, _ := model.FindAssetByConditions(protocol)
|
||||
return Success(c, items)
|
||||
}
|
||||
|
||||
func AssetUpdateEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
|
||||
var item model.Asset
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
model.UpdateAssetById(&item, id)
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func AssetDeleteEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
split := strings.Split(id, ",")
|
||||
for i := range split {
|
||||
model.DeleteAssetById(split[i])
|
||||
}
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func AssetGetEndpoint(c echo.Context) (err error) {
|
||||
id := c.Param("id")
|
||||
|
||||
var item model.Asset
|
||||
if item, err = model.FindAssetById(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, item)
|
||||
}
|
||||
|
||||
func AssetTcpingEndpoint(c echo.Context) (err error) {
|
||||
id := c.Param("id")
|
||||
|
||||
var item model.Asset
|
||||
if item, err = model.FindAssetById(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
active := utils.Tcping(item.IP, item.Port)
|
||||
asset := model.Asset{
|
||||
Active: active,
|
||||
}
|
||||
|
||||
model.UpdateAssetById(&asset, item.ID)
|
||||
return Success(c, active)
|
||||
}
|
70
pkg/api/command.go
Normal file
70
pkg/api/command.go
Normal file
@ -0,0 +1,70 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"next-terminal/pkg/model"
|
||||
"next-terminal/pkg/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CommandCreateEndpoint(c echo.Context) error {
|
||||
var item model.Command
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item.ID = utils.UUID()
|
||||
item.Created = utils.NowJsonTime()
|
||||
|
||||
if err := model.CreateNewCommand(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, item)
|
||||
}
|
||||
|
||||
func CommandPagingEndpoint(c echo.Context) error {
|
||||
pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
|
||||
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
||||
name := c.QueryParam("name")
|
||||
content := c.QueryParam("content")
|
||||
|
||||
items, total, _ := model.FindPageCommand(pageIndex, pageSize, name, content)
|
||||
|
||||
return Success(c, H{
|
||||
"total": total,
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
|
||||
func CommandUpdateEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
|
||||
var item model.Command
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
model.UpdateCommandById(&item, id)
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func CommandDeleteEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
split := strings.Split(id, ",")
|
||||
for i := range split {
|
||||
model.DeleteCommandById(split[i])
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func CommandGetEndpoint(c echo.Context) (err error) {
|
||||
id := c.Param("id")
|
||||
var item model.Command
|
||||
if item, err = model.FindCommandById(id); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, item)
|
||||
}
|
72
pkg/api/credential.go
Normal file
72
pkg/api/credential.go
Normal file
@ -0,0 +1,72 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"next-terminal/pkg/model"
|
||||
"next-terminal/pkg/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CredentialAllEndpoint(c echo.Context) error {
|
||||
items, _ := model.FindAllCredential()
|
||||
return Success(c, items)
|
||||
}
|
||||
func CredentialCreateEndpoint(c echo.Context) error {
|
||||
var item model.Credential
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item.ID = utils.UUID()
|
||||
item.Created = utils.NowJsonTime()
|
||||
|
||||
if err := model.CreateNewCredential(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, item)
|
||||
}
|
||||
|
||||
func CredentialPagingEndpoint(c echo.Context) error {
|
||||
pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
|
||||
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
||||
name := c.QueryParam("name")
|
||||
|
||||
items, total, _ := model.FindPageCredential(pageIndex, pageSize, name)
|
||||
|
||||
return Success(c, H{
|
||||
"total": total,
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
|
||||
func CredentialUpdateEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
|
||||
var item model.Credential
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
model.UpdateCredentialById(&item, id)
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func CredentialDeleteEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
split := strings.Split(id, ",")
|
||||
for i := range split {
|
||||
model.DeleteCredentialById(split[i])
|
||||
}
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func CredentialGetEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
item, _ := model.FindCredentialById(id)
|
||||
|
||||
return Success(c, item)
|
||||
}
|
34
pkg/api/middleware.go
Normal file
34
pkg/api/middleware.go
Normal file
@ -0,0 +1,34 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"next-terminal/pkg/config"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Auth(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
|
||||
urls := []string{"download", "login"}
|
||||
|
||||
return func(c echo.Context) error {
|
||||
// 路由拦截 - 登录身份、资源权限判断等
|
||||
for i := range urls {
|
||||
if c.Request().RequestURI == "/" || strings.HasPrefix(c.Request().RequestURI, "/#") {
|
||||
return next(c)
|
||||
}
|
||||
if strings.Contains(c.Request().RequestURI, urls[i]) {
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
token := GetToken(c)
|
||||
user, found := config.Cache.Get(token)
|
||||
if !found {
|
||||
c.Logger().Error("您的登录信息已失效,请重新登录后再试。")
|
||||
return Fail(c, 403, "您的登录信息已失效,请重新登录后再试。")
|
||||
}
|
||||
config.Cache.Set(token, user, time.Minute*time.Duration(30))
|
||||
return next(c)
|
||||
}
|
||||
}
|
98
pkg/api/overview.go
Normal file
98
pkg/api/overview.go
Normal file
@ -0,0 +1,98 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"next-terminal/pkg/model"
|
||||
"fmt"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/load"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OverviewStatus struct {
|
||||
Load Load `json:"load"`
|
||||
Memory Memory `json:"memory"`
|
||||
CPU CPU `json:"cpu"`
|
||||
}
|
||||
|
||||
type Load struct {
|
||||
Load1 float64 `json:"load1"`
|
||||
Load5 float64 `json:"load5"`
|
||||
Load15 float64 `json:"load15"`
|
||||
}
|
||||
|
||||
type Memory struct {
|
||||
Total uint64 `json:"total"`
|
||||
Available uint64 `json:"available"`
|
||||
UsedPercent float64 `json:"usedPercent"`
|
||||
Used uint64 `json:"used"`
|
||||
}
|
||||
|
||||
type CPU struct {
|
||||
PhysicalCount int `json:"physicalCount"`
|
||||
LogicalCount int `json:"logicalCount"`
|
||||
Percent float64 `json:"percent"`
|
||||
ModelName string `json:"modelName"`
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
User int64 `json:"user"`
|
||||
Asset int64 `json:"asset"`
|
||||
Credential int64 `json:"credential"`
|
||||
OnlineSession int64 `json:"onlineSession"`
|
||||
}
|
||||
|
||||
func OverviewStatusEndPoint(c echo.Context) error {
|
||||
info, _ := load.Avg()
|
||||
memory, _ := mem.VirtualMemory()
|
||||
infoStats, _ := cpu.Info()
|
||||
physicalCount, _ := cpu.Counts(false)
|
||||
logicalCount, _ := cpu.Counts(true)
|
||||
cps, _ := cpu.Percent(time.Second, false)
|
||||
|
||||
fmt.Printf("%+v\n", info)
|
||||
fmt.Printf("%+v\n", memory)
|
||||
fmt.Printf("%+v\n", infoStats)
|
||||
fmt.Printf("%+v\n", physicalCount)
|
||||
fmt.Printf("%+v\n", logicalCount)
|
||||
fmt.Printf("%+v\n", cps)
|
||||
|
||||
overviewStatus := OverviewStatus{
|
||||
Load: Load{
|
||||
Load1: info.Load1,
|
||||
Load5: info.Load5,
|
||||
Load15: info.Load15,
|
||||
},
|
||||
Memory: Memory{
|
||||
Total: memory.Total,
|
||||
Available: memory.Available,
|
||||
UsedPercent: memory.UsedPercent,
|
||||
Used: memory.Used,
|
||||
},
|
||||
CPU: CPU{
|
||||
PhysicalCount: physicalCount,
|
||||
LogicalCount: logicalCount,
|
||||
Percent: cps[0],
|
||||
ModelName: infoStats[0].ModelName,
|
||||
},
|
||||
}
|
||||
|
||||
return Success(c, overviewStatus)
|
||||
}
|
||||
|
||||
func OverviewCounterEndPoint(c echo.Context) error {
|
||||
countUser, _ := model.CountUser()
|
||||
countOnlineSession, _ := model.CountOnlineSession()
|
||||
credential, _ := model.CountCredential()
|
||||
asset, _ := model.CountAsset()
|
||||
|
||||
counter := Counter{
|
||||
User: countUser,
|
||||
OnlineSession: countOnlineSession,
|
||||
Credential: credential,
|
||||
Asset: asset,
|
||||
}
|
||||
|
||||
return Success(c, counter)
|
||||
}
|
29
pkg/api/property.go
Normal file
29
pkg/api/property.go
Normal file
@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"next-terminal/pkg/model"
|
||||
"fmt"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func PropertyGetEndpoint(c echo.Context) error {
|
||||
properties := model.FindAllProperties()
|
||||
return Success(c, properties)
|
||||
}
|
||||
|
||||
func PropertyUpdateEndpoint(c echo.Context) error {
|
||||
var item map[string]interface{}
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for key := range item {
|
||||
value := fmt.Sprintf("%v", item[key])
|
||||
property := model.Property{
|
||||
Name: key,
|
||||
Value: value,
|
||||
}
|
||||
model.UpdatePropertyByName(&property, key)
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
145
pkg/api/routes.go
Normal file
145
pkg/api/routes.go
Normal file
@ -0,0 +1,145 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"net/http"
|
||||
"next-terminal/pkg/config"
|
||||
"next-terminal/pkg/model"
|
||||
)
|
||||
|
||||
const Token = "X-Auth-Token"
|
||||
|
||||
func SetupRoutes() *echo.Echo {
|
||||
|
||||
// Echo instance
|
||||
e := echo.New()
|
||||
|
||||
e.File("/", "web/build/index.html")
|
||||
e.File("/logo.svg", "web/build/logo.svg")
|
||||
e.File("/favicon.ico", "web/build/favicon.ico")
|
||||
e.Static("/static", "web/build/static")
|
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
||||
Skipper: middleware.DefaultSkipper,
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
|
||||
}))
|
||||
e.Use(Auth)
|
||||
|
||||
e.POST("/login", LoginEndpoint)
|
||||
|
||||
e.GET("/tunnel", TunEndpoint)
|
||||
e.GET("/ssh", SSHEndpoint)
|
||||
|
||||
e.POST("/logout", LogoutEndpoint)
|
||||
e.POST("/change-password", ChangePasswordEndpoint)
|
||||
e.GET("/info", InfoEndpoint)
|
||||
|
||||
users := e.Group("/users")
|
||||
{
|
||||
users.POST("", UserCreateEndpoint)
|
||||
users.GET("/paging", UserPagingEndpoint)
|
||||
users.PUT("/:id", UserUpdateEndpoint)
|
||||
users.DELETE("/:id", UserDeleteEndpoint)
|
||||
users.GET("/:id", UserGetEndpoint)
|
||||
}
|
||||
|
||||
assets := e.Group("/assets", Auth)
|
||||
{
|
||||
assets.GET("", AssetAllEndpoint)
|
||||
assets.POST("", AssetCreateEndpoint)
|
||||
assets.GET("/paging", AssetPagingEndpoint)
|
||||
assets.POST("/:id/tcping", AssetTcpingEndpoint)
|
||||
assets.PUT("/:id", AssetUpdateEndpoint)
|
||||
assets.DELETE("/:id", AssetDeleteEndpoint)
|
||||
assets.GET("/:id", AssetGetEndpoint)
|
||||
}
|
||||
|
||||
commands := e.Group("/commands")
|
||||
{
|
||||
commands.GET("/paging", CommandPagingEndpoint)
|
||||
commands.POST("", CommandCreateEndpoint)
|
||||
commands.PUT("/:id", CommandUpdateEndpoint)
|
||||
commands.DELETE("/:id", CommandDeleteEndpoint)
|
||||
commands.GET("/:id", CommandGetEndpoint)
|
||||
}
|
||||
|
||||
credentials := e.Group("/credentials")
|
||||
{
|
||||
credentials.GET("", CredentialAllEndpoint)
|
||||
credentials.GET("/paging", CredentialPagingEndpoint)
|
||||
credentials.POST("", CredentialCreateEndpoint)
|
||||
credentials.PUT("/:id", CredentialUpdateEndpoint)
|
||||
credentials.DELETE("/:id", CredentialDeleteEndpoint)
|
||||
credentials.GET("/:id", CredentialGetEndpoint)
|
||||
}
|
||||
|
||||
sessions := e.Group("/sessions")
|
||||
{
|
||||
sessions.POST("", SessionCreateEndpoint)
|
||||
sessions.GET("/paging", SessionPagingEndpoint)
|
||||
sessions.POST("/:id/content", SessionContentEndpoint)
|
||||
sessions.POST("/:id/discontent", SessionDiscontentEndpoint)
|
||||
sessions.POST("/:id/resize", SessionResizeEndpoint)
|
||||
sessions.POST("/:id/upload", SessionUploadEndpoint)
|
||||
sessions.GET("/:id/download", SessionDownloadEndpoint)
|
||||
sessions.GET("/:id/ls", SessionLsEndpoint)
|
||||
sessions.POST("/:id/mkdir", SessionMkDirEndpoint)
|
||||
sessions.DELETE("/:id/rmdir", SessionRmDirEndpoint)
|
||||
sessions.DELETE("/:id/rm", SessionRmEndpoint)
|
||||
sessions.DELETE("/:id", SessionDeleteEndpoint)
|
||||
}
|
||||
|
||||
e.GET("/properties", PropertyGetEndpoint)
|
||||
e.PUT("/properties", PropertyUpdateEndpoint)
|
||||
|
||||
e.GET("/overview/status", OverviewStatusEndPoint)
|
||||
e.GET("/overview/counter", OverviewCounterEndPoint)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
type H map[string]interface{}
|
||||
|
||||
func Fail(c echo.Context, code int, message string) error {
|
||||
return c.JSON(200, H{
|
||||
"code": code,
|
||||
"message": message,
|
||||
})
|
||||
}
|
||||
|
||||
func Success(c echo.Context, data interface{}) error {
|
||||
return c.JSON(200, H{
|
||||
"code": 1,
|
||||
"message": "success",
|
||||
"data": data,
|
||||
})
|
||||
}
|
||||
|
||||
func NotFound(c echo.Context, message string) error {
|
||||
return c.JSON(200, H{
|
||||
"code": -1,
|
||||
"message": message,
|
||||
})
|
||||
}
|
||||
|
||||
func GetToken(c echo.Context) string {
|
||||
token := c.Request().Header.Get(Token)
|
||||
if len(token) > 0 {
|
||||
return token
|
||||
}
|
||||
return c.QueryParam(Token)
|
||||
}
|
||||
|
||||
func GetCurrentAccount(c echo.Context) (model.User, bool) {
|
||||
token := GetToken(c)
|
||||
get, b := config.Cache.Get(token)
|
||||
if b {
|
||||
return get.(model.User), true
|
||||
}
|
||||
return model.User{}, false
|
||||
}
|
430
pkg/api/session.go
Normal file
430
pkg/api/session.go
Normal file
@ -0,0 +1,430 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/labstack/echo/v4"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"next-terminal/pkg/config"
|
||||
"next-terminal/pkg/model"
|
||||
"next-terminal/pkg/utils"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SessionPagingEndpoint(c echo.Context) error {
|
||||
pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
|
||||
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
||||
status := c.QueryParam("status")
|
||||
userId := c.QueryParam("userId")
|
||||
clientIp := c.QueryParam("clientIp")
|
||||
assetId := c.QueryParam("assetId")
|
||||
protocol := c.QueryParam("protocol")
|
||||
|
||||
items, total, err := model.FindPageSession(pageIndex, pageSize, status, userId, clientIp, assetId, protocol)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, H{
|
||||
"total": total,
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
|
||||
func SessionDeleteEndpoint(c echo.Context) error {
|
||||
sessionIds := c.Param("id")
|
||||
split := strings.Split(sessionIds, ",")
|
||||
for i := range split {
|
||||
model.DeleteSessionById(split[i])
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
_ = os.Remove(path.Join(drivePath, split[i]))
|
||||
}
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func SessionContentEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
|
||||
session := model.Session{}
|
||||
session.ID = sessionId
|
||||
session.Status = model.Connected
|
||||
session.ConnectedTime = utils.NowJsonTime()
|
||||
|
||||
model.UpdateSessionById(&session, sessionId)
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func SessionDiscontentEndpoint(c echo.Context) error {
|
||||
sessionIds := c.Param("id")
|
||||
|
||||
split := strings.Split(sessionIds, ",")
|
||||
for i := range split {
|
||||
tun, ok := config.Store.Get(split[i])
|
||||
if ok {
|
||||
CloseSession(split[i], tun)
|
||||
}
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func CloseSession(sessionId string, tun config.Tun) {
|
||||
_ = tun.Tun.Close()
|
||||
config.Store.Del(sessionId)
|
||||
|
||||
session := model.Session{}
|
||||
session.ID = sessionId
|
||||
session.Status = model.Disconnected
|
||||
session.DisconnectedTime = utils.NowJsonTime()
|
||||
|
||||
model.UpdateSessionById(&session, sessionId)
|
||||
}
|
||||
|
||||
func SessionResizeEndpoint(c echo.Context) error {
|
||||
width := c.QueryParam("width")
|
||||
height := c.QueryParam("height")
|
||||
sessionId := c.Param("id")
|
||||
|
||||
if len(width) == 0 || len(height) == 0 {
|
||||
panic("参数异常")
|
||||
}
|
||||
|
||||
intWidth, _ := strconv.Atoi(width)
|
||||
|
||||
intHeight, _ := strconv.Atoi(height)
|
||||
|
||||
session := model.Session{}
|
||||
session.ID = sessionId
|
||||
session.Width = intWidth
|
||||
session.Height = intHeight
|
||||
|
||||
model.UpdateSessionById(&session, sessionId)
|
||||
return Success(c, session)
|
||||
}
|
||||
|
||||
func SessionCreateEndpoint(c echo.Context) error {
|
||||
assetId := c.QueryParam("assetId")
|
||||
user, _ := GetCurrentAccount(c)
|
||||
|
||||
asset, err := model.FindAssetById(assetId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session := &model.Session{
|
||||
ID: utils.UUID(),
|
||||
AssetId: asset.ID,
|
||||
Username: asset.Username,
|
||||
Password: asset.Password,
|
||||
Protocol: asset.Protocol,
|
||||
IP: asset.IP,
|
||||
Port: asset.Port,
|
||||
Status: model.NoConnect,
|
||||
Creator: user.ID,
|
||||
ClientIP: c.RealIP(),
|
||||
}
|
||||
|
||||
if asset.AccountType == "credential" {
|
||||
credential, err := model.FindCredentialById(asset.CredentialId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session.Username = credential.Username
|
||||
session.Password = credential.Password
|
||||
}
|
||||
|
||||
if err := model.CreateNewSession(session); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, session)
|
||||
}
|
||||
|
||||
func SessionUploadEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := file.Filename
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
remoteDir := c.QueryParam("dir")
|
||||
remoteFile := path.Join(remoteDir, filename)
|
||||
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := config.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
|
||||
dstFile, err := tun.SftpClient.Create(remoteFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer dstFile.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n, _ := src.Read(buf)
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
_, _ = dstFile.Write(buf)
|
||||
}
|
||||
return Success(c, nil)
|
||||
} else if "rdp" == session.Protocol {
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Destination
|
||||
dst, err := os.Create(path.Join(drivePath, remoteFile))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
// Copy
|
||||
if _, err = io.Copy(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func SessionDownloadEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//remoteDir := c.Query("dir")
|
||||
remoteFile := c.QueryParam("file")
|
||||
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := config.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
|
||||
dstFile, err := tun.SftpClient.Open(remoteFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer dstFile.Close()
|
||||
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", remoteFile))
|
||||
|
||||
var buff bytes.Buffer
|
||||
if _, err := dstFile.WriteTo(&buff); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(buff.Bytes()))
|
||||
} else if "rdp" == session.Protocol {
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.File(path.Join(drivePath, remoteFile))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
IsDir bool `json:"isDir"`
|
||||
Mode string `json:"mode"`
|
||||
IsLink bool `json:"isLink"`
|
||||
}
|
||||
|
||||
func SessionLsEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteDir := c.QueryParam("dir")
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := config.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
|
||||
fileInfos, err := tun.SftpClient.ReadDir(remoteDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var files = make([]File, 0)
|
||||
for i := range fileInfos {
|
||||
file := File{
|
||||
Name: fileInfos[i].Name(),
|
||||
Path: path.Join(remoteDir, fileInfos[i].Name()),
|
||||
IsDir: fileInfos[i].IsDir(),
|
||||
Mode: fileInfos[i].Mode().String(),
|
||||
IsLink: fileInfos[i].Mode()&os.ModeSymlink == os.ModeSymlink,
|
||||
}
|
||||
|
||||
files = append(files, file)
|
||||
}
|
||||
|
||||
return Success(c, files)
|
||||
} else if "rdp" == session.Protocol {
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileInfos, err := ioutil.ReadDir(path.Join(drivePath, remoteDir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var files = make([]File, 0)
|
||||
for i := range fileInfos {
|
||||
file := File{
|
||||
Name: fileInfos[i].Name(),
|
||||
Path: path.Join(remoteDir, fileInfos[i].Name()),
|
||||
IsDir: fileInfos[i].IsDir(),
|
||||
Mode: fileInfos[i].Mode().String(),
|
||||
IsLink: fileInfos[i].Mode()&os.ModeSymlink == os.ModeSymlink,
|
||||
}
|
||||
|
||||
files = append(files, file)
|
||||
}
|
||||
|
||||
return Success(c, files)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func SessionMkDirEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteDir := c.QueryParam("dir")
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := config.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
if err := tun.SftpClient.Mkdir(remoteDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
} else if "rdp" == session.Protocol {
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path.Join(drivePath, remoteDir), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SessionRmDirEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteDir := c.QueryParam("dir")
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := config.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
fileInfos, err := tun.SftpClient.ReadDir(remoteDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range fileInfos {
|
||||
if err := tun.SftpClient.Remove(path.Join(remoteDir, fileInfos[i].Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tun.SftpClient.RemoveDirectory(remoteDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
} else if "rdp" == session.Protocol {
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(path.Join(drivePath, remoteDir)); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SessionRmEndpoint(c echo.Context) error {
|
||||
sessionId := c.Param("id")
|
||||
session, err := model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteFile := c.QueryParam("file")
|
||||
if "ssh" == session.Protocol {
|
||||
tun, ok := config.Store.Get(sessionId)
|
||||
if !ok {
|
||||
return errors.New("获取sftp客户端失败")
|
||||
}
|
||||
if err := tun.SftpClient.Remove(remoteFile); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
} else if "rdp" == session.Protocol {
|
||||
drivePath, err := model.GetDrivePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Remove(path.Join(drivePath, remoteFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
return Success(c, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
175
pkg/api/ssh.go
Normal file
175
pkg/api/ssh.go
Normal file
@ -0,0 +1,175 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"next-terminal/pkg/model"
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var UpGrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
Subprotocols: []string{"guacamole"},
|
||||
}
|
||||
|
||||
type NextWriter struct {
|
||||
b bytes.Buffer
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (w *NextWriter) Write(p []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.b.Write(p)
|
||||
}
|
||||
|
||||
func (w *NextWriter) Read() ([]byte, int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
p := w.b.Bytes()
|
||||
buf := make([]byte, len(p))
|
||||
read, err := w.b.Read(buf)
|
||||
w.b.Reset()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return buf, read, err
|
||||
}
|
||||
|
||||
func SSHEndpoint(c echo.Context) error {
|
||||
ws, err := UpGrader.Upgrade(c.Response().Writer, c.Request(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
assetId := c.QueryParam("assetId")
|
||||
width, _ := strconv.Atoi(c.QueryParam("width"))
|
||||
height, _ := strconv.Atoi(c.QueryParam("height"))
|
||||
|
||||
asset, err := model.FindAssetById(assetId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if asset.AccountType == "credential" {
|
||||
credential, err := model.FindCredentialById(asset.CredentialId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
asset.Username = credential.Username
|
||||
asset.Password = credential.Password
|
||||
}
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
Timeout: 1 * time.Second,
|
||||
User: asset.Username,
|
||||
Auth: []ssh.AuthMethod{ssh.Password(asset.Password)},
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", asset.IP, asset.Port)
|
||||
|
||||
sshClient, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session, err := sshClient.NewSession()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 1,
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
}
|
||||
|
||||
if err := session.RequestPty("xterm", height, width, modes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var b NextWriter
|
||||
session.Stdout = &b
|
||||
session.Stderr = &b
|
||||
|
||||
stdinPipe, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := session.Shell(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
||||
for true {
|
||||
p, n, err := b.Read()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if n > 0 {
|
||||
WriteByteMessage(ws, p)
|
||||
}
|
||||
time.Sleep(time.Duration(100) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
for true {
|
||||
_, message, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
_, err = stdinPipe.Write(message)
|
||||
if err != nil {
|
||||
log.Println("Tunnel write:", err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func WriteMessage(ws *websocket.Conn, message string) {
|
||||
WriteByteMessage(ws, []byte(message))
|
||||
}
|
||||
|
||||
func WriteByteMessage(ws *websocket.Conn, p []byte) {
|
||||
err := ws.WriteMessage(websocket.TextMessage, p)
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func CreateSftpClient(username, password, ip string, port int) (sftpClient *sftp.Client, err error) {
|
||||
clientConfig := &ssh.ClientConfig{
|
||||
Timeout: 1 * time.Second,
|
||||
User: username,
|
||||
Auth: []ssh.AuthMethod{ssh.Password(password)},
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", ip, port)
|
||||
|
||||
sshClient, err := ssh.Dial("tcp", addr, clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sftp.NewClient(sshClient)
|
||||
}
|
33
pkg/api/test/ps.go
Normal file
33
pkg/api/test/ps.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
//v, _ := mem.VirtualMemory()
|
||||
//c, _ := cpu.Info()
|
||||
//cc, _ := cpu.Percent(time.Second, false)
|
||||
//d, _ := disk.Usage("/")
|
||||
//n, _ := host.Info()
|
||||
//nv, _ := net.IOCounters(true)
|
||||
//boottime, _ := host.BootTime()
|
||||
//btime := time.Unix(int64(boottime), 0).Format("2006-01-02 15:04:05")
|
||||
//
|
||||
//fmt.Printf(" Mem : %v MB Free: %v MB Used:%v Usage:%f%%\n", v.Total/1024/1024, v.Available/1024/1024, v.Used/1024/1024, v.UsedPercent)
|
||||
//if len(c) > 1 {
|
||||
// for _, sub_cpu := range c {
|
||||
// modelname := sub_cpu.ModelName
|
||||
// cores := sub_cpu.Cores
|
||||
// fmt.Printf(" CPU : %v %v cores \n", modelname, cores)
|
||||
// }
|
||||
//} else {
|
||||
// sub_cpu := c[0]
|
||||
// modelname := sub_cpu.ModelName
|
||||
// cores := sub_cpu.Cores
|
||||
// fmt.Printf(" CPU : %v %v cores \n", modelname, cores)
|
||||
//
|
||||
//}
|
||||
//fmt.Printf(" Network: %v bytes / %v bytes\n", nv[0].BytesRecv, nv[0].BytesSent)
|
||||
//fmt.Printf(" SystemBoot:%v\n", btime)
|
||||
//fmt.Printf(" CPU Used : used %f%% \n", cc[0])
|
||||
//fmt.Printf(" HD : %v GB Free: %v GB Usage:%f%%\n", d.Total/1024/1024/1024, d.Free/1024/1024/1024, d.UsedPercent)
|
||||
//fmt.Printf(" OS : %v(%v) %v \n", n.Platform, n.PlatformFamily, n.PlatformVersion)
|
||||
//fmt.Printf(" Hostname : %v \n", n.Hostname)
|
||||
}
|
158
pkg/api/tunnel.go
Normal file
158
pkg/api/tunnel.go
Normal file
@ -0,0 +1,158 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"next-terminal/pkg/config"
|
||||
"next-terminal/pkg/guacd"
|
||||
"next-terminal/pkg/model"
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/pkg/sftp"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func TunEndpoint(c echo.Context) error {
|
||||
|
||||
ws, err := UpGrader.Upgrade(c.Response().Writer, c.Request(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
width := c.QueryParam("width")
|
||||
height := c.QueryParam("height")
|
||||
sessionId := c.QueryParam("sessionId")
|
||||
connectionId := c.QueryParam("connectionId")
|
||||
|
||||
intWidth, _ := strconv.Atoi(width)
|
||||
intHeight, _ := strconv.Atoi(height)
|
||||
|
||||
configuration := guacd.NewConfiguration()
|
||||
configuration.SetParameter("width", width)
|
||||
configuration.SetParameter("height", height)
|
||||
|
||||
propertyMap := model.FindAllPropertiesMap()
|
||||
|
||||
for name := range propertyMap {
|
||||
|
||||
if name == model.GuacdFontSize {
|
||||
fontSize, _ := strconv.Atoi(propertyMap[name])
|
||||
fontSize = fontSize * 2
|
||||
configuration.SetParameter(name, strconv.Itoa(fontSize))
|
||||
} else {
|
||||
configuration.SetParameter(name, propertyMap[name])
|
||||
}
|
||||
}
|
||||
|
||||
var session model.Session
|
||||
var sftpClient *sftp.Client
|
||||
|
||||
if len(connectionId) > 0 {
|
||||
session, err = model.FindSessionByConnectionId(connectionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configuration.ConnectionID = connectionId
|
||||
} else {
|
||||
session, err = model.FindSessionById(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configuration.Protocol = session.Protocol
|
||||
switch configuration.Protocol {
|
||||
case "rdp":
|
||||
configuration.SetParameter("username", session.Username)
|
||||
configuration.SetParameter("password", session.Password)
|
||||
|
||||
configuration.SetParameter("security", "any")
|
||||
configuration.SetParameter("ignore-cert", "true")
|
||||
configuration.SetParameter("create-drive-path", "true")
|
||||
|
||||
configuration.SetParameter("dpi", "96")
|
||||
configuration.SetParameter("resize-method", "reconnect")
|
||||
configuration.SetParameter("enable-sftp", "")
|
||||
break
|
||||
case "ssh":
|
||||
configuration.SetParameter("username", session.Username)
|
||||
configuration.SetParameter("password", session.Password)
|
||||
|
||||
sftpClient, err = CreateSftpClient(session.Username, session.Password, session.IP, session.Port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
case "vnc":
|
||||
configuration.SetParameter("password", session.Password)
|
||||
configuration.SetParameter("enable-sftp", "")
|
||||
break
|
||||
case "telnet":
|
||||
configuration.SetParameter("username", session.Username)
|
||||
configuration.SetParameter("password", session.Password)
|
||||
configuration.SetParameter("enable-sftp", "")
|
||||
break
|
||||
}
|
||||
|
||||
configuration.SetParameter("hostname", session.IP)
|
||||
configuration.SetParameter("port", strconv.Itoa(session.Port))
|
||||
}
|
||||
|
||||
addr := propertyMap[model.GuacdHost] + ":" + propertyMap[model.GuacdPort]
|
||||
tunnel, err := guacd.NewTunnel(addr, configuration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("=====================================================\n")
|
||||
fmt.Printf("connect to %v with config: %+v\n", addr, configuration)
|
||||
fmt.Printf("=====================================================\n")
|
||||
|
||||
tun := config.Tun{
|
||||
Tun: tunnel,
|
||||
SftpClient: sftpClient,
|
||||
}
|
||||
|
||||
config.Store.Set(sessionId, tun)
|
||||
|
||||
if len(session.ConnectionId) == 0 {
|
||||
session.ConnectionId = tunnel.UUID
|
||||
session.Width = intWidth
|
||||
session.Height = intHeight
|
||||
|
||||
model.UpdateSessionById(&session, sessionId)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for true {
|
||||
instruction, err := tunnel.Read()
|
||||
if err != nil {
|
||||
CloseSession(sessionId, tun)
|
||||
log.Printf("WS读取异常: %v", err)
|
||||
break
|
||||
}
|
||||
//fmt.Printf("<= %v \n", string(instruction))
|
||||
err = ws.WriteMessage(websocket.TextMessage, instruction)
|
||||
if err != nil {
|
||||
CloseSession(sessionId, tun)
|
||||
log.Printf("WS写入异常: %v", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for true {
|
||||
_, message, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
CloseSession(sessionId, tun)
|
||||
log.Printf("Tunnel读取异常: %v", err)
|
||||
break
|
||||
}
|
||||
_, err = tunnel.WriteAndFlush(message)
|
||||
if err != nil {
|
||||
CloseSession(sessionId, tun)
|
||||
log.Printf("Tunnel写入异常: %v", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
83
pkg/api/user.go
Normal file
83
pkg/api/user.go
Normal file
@ -0,0 +1,83 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"next-terminal/pkg/model"
|
||||
"next-terminal/pkg/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func UserCreateEndpoint(c echo.Context) error {
|
||||
var item model.User
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pass []byte
|
||||
var err error
|
||||
if pass, err = utils.Encoder.Encode([]byte("admin")); err != nil {
|
||||
return err
|
||||
}
|
||||
item.Password = string(pass)
|
||||
|
||||
item.ID = utils.UUID()
|
||||
item.Created = utils.NowJsonTime()
|
||||
|
||||
if err := model.CreateNewUser(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, item)
|
||||
}
|
||||
|
||||
func UserPagingEndpoint(c echo.Context) error {
|
||||
pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
|
||||
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
||||
username := c.QueryParam("username")
|
||||
nickname := c.QueryParam("nickname")
|
||||
|
||||
items, total, err := model.FindPageUser(pageIndex, pageSize, username, nickname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, H{
|
||||
"total": total,
|
||||
"items": items,
|
||||
})
|
||||
}
|
||||
|
||||
func UserUpdateEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
|
||||
var item model.User
|
||||
if err := c.Bind(&item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
model.UpdateUserById(&item, id)
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func UserDeleteEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
split := strings.Split(id, ",")
|
||||
for i := range split {
|
||||
model.DeleteUserById(split[i])
|
||||
}
|
||||
|
||||
return Success(c, nil)
|
||||
}
|
||||
|
||||
func UserGetEndpoint(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
|
||||
item, err := model.FindUserById(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Success(c, item)
|
||||
}
|
Reference in New Issue
Block a user