Commit 3198cb2a authored by ibuler's avatar ibuler

[Update] 修改结构

parent 77ac1fce
package common
import "fmt"
package handler
import (
"text/template"
"github.com/gliderlabs/ssh"
"cocogo/pkg/logger"
)
const bannerTemplate = `
{{.UserName}} Welcome to use Jumpserver open source fortress system{{.EndLine}}
{{.Tab}}1) Enter {{.ColorCode}}ID{{.ColorEnd}} directly login or enter {{.ColorCode}}part IP, Hostname, Comment{{.ColorEnd}} to search login(if unique). {{.EndLine}}
{{.Tab}}2) Enter {{.ColorCode}}/{{.ColorEnd}} + {{.ColorCode}}IP, Hostname{{.ColorEnd}} or {{.ColorCode}}Comment{{.ColorEnd}} search, such as: /ip. {{.EndLine}}
{{.Tab}}3) Enter {{.ColorCode}}p{{.ColorEnd}} to display the host you have permission.{{.EndLine}}
{{.Tab}}4) Enter {{.ColorCode}}g{{.ColorEnd}} to display the node that you have permission.{{.EndLine}}
{{.Tab}}5) Enter {{.ColorCode}}g{{.ColorEnd}} + {{.ColorCode}}NodeID{{.ColorEnd}} to display the host under the node, such as g1. {{.EndLine}}
{{.Tab}}6) Enter {{.ColorCode}}s{{.ColorEnd}} Chinese-english proxy.{{.EndLine}}
{{.Tab}}7) Enter {{.ColorCode}}h{{.ColorEnd}} help.{{.EndLine}}
{{.Tab}}8) Enter {{.ColorCode}}r{{.ColorEnd}} to refresh your assets and nodes.{{.EndLine}}
{{.Tab}}0) Enter {{.ColorCode}}q{{.ColorEnd}} exit.{{.EndLine}}
`
var displayTemplate = template.Must(template.New("display").Parse(bannerTemplate))
type Banner struct {
UserName string
ColorCode string
ColorEnd string
Tab string
EndLine string
}
func (h *Banner) display(sess ssh.Session) {
e := displayTemplate.Execute(sess, h)
if e != nil {
logger.Warn("Display help info failed")
}
}
func NewBanner(userName string) *Banner {
return &Banner{
UserName: userName,
ColorCode: GreenColorCode,
ColorEnd: ColorEnd,
Tab: Tab,
EndLine: EndLine,
}
}
package model
import "cocogo/pkg/sdk"
type AssetList []sdk.Asset
func (a *AssetList) SortBy(tp string) AssetList {
switch tp {
case "ip":
return []sdk.Asset{}
default:
return []sdk.Asset{}
}
}
type NodeList []sdk.Node
...@@ -6,7 +6,6 @@ import ( ...@@ -6,7 +6,6 @@ import (
"cocogo/pkg/common" "cocogo/pkg/common"
"cocogo/pkg/config" "cocogo/pkg/config"
"cocogo/pkg/model"
) )
type ClientAuth interface { type ClientAuth interface {
...@@ -34,7 +33,7 @@ func (c *WrapperClient) LoadAuth() error { ...@@ -34,7 +33,7 @@ func (c *WrapperClient) LoadAuth() error {
} }
func (c *WrapperClient) CheckAuth() error { func (c *WrapperClient) CheckAuth() error {
var user model.User var user User
err := c.Http.Get("UserProfileUrl", &user) err := c.Http.Get("UserProfileUrl", &user)
if err != nil { if err != nil {
return err return err
......
package service package service
import "cocogo/pkg/sdk" import (
"cocogo/pkg/model"
)
func GetUserAssets(userId string) (assets []sdk.Asset) { func GetUserAssets(userId string) (assets model.AssetList) {
return return model.AssetList{{Id: "xxxxxxxxx", Hostname: "test", Ip: "192.168.244.185", Port: 22}}
} }
func GetUserNodes(userId string) (nodes []sdk.Node) { func GetUserNodes(userId string) (nodes model.NodeList) {
return return model.NodeList{{Id: "XXXXXXX", Name: "test"}}
}
func ValidateUserAssetPermission(userId, assetId, systemUserId string) bool {
return true
} }
package handler
import (
"cocogo/pkg/config"
"fmt"
"io"
"text/template"
"github.com/gliderlabs/ssh"
"cocogo/pkg/logger"
)
const defaultTitle = `Welcome to use Jumpserver open source fortress system`
type MenuItem struct {
instruct string
helpText string
}
type Menu []MenuItem
var menu = Menu{
{instruct: "ID", helpText: "directly login or enter."},
{instruct: "part IP, Hostname, Comment", helpText: "to search login if unique."},
{instruct: "/ + IP, Hostname, Comment", helpText: "to search, such as: /192.168"},
{instruct: "p", helpText: "display the host you have permission."},
{instruct: "g", helpText: "display the node that you have permission."},
{instruct: "r", helpText: "refresh your assets and nodes"},
{instruct: "s", helpText: "switch Chinese-english language."},
{instruct: "h", helpText: "print help"},
{instruct: "q", helpText: "exit"},
}
type Banner struct {
user string
}
type ColorMeta struct {
GreenBoldColor string
ColorEnd string
}
func displayBanner(sess ssh.Session, user string) {
title := defaultTitle
if config.Conf.HeaderTitle != "" {
title = config.Conf.HeaderTitle
}
welcomeMsg := user + " " + title
_, err := io.WriteString(sess, welcomeMsg)
if err != nil {
logger.Error("Send to client error, %s", err)
}
cm := ColorMeta{GreenBoldColor: "\033[1;32m", ColorEnd: "\033[0m"}
for i, v := range menu {
line := fmt.Sprintf("\t%d) Enter {{.GreenBoldColor}}%s{{.ColorEnd}} to %s.\r\n", i+1, v.instruct, v.helpText)
tmpl := template.Must(template.New("item").Parse(line))
err := tmpl.Execute(sess, cm)
if err != nil {
logger.Error("Send to client error, %s", err)
}
}
}
...@@ -2,9 +2,6 @@ package handler ...@@ -2,9 +2,6 @@ package handler
const ( const (
GreenColorCode = "\033[32m" GreenColorCode = "\033[32m"
ColorEnd = "\033[0m"
Tab = "\t"
EndLine = "\r\n\r"
) )
const ( const (
......
...@@ -4,7 +4,11 @@ import ( ...@@ -4,7 +4,11 @@ import (
//"context" //"context"
//"strconv" //"strconv"
"cocogo/pkg/model"
"cocogo/pkg/proxy"
"cocogo/pkg/sdk" "cocogo/pkg/sdk"
"cocogo/pkg/service"
"cocogo/pkg/userhome"
"context" "context"
"fmt" "fmt"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
...@@ -37,56 +41,65 @@ import ( ...@@ -37,56 +41,65 @@ import (
) )
type InteractiveHandler struct { type InteractiveHandler struct {
sess ssh.Session sess ssh.Session
term *terminal.Terminal term *terminal.Terminal
user sdk.User user sdk.User
banner *Banner assets model.AssetList
currentSearchAssets []sdk.Asset searchResult model.AssetList
onceLoad sync.Once nodes model.NodeList
onceLoad sync.Once
sync.RWMutex sync.RWMutex
} }
func (i *InteractiveHandler) displayBanner() { func (i *InteractiveHandler) displayBanner() {
i.banner.display(i.sess) displayBanner(i.sess, i.user.Name)
} }
func (i *InteractiveHandler) Dispatch() { func (i *InteractiveHandler) preDispatch() {
i.displayBanner() i.displayBanner()
_, winCh, _ := i.sess.Pty() i.onceLoad.Do(func() {
i.loadUserAssets()
i.loadUserAssetNodes()
})
}
func (i *InteractiveHandler) watchSizeChange(winCh <-chan ssh.Window) {
ctx, cancelFunc := context.WithCancel(i.sess.Context())
defer cancelFunc()
for { for {
ctx, cancelFunc := context.WithCancel(i.sess.Context()) select {
go func() { case <-ctx.Done():
for { logger.Info("ctx done")
select { return
case <-ctx.Done(): case win, ok := <-winCh:
logger.Info("ctx done") if !ok {
return return
case win, ok := <-winCh:
if !ok {
return
}
logger.Info("Term change:", win)
_ = i.term.SetSize(win.Width, win.Height)
}
} }
}() logger.Info("Term change:", win)
_ = i.term.SetSize(win.Width, win.Height)
}
}
}
func (i *InteractiveHandler) Dispatch() {
i.preDispatch()
_, winCh, _ := i.sess.Pty()
for {
go i.watchSizeChange(winCh)
line, err := i.term.ReadLine() line, err := i.term.ReadLine()
cancelFunc()
if err != nil { if err != nil {
logger.Error("ReadLine done", err) logger.Error("ReadLine done", err)
break break
} }
if line == "" {
continue
}
if len(line) == 1 { switch len(line) {
case 0, 1:
switch line { switch line {
case "p", "P": case "", "p", "P":
i.displayAssets([]sdk.Asset{}) i.displayAssets(i.assets)
case "g", "G": case "g", "G":
i.displayNodes([]sdk.Node{}) i.displayNodes(i.nodes)
case "s", "S": case "s", "S":
i.changeLanguage() i.changeLanguage()
case "h", "H": case "h", "H":
...@@ -98,41 +111,28 @@ func (i *InteractiveHandler) Dispatch() { ...@@ -98,41 +111,28 @@ func (i *InteractiveHandler) Dispatch() {
return return
default: default:
assets := i.searchAsset(line) assets := i.searchAsset(line)
i.currentSearchAssets = assets i.searchResult = assets
i.displayAssetsOrProxy(assets) i.displayAssetsOrProxy(assets)
} }
continue default:
} switch {
if strings.Index(line, "/") == 0 { case strings.Index(line, "/") == 0:
searchWord := strings.TrimSpace(strings.TrimPrefix(line, "/")) searchWord := strings.TrimSpace(line[1:])
assets := i.searchAsset(searchWord) assets := i.searchAsset(searchWord)
i.currentSearchAssets = assets i.searchResult = assets
i.displayAssets(assets) i.displayAssets(assets)
continue case strings.Index(line, "g") == 0:
} searchWord := strings.TrimSpace(strings.TrimPrefix(line, "g"))
if num, err := strconv.Atoi(searchWord); err == nil {
if strings.Index(line, "g") == 0 { if num >= 0 {
searchWord := strings.TrimSpace(strings.TrimPrefix(line, "g")) assets := i.searchNodeAssets(num)
if num, err := strconv.Atoi(searchWord); err == nil { i.displayAssets(assets)
if num >= 0 { i.searchResult = assets
assets := i.searchNodeAssets(num) continue
i.displayAssets(assets) }
i.currentSearchAssets = assets
continue
} }
} }
} }
if strings.Index(line, "join") == 0 {
roomID := strings.TrimSpace(strings.TrimPrefix(line, "join"))
i.JoinShareRoom(roomID)
continue
}
assets := i.searchAsset(line)
i.currentSearchAssets = assets
i.displayAssetsOrProxy(assets)
} }
} }
...@@ -180,7 +180,7 @@ func (i *InteractiveHandler) displayAssetsOrProxy(assets []sdk.Asset) { ...@@ -180,7 +180,7 @@ func (i *InteractiveHandler) displayAssetsOrProxy(assets []sdk.Asset) {
if err != nil { if err != nil {
return return
} }
if ok := sdk.ValidateUserAssetPermission(i.user.Id, systemUser.Id, assets[0].Id); !ok { if ok := service.ValidateUserAssetPermission(i.user.Id, systemUser.Id, assets[0].Id); !ok {
// 检查user 是否对该资产有权限 // 检查user 是否对该资产有权限
return return
} }
...@@ -195,7 +195,7 @@ func (i *InteractiveHandler) displayAssetsOrProxy(assets []sdk.Asset) { ...@@ -195,7 +195,7 @@ func (i *InteractiveHandler) displayAssetsOrProxy(assets []sdk.Asset) {
} }
} }
func (i *InteractiveHandler) displayAssets(assets []sdk.Asset) { func (i *InteractiveHandler) displayAssets(assets model.AssetList) {
if len(assets) == 0 { if len(assets) == 0 {
_, _ = io.WriteString(i.sess, "\r\n No Assets\r\n\r") _, _ = io.WriteString(i.sess, "\r\n No Assets\r\n\r")
} else { } else {
...@@ -235,99 +235,86 @@ func (i *InteractiveHandler) refreshAssetsAndNodesData() { ...@@ -235,99 +235,86 @@ func (i *InteractiveHandler) refreshAssetsAndNodesData() {
if err != nil { if err != nil {
logger.Error("refresh Assets Nodes err:", err) logger.Error("refresh Assets Nodes err:", err)
} }
}
func (i *InteractiveHandler) loadUserAssets() {
i.assets = service.GetUserAssets(i.user.Id)
}
func (i *InteractiveHandler) loadUserAssetNodes() {
i.nodes = service.GetUserNodes(i.user.Id)
} }
//
//func (i *InteractiveHandler) loadUserAssets() {
// assets, err := appService.GetUserAssets(i.user.Id)
// if err != nil {
// logger.Error("load Assets failed")
// return
// }
// logger.Info("load Assets success")
// Cached.Store(i.user.Id, assets)
// i.assetData.Store(AssetsMapKey, assets)
//}
//
//func (i *InteractiveHandler) loadUserAssetNodes() {
// assetNodes, err := appService.GetUserAssetNodes(i.user.Id)
// if err != nil {
// logger.Error("load Asset Nodes failed")
// return
// }
// logger.Info("load Asset Nodes success")
// i.assetData.Store(AssetNodesMapKey, assetNodes)
//}
//
func (i *InteractiveHandler) changeLanguage() { func (i *InteractiveHandler) changeLanguage() {
} }
// func (i *InteractiveHandler) JoinShareRoom(roomID string) {
//func (i *InteractiveHandler) JoinShareRoom(roomID string) { sshConn := userhome.NewSSHConn(i.sess)
// sshConn := userhome.NewSSHConn(i.sess) ctx, cancelFuc := context.WithCancel(i.sess.Context())
// ctx, cancelFuc := context.WithCancel(i.sess.Context())
// _, winCh, _ := i.sess.Pty()
// _, winCh, _ := i.sess.Pty() go func() {
// go func() { for {
// for { select {
// select { case <-ctx.Done():
// case <-ctx.Done(): return
// return case win, ok := <-winCh:
// case win, ok := <-winCh: if !ok {
// if !ok { return
// return }
// } fmt.Println("join term change:", win)
// fmt.Println("join term change:", win) }
// } }
// } }()
// }() proxy.Manager.JoinShareRoom(roomID, sshConn)
// proxy.Manager.JoinShareRoom(roomID, sshConn) logger.Info("exit room id:", roomID)
// logger.Info("exit room id:", roomID) cancelFuc()
// cancelFuc()
// }
//}
// func (i *InteractiveHandler) searchAsset(key string) (assets []sdk.Asset) {
//func (i *InteractiveHandler) searchAsset(key string) (assets []sdk.Asset) { //if indexNum, err := strconv.Atoi(key); err == nil {
// if indexNum, err := strconv.Atoi(key); err == nil { // if indexNum > 0 && indexNum <= len(i.searchResult) {
// if indexNum > 0 && indexNum <= len(i.currentSearchAssets) { // return []sdk.Asset{i.searchResult[indexNum-1]}
// return []sdk.Asset{i.currentSearchAssets[indexNum-1]} // }
// } //}
// } //
// //if assetsData, ok := i.assetData.Load(AssetsMapKey); ok {
// if assetsData, ok := i.assetData.Load(AssetsMapKey); ok { // for _, assetValue := range assetsData.([]sdk.Asset) {
// for _, assetValue := range assetsData.([]sdk.Asset) { // if isSubstring([]string{assetValue.Ip, assetValue.Hostname, assetValue.Comment}, key) {
// if isSubstring([]string{assetValue.Ip, assetValue.Hostname, assetValue.Comment}, key) { // assets = append(assets, assetValue)
// assets = append(assets, assetValue) // }
// } // }
// } //} else {
// } else { // assetsData, _ := Cached.Load(i.user.Id)
// assetsData, _ := Cached.Load(i.user.Id) // for _, assetValue := range assetsData.([]sdk.Asset) {
// for _, assetValue := range assetsData.([]sdk.Asset) { // if isSubstring([]string{assetValue.Ip, assetValue.Hostname, assetValue.Comment}, key) {
// if isSubstring([]string{assetValue.Ip, assetValue.Hostname, assetValue.Comment}, key) { // assets = append(assets, assetValue)
// assets = append(assets, assetValue) // }
// } // }
// } //}
// }
// return assets
// return assets }
//}
// func (i *InteractiveHandler) searchNodeAssets(num int) (assets []sdk.Asset) {
//func (i *InteractiveHandler) searchNodeAssets(num int) (assets []sdk.Asset) { //var assetNodesData []sdk.Node
// var assetNodesData []sdk.Node //if assetNodes, ok := i.assetData.Load(AssetNodesMapKey); ok {
// if assetNodes, ok := i.assetData.Load(AssetNodesMapKey); ok { // assetNodesData = assetNodes.([]sdk.Node)
// assetNodesData = assetNodes.([]sdk.Node) // if num > len(assetNodesData) || num == 0 {
// if num > len(assetNodesData) || num == 0 { // return assets
// return assets // }
// } // return assetNodesData[num-1].AssetsGranted
// return assetNodesData[num-1].AssetsGranted //}
// } return assets
// return assets
// }
//}
// func (i *InteractiveHandler) Proxy(asset sdk.Asset, systemUser sdk.SystemUserAuthInfo) error {
//func (i *InteractiveHandler) Proxy(asset sdk.Asset, systemUser sdk.SystemUserAuthInfo) error { return nil
}
// /* // /*
// 1. 创建SSHConn,符合core.Conn接口 // 1. 创建SSHConn,符合core.Conn接口
// 2. 创建一个session Home // 2. 创建一个session Home
...@@ -433,15 +420,12 @@ func ConstructAssetNodeTree(assetNodes []sdk.Node) treeprint.Tree { ...@@ -433,15 +420,12 @@ func ConstructAssetNodeTree(assetNodes []sdk.Node) treeprint.Tree {
func SessionHandler(sess ssh.Session) { func SessionHandler(sess ssh.Session) {
_, _, ptyOk := sess.Pty() _, _, ptyOk := sess.Pty()
if ptyOk { if ptyOk {
banner := NewBanner(sess.User())
handler := &InteractiveHandler{ handler := &InteractiveHandler{
sess: sess, sess: sess,
term: terminal.NewTerminal(sess, "Opt> "), term: terminal.NewTerminal(sess, "Opt> "),
banner: banner,
} }
logger.Info("Accept one session") logger.Info("Accept one session")
handler.displayBanner()
handler.Dispatch() handler.Dispatch()
} else { } else {
_, err := io.WriteString(sess, "No PTY requested.\n") _, err := io.WriteString(sess, "No PTY requested.\n")
...@@ -449,5 +433,4 @@ func SessionHandler(sess ssh.Session) { ...@@ -449,5 +433,4 @@ func SessionHandler(sess ssh.Session) {
return return
} }
} }
} }
package handler
import (
"fmt"
"strings"
)
const (
ColorStart = "\033["
Green = "32m"
Red = "41m"
White = "47m"
ColorEnd = "0m"
Tab = "\t"
EndLine = "\r\n"
Bold = "1"
)
func WrapperString(text string, color string, bold bool) string {
wrapWith := make([]string, 1)
if bold {
wrapWith = append(wrapWith, Bold)
}
wrapWith = append(wrapWith, color)
return fmt.Sprintf("%s%s%s", strings.Join(wrapWith, ";"), text, ColorEnd)
}
func STitle(text string) string {
return WrapperString(text, Green, true)
}
func SWarn(text string) string {
return WrapperString(text, White, false)
}
...@@ -7,8 +7,9 @@ import ( ...@@ -7,8 +7,9 @@ import (
"cocogo/pkg/auth" "cocogo/pkg/auth"
"cocogo/pkg/config" "cocogo/pkg/config"
"cocogo/pkg/handler"
"cocogo/pkg/logger" "cocogo/pkg/logger"
"./handler"
) )
var ( var (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment