Unverified Commit 9bbcfa95 authored by Eric_Lee's avatar Eric_Lee Committed by GitHub

Merge pull request #145 from jumpserver/dev

Dev
parents b185b1a2 b4ed7c7a
# KoKo # KoKo
koko是golang版本的的coco;重构了coco的SSH/SFTP服务和web terminal服务。 Koko 是 Go 版本的 coco;重构了 coco 的 SSH/SFTP 服务和 Web Terminal 服务
## 主要功能 ## 主要功能
......
...@@ -30,17 +30,17 @@ msgstr "部分IP、主机名、备注" ...@@ -30,17 +30,17 @@ msgstr "部分IP、主机名、备注"
#. i18n.T #. i18n.T
#: pkg/handler/banner.go:49 #: pkg/handler/banner.go:49
msgid "to search login if unique" msgid "to search login if unique"
msgstr "进行搜索登录(如果唯一)" msgstr "搜索登录(如果唯一)"
#. i18n.T #. i18n.T
#: pkg/handler/banner.go:50 #: pkg/handler/banner.go:50
msgid "/ + IP, Hostname, Comment" msgid "/ + IP, Hostname, Comment"
msgstr "/ + IP, 主机名 or 备注" msgstr "/ + IP,主机名 or 备注"
#. i18n.T #. i18n.T
#: pkg/handler/banner.go:50 #: pkg/handler/banner.go:50
msgid "to search, such as: /192.168" msgid "to search, such as: /192.168"
msgstr "搜索, 如:/192.168" msgstr "搜索,如:/192.168"
#. i18n.T #. i18n.T
#: pkg/handler/banner.go:51 #: pkg/handler/banner.go:51
......
...@@ -37,7 +37,7 @@ type UrlParser interface { ...@@ -37,7 +37,7 @@ type UrlParser interface {
} }
func NewClient(timeout time.Duration, baseHost string) Client { func NewClient(timeout time.Duration, baseHost string) Client {
headers := make(map[string]string, 0) headers := make(map[string]string)
client := http.Client{ client := http.Client{
Timeout: timeout * time.Second, Timeout: timeout * time.Second,
} }
...@@ -46,7 +46,7 @@ func NewClient(timeout time.Duration, baseHost string) Client { ...@@ -46,7 +46,7 @@ func NewClient(timeout time.Duration, baseHost string) Client {
Timeout: timeout * time.Second, Timeout: timeout * time.Second,
Headers: headers, Headers: headers,
http: client, http: client,
cookie: make(map[string]string, 0), cookie: make(map[string]string),
} }
} }
......
...@@ -26,7 +26,6 @@ type WrapperTable struct { ...@@ -26,7 +26,6 @@ type WrapperTable struct {
paddingSize int paddingSize int
bolderSize int bolderSize int
fieldsSize map[string]int // 计算后的最终宽度 fieldsSize map[string]int // 计算后的最终宽度
cleanedData []map[string]string
Caption string Caption string
} }
......
...@@ -36,7 +36,7 @@ func (mi *MenuItem) Text() string { ...@@ -36,7 +36,7 @@ func (mi *MenuItem) Text() string {
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
mi.showText = string(buf.Bytes()) mi.showText = buf.String()
return mi.showText return mi.showText
} }
......
...@@ -299,8 +299,7 @@ func (p *UserAssetPagination) displayPageAssets() { ...@@ -299,8 +299,7 @@ func (p *UserAssetPagination) displayPageAssets() {
var totalPage int var totalPage int
var currentPage int var currentPage int
var totalCount int var totalCount int
var currentOffset int currentOffset := p.offset + len(p.currentData)
currentOffset = p.offset + len(p.currentData)
switch p.limit { switch p.limit {
case 0: case 0:
pageSize = len(p.currentData) pageSize = len(p.currentData)
......
...@@ -58,9 +58,6 @@ type interactiveHandler struct { ...@@ -58,9 +58,6 @@ type interactiveHandler struct {
searchResult []model.Asset searchResult []model.Asset
allAssets []model.Asset allAssets []model.Asset
search string
offset int
limit int
loadDataDone chan struct{} loadDataDone chan struct{}
assetLoadPolicy string assetLoadPolicy string
...@@ -297,9 +294,9 @@ func (h *interactiveHandler) displayAssets(assets model.AssetList) { ...@@ -297,9 +294,9 @@ func (h *interactiveHandler) displayAssets(assets model.AssetList) {
func (h *interactiveHandler) displayNodes(nodes []model.Node) { func (h *interactiveHandler) displayNodes(nodes []model.Node) {
tree := ConstructAssetNodeTree(nodes) tree := ConstructAssetNodeTree(nodes)
_, err := io.WriteString(h.term, "\n\r"+getI18nFromMap("NodeHeaderTip")) _, _ = io.WriteString(h.term, "\n\r"+getI18nFromMap("NodeHeaderTip"))
_, err = io.WriteString(h.term, tree.String()) _, _ = io.WriteString(h.term, tree.String())
_, err = io.WriteString(h.term, getI18nFromMap("NodeEndTip")+"\n\r") _, err := io.WriteString(h.term, getI18nFromMap("NodeEndTip")+"\n\r")
if err != nil { if err != nil {
logger.Info("displayAssetNodes err:", err) logger.Info("displayAssetNodes err:", err)
} }
......
...@@ -61,8 +61,7 @@ func (w *WrapperSession) Read(p []byte) (int, error) { ...@@ -61,8 +61,7 @@ func (w *WrapperSession) Read(p []byte) (int, error) {
} }
func (w *WrapperSession) Close() error { func (w *WrapperSession) Close() error {
var err error err := w.inWriter.Close()
err = w.inWriter.Close()
w.initReadPip() w.initReadPip()
return err return err
} }
......
...@@ -66,10 +66,8 @@ func (c *Connections) GetClients(cID string) (clients []string) { ...@@ -66,10 +66,8 @@ func (c *Connections) GetClients(cID string) (clients []string) {
} }
func (c *Connections) DeleteClients(cID string) { func (c *Connections) DeleteClients(cID string) {
if clientIDs := c.GetClients(cID); clientIDs != nil { for _, clientID := range c.GetClients(cID) {
for _, clientID := range clientIDs { clients.DeleteClient(clientID)
clients.DeleteClient(clientID)
}
} }
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
......
...@@ -38,7 +38,7 @@ func (c *Coco) Stop() { ...@@ -38,7 +38,7 @@ func (c *Coco) Stop() {
func RunForever() { func RunForever() {
ctx,cancelFunc := context.WithCancel(context.Background()) ctx,cancelFunc := context.WithCancel(context.Background())
bootstrap(ctx) bootstrap(ctx)
gracefulStop := make(chan os.Signal) gracefulStop := make(chan os.Signal, 1)
signal.Notify(gracefulStop, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) signal.Notify(gracefulStop, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)
app := &Coco{} app := &Coco{}
app.Start() app.Start()
......
...@@ -46,6 +46,6 @@ func (hook *RotateFileHook) Fire(entry *logrus.Entry) (err error) { ...@@ -46,6 +46,6 @@ func (hook *RotateFileHook) Fire(entry *logrus.Entry) (err error) {
if err != nil { if err != nil {
return err return err
} }
hook.logWriter.Write(b) _, err = hook.logWriter.Write(b)
return nil return
} }
...@@ -123,7 +123,6 @@ func (p *Parser) parseInputState(b []byte) []byte { ...@@ -123,7 +123,6 @@ func (p *Parser) parseInputState(b []byte) []byte {
if bytes.Contains(b, charEnter) { if bytes.Contains(b, charEnter) {
// 连续输入enter key, 结算上一条可能存在的命令结果 // 连续输入enter key, 结算上一条可能存在的命令结果
p.sendCommandRecord() p.sendCommandRecord()
p.inputState = false p.inputState = false
// 用户输入了Enter,开始结算命令 // 用户输入了Enter,开始结算命令
p.parseCmdInput() p.parseCmdInput()
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
var ps1Pattern = regexp.MustCompile(`^\[?.*@.*\]?[\\$#]\s|mysql>\s`) var ps1Pattern = regexp.MustCompile(`^\[?.*@.*\]?[\\$#]\s|mysql>\s`)
func NewCmdParser(sid, name string) *CmdParser { func NewCmdParser(sid, name string) *CmdParser {
parser := CmdParser{id: sid, name:name} parser := CmdParser{id: sid, name: name}
parser.initial() parser.initial()
return &parser return &parser
} }
...@@ -102,4 +102,4 @@ func (cp *CmdParser) Parse() string { ...@@ -102,4 +102,4 @@ func (cp *CmdParser) Parse() string {
cp.currentLines = make([]string, 0) cp.currentLines = make([]string, 0)
cp.currentLength = 0 cp.currentLength = 0
return output return output
} }
\ No newline at end of file
package proxy package proxy
import ( import (
"fmt" "strings"
"testing" "testing"
"github.com/jumpserver/koko/pkg/utils"
) )
func TestCmdParser_Parse(t *testing.T) { func TestCmdParser_Parse(t *testing.T) {
p := NewCmdParser()
var b = []byte("ifconfig \x08\x1b[K\x08\x1b[K\x08\x1b[K\x08\x1b[K\x08\x1b[K\x08\x1b[Konfig") var b = []byte("ifconfig \x08\x1b[K\x08\x1b[K\x08\x1b[K\x08\x1b[K\x08\x1b[K\x08\x1b[Konfig")
data := p.Parse(b) data := utils.ParseTerminalData(b)
if data != "ifconfig" {
t.Error("data should be ifconfig but not") if strings.Join(data, "") != "ifconfig" {
t.Error("data should be ifconfig but not", data)
} }
b = []byte("ifconfig\xe4\xbd\xa0") b = []byte("ifconfig\xe4\xbd\xa0")
data = p.Parse(b) data = utils.ParseTerminalData(b)
fmt.Println("line: ", data) t.Log("line: ", strings.Join(data, ""))
} }
...@@ -237,7 +237,6 @@ func (p *ProxyServer) sendConnectErrorMsg(err error) { ...@@ -237,7 +237,6 @@ func (p *ProxyServer) sendConnectErrorMsg(err error) {
msg2 := fmt.Sprintf("Try password: %s", password[:showLen]+strings.Repeat("*", hiddenLen)) msg2 := fmt.Sprintf("Try password: %s", password[:showLen]+strings.Repeat("*", hiddenLen))
logger.Errorf(msg2) logger.Errorf(msg2)
} }
return
} }
// Proxy 代理 // Proxy 代理
......
...@@ -27,7 +27,7 @@ const ( ...@@ -27,7 +27,7 @@ const (
SAG = 3 SAG = 3
ECHO = 1 ECHO = 1
loginRegs = "(?i)login:?\\s*$|username:?\\s*$|name:?\\s*$|用户名:?\\s*$|账\\s*号:?\\s*$" loginRegs = "(?i)login:?\\s*$|username:?\\s*$|name:?\\s*$|用户名:?\\s*$|账\\s*号:?\\s*$|user:?\\s*$"
passwordRegs = "(?i)Password:?\\s*$|ssword:?\\s*$|passwd:?\\s*$|密\\s*码:?\\s*$" passwordRegs = "(?i)Password:?\\s*$|ssword:?\\s*$|passwd:?\\s*$|密\\s*码:?\\s*$"
FailedRegs = "(?i)incorrect|failed|失败|错误" FailedRegs = "(?i)incorrect|failed|失败|错误"
DefaultSuccessRegs = "(?i)Last\\s*login|success|成功|#|>|\\$" DefaultSuccessRegs = "(?i)Last\\s*login|success|成功|#|>|\\$"
...@@ -122,11 +122,11 @@ func (tc *ServerTelnetConnection) login(data []byte) AuthStatus { ...@@ -122,11 +122,11 @@ func (tc *ServerTelnetConnection) login(data []byte) AuthStatus {
return AuthFailed return AuthFailed
} else if usernamePattern.Match(data) { } else if usernamePattern.Match(data) {
_, _ = tc.conn.Write([]byte(tc.SystemUser.Username + "\r\n")) _, _ = tc.conn.Write([]byte(tc.SystemUser.Username + "\r\n"))
logger.Debug("Username pattern match: ", data) logger.Debugf("Username pattern match: %s", data)
return AuthPartial return AuthPartial
} else if passwordPattern.Match(data) { } else if passwordPattern.Match(data) {
_, _ = tc.conn.Write([]byte(tc.SystemUser.Password + "\r\n")) _, _ = tc.conn.Write([]byte(tc.SystemUser.Password + "\r\n"))
logger.Debug("Password pattern ", data) logger.Debugf("Password pattern: %s", data)
return AuthPartial return AuthPartial
} else if successPattern.Match(data) { } else if successPattern.Match(data) {
return AuthSuccess return AuthSuccess
...@@ -148,7 +148,7 @@ func (tc *ServerTelnetConnection) Connect(h, w int, term string) (err error) { ...@@ -148,7 +148,7 @@ func (tc *ServerTelnetConnection) Connect(h, w int, term string) (err error) {
if asset.Domain != "" { if asset.Domain != "" {
sshConfig := MakeConfig(tc.Asset, tc.SystemUser, tc.Timeout()) sshConfig := MakeConfig(tc.Asset, tc.SystemUser, tc.Timeout())
proxyConn, err = sshConfig.DialProxy() proxyConn, err = sshConfig.DialProxy()
logger.Errorf("Proxy conn: ", proxyConn) logger.Errorf("Proxy conn: %p", proxyConn)
if err != nil { if err != nil {
logger.Error("Dial proxy host error") logger.Error("Dial proxy host error")
return return
...@@ -169,7 +169,7 @@ func (tc *ServerTelnetConnection) Connect(h, w int, term string) (err error) { ...@@ -169,7 +169,7 @@ func (tc *ServerTelnetConnection) Connect(h, w int, term string) (err error) {
return return
} }
if tc.SystemUser.Password == ""{ if tc.SystemUser.Password == "" {
info := service.GetSystemUserAssetAuthInfo(tc.SystemUser.ID, asset.ID) info := service.GetSystemUserAssetAuthInfo(tc.SystemUser.ID, asset.ID)
tc.SystemUser.Password = info.Password tc.SystemUser.Password = info.Password
tc.SystemUser.PrivateKey = info.PrivateKey tc.SystemUser.PrivateKey = info.PrivateKey
...@@ -193,7 +193,7 @@ func (tc *ServerTelnetConnection) Connect(h, w int, term string) (err error) { ...@@ -193,7 +193,7 @@ func (tc *ServerTelnetConnection) Connect(h, w int, term string) (err error) {
case AuthSuccess: case AuthSuccess:
return nil return nil
case AuthFailed: case AuthFailed:
return errors.New("Failed login") return errors.New("failed login")
default: default:
continue continue
} }
......
package utils
import (
"bytes"
"fmt"
"unicode/utf8"
)
func ParseTerminalData(p []byte) (lines []string) {
c := bytes.NewReader(p)
pasteActive := false
var line []rune
var pos int
var remainder []byte
var inBuf [256]byte
for {
rest := remainder
lineOk := false
for !lineOk {
var key rune
key, rest = bytesToKey(rest, pasteActive)
if key == utf8.RuneError {
break
}
if !pasteActive {
if key == keyPasteStart {
pasteActive = true
if len(line) == 0 {
}
continue
}
} else if key == keyPasteEnd {
pasteActive = false
continue
}
switch key {
case keyBackspace:
if pos == 0 {
continue
}
line, pos = EraseNPreviousChars(1, pos, line)
case keyAltLeft:
// move left by a word.
pos -= CountToLeftWord(pos, line)
case keyAltRight:
// move right by a word.
pos += CountToRightWord(pos, line)
case keyLeft:
if pos == 0 {
continue
}
pos--
case keyRight:
if pos == len(line) {
continue
}
pos++
case keyHome:
if pos == 0 {
continue
}
pos = 0
case keyEnd:
if pos == len(line) {
continue
}
pos = len(line)
case keyUp:
line = []rune{}
pos = 0
case keyDown:
line = []rune{}
pos = 0
case keyEnter:
lines = append(lines, string(line))
line = line[:0]
pos = 0
lineOk = true
case keyDeleteWord:
// Delete zero or more spaces and then one or more characters.
line, pos = EraseNPreviousChars(CountToLeftWord(pos, line), pos, line)
case keyDeleteLine:
line = line[:pos]
case keyCtrlD:
// Erase the character under the current position.
// The EOF case when the line is empty is handled in
// readLine().
if pos < len(line) {
pos++
line, pos = EraseNPreviousChars(1, pos, line)
}
case keyCtrlU:
line = line[:0]
case keyClearScreen:
default:
if !isPrintable(key) {
fmt.Println("could not printable: ", []byte(string(key)), " ", key)
continue
}
line, pos = AddKeyToLine(key, pos, line)
}
}
if len(rest) > 0 {
n := copy(inBuf[:], rest)
remainder = inBuf[:n]
} else {
remainder = nil
}
// remainder is a slice at the beginning of t.inBuf
// containing a partial key sequence
readBuf := inBuf[len(remainder):]
var n int
n, err := c.Read(readBuf)
if err != nil {
if len(line) > 0 {
lines = append(lines, string(line))
} else if len(rest) > 0 {
lines = append(lines, string(rest))
}
return
}
remainder = inBuf[:n+len(remainder)]
}
}
func EraseNPreviousChars(n, cPos int, line []rune) ([]rune, int) {
if n == 0 {
return line, cPos
}
if cPos < n {
n = cPos
}
cPos -= n
copy(line[cPos:], line[n+cPos:])
return line[:len(line)-n], cPos
}
func CountToLeftWord(currentPos int, line []rune) int {
if currentPos == 0 {
return 0
}
pos := currentPos - 1
for pos > 0 {
if line[pos] != ' ' {
break
}
pos--
}
for pos > 0 {
if line[pos] == ' ' {
pos++
break
}
pos--
}
return currentPos - pos
}
func CountToRightWord(currentPos int, line []rune) int {
pos := currentPos
for pos < len(line) {
if line[pos] == ' ' {
break
}
pos++
}
for pos < len(line) {
if line[pos] != ' ' {
break
}
pos++
}
return pos - currentPos
}
func AddKeyToLine(key rune, pos int, line []rune) ([]rune, int) {
if len(line) == cap(line) {
newLine := make([]rune, len(line), 2*(1+len(line)))
copy(newLine, line)
line = newLine
}
line = line[:len(line)+1]
copy(line[pos+1:], line[pos:])
line[pos] = key
pos++
return line, pos
}
\ No newline at end of file
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