From 545ec26ea896562b09b00db2b4bd01d1961f5beb Mon Sep 17 00:00:00 2001 From: shylinux Date: Tue, 1 Jun 2021 06:58:45 +0800 Subject: [PATCH] opt ssh.scripts --- base/mdb/mdb.go | 13 ++-- base/ssh/channel.go | 11 +-- base/ssh/connect.go | 7 ++ base/ssh/scripts.go | 147 +++++++++++++++++++++----------------- base/ssh/service.go | 83 +++++++++++---------- base/ssh/service_linux.go | 5 +- base/ssh/session.go | 2 +- base/ssh/ssh.go | 12 +--- base/ssh/ssh.shy | 9 ++- conf.go | 1 + 10 files changed, 165 insertions(+), 125 deletions(-) diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 1f2f4e08..507aafba 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -170,9 +170,9 @@ func _list_select(m *ice.Message, prefix, chain, field, value string) { } } }) - if m.Option(FIELDS) != DETAIL { - m.SortIntR(kit.MDB_ID) - } + // if m.Option(FIELDS) != DETAIL { + // m.SortIntR(kit.MDB_ID) + // } } func _list_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) { m.Grows(prefix, chain, field, value, func(index int, val map[string]interface{}) { @@ -412,9 +412,10 @@ const ( INPUTS = "inputs" ) const ( - CACHE_LIMIT = "cache.limit" - CACHE_FIELD = "cache.field" - CACHE_VALUE = "cache.value" + CACHE_LIMIT = "cache.limit" + CACHE_FIELD = "cache.field" + CACHE_VALUE = "cache.value" + CACHE_OFFEND = "cache.offend" CACHE_CLEAR_ON_EXIT = "cache.clear.on.exit" ) diff --git a/base/ssh/channel.go b/base/ssh/channel.go index 6061f74f..f1753b92 100644 --- a/base/ssh/channel.go +++ b/base/ssh/channel.go @@ -34,7 +34,7 @@ func _ssh_exec(m *ice.Message, cmd string, arg []string, env []string, tty io.Re } func _ssh_close(m *ice.Message, c net.Conn, channel ssh.Channel) { defer channel.Close() - channel.Write([]byte(m.Conf(SERVICE, "meta.goodbye"))) + channel.Write([]byte(m.Conf(SERVICE, kit.Keym(GOODBYE)))) } func _ssh_watch(m *ice.Message, meta map[string]string, h string, input io.Reader, output io.Writer, display io.Writer) { r, w := io.Pipe() @@ -77,11 +77,13 @@ func init() { m.Cmdy(mdb.DELETE, CHANNEL, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Option(mdb.FIELDS, "time,hash,status,username,hostport,tty,count") + m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR) m.Cmdy(mdb.PRUNES, CHANNEL, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) == 0 { - m.Option(mdb.FIELDS, "time,hash,status,username,hostname,hostport,tty,count") + if len(arg) == 0 { // 通道列表 + m.Fields(len(arg) == 0, "time,hash,status,username,hostport,tty,count") if m.Cmdy(mdb.SELECT, CHANNEL, "", mdb.HASH); len(arg) == 0 { m.Table(func(index int, value map[string]string, head []string) { m.PushButton(kit.Select("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) @@ -90,7 +92,8 @@ func init() { return } - m.Option(mdb.FIELDS, kit.Select("time,id,type,text", mdb.DETAIL, len(arg) > 1)) + // 通道命令 + m.Fields(len(arg) == 1, "time,id,type,text") m.Cmdy(mdb.SELECT, CHANNEL, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:]) }}, }, diff --git a/base/ssh/connect.go b/base/ssh/connect.go index d1032f7f..3bf4df65 100644 --- a/base/ssh/connect.go +++ b/base/ssh/connect.go @@ -172,6 +172,13 @@ func init() { CONNECT: {Name: CONNECT, Help: "连接", Value: kit.Data()}, }, Commands: map[string]*ice.Command{ + ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Richs(CONNECT, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + if value = kit.GetMeta(value); kit.Value(value, kit.MDB_STATUS) == tcp.OPEN { + m.Cmd(CONNECT, tcp.DIAL, aaa.USERNAME, value[aaa.USERNAME], value) + } + }) + }}, CONNECT: {Name: "connect hash auto dial prunes", Help: "连接", Action: map[string]*ice.Action{ tcp.OPEN: {Name: "open authfile= username=shy password= verfiy= host=shylinux.com port=22 private=.ssh/id_rsa", Help: "终端", Hand: func(m *ice.Message, arg ...string) { _ssh_open(m, arg...) diff --git a/base/ssh/scripts.go b/base/ssh/scripts.go index d600505e..122cc8f6 100644 --- a/base/ssh/scripts.go +++ b/base/ssh/scripts.go @@ -21,17 +21,10 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) { switch arg := kit.Simple(args...); cmd { case ice.RENDER_VOID: case ice.RENDER_RESULT: - fmt.Fprint(msg.O, msg.Result()) - - case ice.RENDER_QRCODE: - fmt.Fprint(msg.O, msg.Cmdx("cli.qrcode", kit.Format(args[0], args[1:]...))) - - case ice.RENDER_DOWNLOAD: - if f, e := os.Open(arg[0]); e == nil { - defer f.Close() - - io.Copy(msg.O, f) + if len(arg) > 0 { + msg.Resultv(arg) } + fmt.Fprint(msg.O, msg.Result()) default: // 转换结果 @@ -39,7 +32,6 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) { if res == "" { res = msg.Table().Result() } - args = append(args, "length:", len(res)) // 输出结果 if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, "\n") { @@ -48,11 +40,12 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) { } } func Script(m *ice.Message, name string) io.Reader { - if strings.Contains(m.Option("_script"), "/") { - name = path.Join(path.Dir(m.Option("_script")), name) + if strings.Contains(m.Option(ice.MSG_SCRIPT), "/") { + name = path.Join(path.Dir(m.Option(ice.MSG_SCRIPT)), name) } - m.Option("_script", name) + m.Option(ice.MSG_SCRIPT, name) + // 本地文件 back := kit.Split(m.Option(nfs.DIR_ROOT)) for i := len(back) - 1; i >= 0; i-- { if s, e := os.Open(path.Join(path.Join(back[:i]...), name)); e == nil { @@ -64,24 +57,26 @@ func Script(m *ice.Message, name string) io.Reader { } switch strings.Split(name, "/")[0] { - case "etc", "var": + case kit.SSH_ETC, kit.SSH_VAR: m.Warn(true, ice.ErrNotFound) return nil } + // 打包文件 if b, ok := ice.BinPack["/"+name]; ok { m.Info("binpack %v %v", len(b), name) return bytes.NewReader(b) } + // 远程文件 if msg := m.Cmd("web.spide", "dev", "GET", path.Join("/share/local/", name)); msg.Result(0) != ice.ErrWarn { - bio := bytes.NewBuffer([]byte(msg.Result())) - return bio + return bytes.NewBuffer([]byte(msg.Result())) } - if strings.HasPrefix(name, "usr") { + // 源码文件 + if strings.HasPrefix(name, kit.SSH_USR) { ls := strings.Split(name, "/") - m.Cmd("web.code.git.repos", ls[1], "usr/"+ls[1]) + m.Cmd("web.code.git.repos", ls[1], path.Join(kit.SSH_USR, ls[1])) if s, e := os.Open(name); e == nil { return s } @@ -93,6 +88,8 @@ type Frame struct { source string target *ice.Context stdout io.Writer + stdin io.Reader + pipe io.Writer count int ps1 []string @@ -113,11 +110,11 @@ func (f *Frame) prompt(m *ice.Message, list ...string) *Frame { fmt.Fprintf(f.stdout, "\r") for _, v := range list { switch v { - case "count": + case kit.MDB_COUNT: fmt.Fprintf(f.stdout, "%d", f.count) - case "time": + case kit.MDB_TIME: fmt.Fprintf(f.stdout, time.Now().Format("15:04:05")) - case "target": + case TARGET: fmt.Fprintf(f.stdout, f.target.Name) default: fmt.Fprintf(f.stdout, v) @@ -135,7 +132,7 @@ func (f *Frame) printf(m *ice.Message, res string, arg ...interface{}) *Frame { } func (f *Frame) option(m *ice.Message, ls []string) []string { ln := []string{} - m.Option("cache.limit", 10) + m.Option(mdb.CACHE_LIMIT, 10) for i := 0; i < len(ls); i++ { if ls[i] == "--" { ln = append(ln, ls[i+1:]...) @@ -161,11 +158,10 @@ func (f *Frame) option(m *ice.Message, ls []string) []string { return ln } func (f *Frame) change(m *ice.Message, ls []string) []string { - if len(ls) == 1 && ls[0] == "~" { - // 模块列表 + if len(ls) == 1 && ls[0] == "~" { // 模块列表 ls = []string{"context"} - } else if len(ls) > 0 && strings.HasPrefix(ls[0], "~") { - // 切换模块 + + } else if len(ls) > 0 && strings.HasPrefix(ls[0], "~") { // 切换模块 target := ls[0][1:] if ls = ls[1:]; len(target) == 0 && len(ls) > 0 { target, ls = ls[0], ls[1:] @@ -231,21 +227,21 @@ func (f *Frame) parse(m *ice.Message, line string) string { } return "" } -func (f *Frame) scan(m *ice.Message, h, line string, r io.Reader) *Frame { - m.Option("ssh.return", func() { f.exit = true }) - f.ps1 = kit.Simple(m.Confv("prompt", "meta.PS1")) - f.ps2 = kit.Simple(m.Confv("prompt", "meta.PS2")) +func (f *Frame) scan(m *ice.Message, h, line string) *Frame { + m.Option(kit.Keycb(RETURN), func() { f.exit = true }) + f.ps1 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS1))) + f.ps2 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS2))) ps := f.ps1 - m.I, m.O = r, f.stdout - bio := bufio.NewScanner(r) m.Sleep("300ms") + m.I, m.O = f.stdin, f.stdout + bio := bufio.NewScanner(f.stdin) for f.prompt(m, ps...); bio.Scan() && !f.exit; f.prompt(m, ps...) { if h == STDIO && len(bio.Text()) == 0 { continue // 空行 } - // m.Cmdx(mdb.INSERT, SOURCE, kit.Keys(kit.MDB_HASH, h), mdb.LIST, kit.MDB_TEXT, bio.Text()) + m.Cmdx(mdb.INSERT, SOURCE, kit.Keys(kit.MDB_HASH, h), mdb.LIST, kit.MDB_TEXT, bio.Text()) f.count++ if len(bio.Text()) == 0 { @@ -284,40 +280,43 @@ func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server func (f *Frame) Start(m *ice.Message, arg ...string) bool { f.source, f.target = kit.Select(STDIO, arg, 0), m.Target() - var r io.Reader switch m.Cap(ice.CTX_STREAM, f.source) { case STDIO: // 终端交互 - r, f.stdout = os.Stdin, os.Stdout + r, w, _ := os.Pipe() + m.Go(func() { io.Copy(w, os.Stdin) }) + f.stdin, f.stdout = r, os.Stdout + f.pipe = w m.Option(ice.MSG_OPTS, ice.MSG_USERNAME) aaa.UserRoot(m) - default: + default: // 脚本文件 f.target = m.Source() if strings.HasPrefix(f.source, "/dev") { - r, f.stdout = m.I, m.O + f.stdin, f.stdout = m.I, m.O break } - buf := bytes.NewBuffer(make([]byte, 0, 4096)) + buf := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS)) defer func() { m.Echo(buf.String()) }() if s := Script(m, f.source); s != nil { - r, f.stdout = s, buf + f.stdin, f.stdout = s, buf break } + // 查找失败 return true } + // 解析脚本 if f.count = 1; f.source == STDIO { - // m.Option("_disable_log", "true") - f.count = kit.Int(m.Conf(SOURCE, "hash.stdio.meta.count")) + 1 - f.scan(m, STDIO, "", r) + f.count = kit.Int(m.Conf(SOURCE, kit.Keys("hash.stdio.meta.count"))) + 1 + f.scan(m, STDIO, "") } else { h := m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, kit.MDB_NAME, f.source) - f.scan(m, h, "", r) + f.scan(m, h, "") } return true } @@ -327,60 +326,80 @@ func (f *Frame) Close(m *ice.Message, arg ...string) bool { const ( STDIO = "stdio" + PS1 = "PS1" + PS2 = "PS2" ) const ( SOURCE = "source" TARGET = "target" PROMPT = "prompt" + PRINTF = "printf" RETURN = "return" + + SCREEN = "screen" ) func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ - SOURCE: {Name: SOURCE, Help: "加载脚本", Value: kit.Dict()}, + SOURCE: {Name: SOURCE, Help: "加载脚本", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)}, PROMPT: {Name: PROMPT, Help: "命令提示", Value: kit.Data( - "PS1", []interface{}{"\033[33;44m", "count", "[", "time", "]", "\033[5m", "target", "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"}, - "PS2", []interface{}{"count", " ", "target", "> "}, + PS1, []interface{}{"\033[33;44m", kit.MDB_COUNT, "[", kit.MDB_TIME, "]", "\033[5m", TARGET, "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"}, + PS2, []interface{}{kit.MDB_COUNT, " ", TARGET, "> "}, )}, }, Commands: map[string]*ice.Command{ - SOURCE: {Name: "source hash id auto", Help: "脚本解析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) > 0 && strings.HasSuffix(arg[0], ".shy") { + SOURCE: {Name: "source hash id limit offend auto", Help: "脚本解析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) > 0 && kit.Ext(arg[0]) == "shy" { // 解析脚本 m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...) return } - if len(arg) == 0 { - m.Option(mdb.FIELDS, "time,hash,name,count") + if len(arg) == 0 { // 脚本列表 + m.Fields(len(arg) == 0, "time,hash,name,count") m.Cmdy(mdb.SELECT, SOURCE, "", mdb.HASH) m.Sort(kit.MDB_NAME) return } - if arg[0] == STDIO { - m.Option("_control", "_page") + if m.Option(mdb.CACHE_OFFEND, kit.Select("0", arg, 3)); arg[0] == STDIO { + m.Option(mdb.CACHE_LIMIT, kit.Select("10", arg, 2)) } else { - m.Option("cache.limit", "-1") + m.Option(mdb.CACHE_LIMIT, kit.Select("-1", arg, 2)) } - m.Option(mdb.FIELDS, kit.Select("time,id,text", mdb.DETAIL, len(arg) > 1)) + + // 命令列表 + m.Fields(len(arg) == 1 || arg[1] == "", "time,id,text") m.Cmdy(mdb.SELECT, SOURCE, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:]) - m.Sort(kit.MDB_ID) }}, - TARGET: {Name: "target name", Help: "当前模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Search(arg[0], func(p *ice.Context, s *ice.Context, key string) { - f := m.Target().Server().(*Frame) - f.target = s - f.prompt(m) - }) + TARGET: {Name: "target name 执行:button", Help: "当前模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + f := m.Target().Server().(*Frame) + m.Search(arg[0]+".", func(p *ice.Context, s *ice.Context, key string) { f.target = s }) + f.prompt(m) + m.Echo(arg[0]) }}, - PROMPT: {Name: "prompt arg...", Help: "命令提示", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + PROMPT: {Name: "prompt arg 执行:button", Help: "命令提示", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { f := m.Target().Server().(*Frame) f.ps1 = arg f.prompt(m) + m.Echo(arg[0]) + }}, + PRINTF: {Name: "printf 执行:button text:textarea", Help: "输出显示", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + f := m.Target().Server().(*Frame) + f.printf(m, arg[0]) + m.Echo(arg[0]) + }}, + SCREEN: {Name: "screen 执行:button text:textarea", Help: "输出命令", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + f := m.Target().Server().(*Frame) + for _, line := range kit.Split(arg[0], "\n", "\n", "\n") { + f.printf(m, line+"\n") + fmt.Fprintf(f.pipe, line+"\n") + m.Sleep("300ms") + } + m.Echo(arg[0]) }}, RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - switch cb := m.Optionv("ssh.return").(type) { + switch cb := m.Optionv(kit.Keycb(RETURN)).(type) { case func(): cb() } diff --git a/base/ssh/service.go b/base/ssh/service.go index b9f0b58f..b8ec43cd 100644 --- a/base/ssh/service.go +++ b/base/ssh/service.go @@ -12,6 +12,7 @@ import ( ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/aaa" + "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" "github.com/shylinux/icebergs/base/tcp" @@ -22,7 +23,6 @@ import ( func _ssh_meta(conn ssh.ConnMetadata) map[string]string { return map[string]string{aaa.USERNAME: conn.User(), tcp.HOSTPORT: conn.RemoteAddr().String()} } - func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig { config := &ssh.ServerConfig{ PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { @@ -51,22 +51,20 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig { }, PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight) - m.Richs(aaa.USER, "", conn.User(), func(k string, value map[string]interface{}) { - if string(password) == kit.Format(value[aaa.PASSWORD]) { - m.Log_AUTH(tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), aaa.PASSWORD, strings.Repeat("*", len(kit.Format(value[aaa.PASSWORD])))) - err = nil // 密码登录 - } - }) + if aaa.UserLogin(m, conn.User(), string(password)) { + m.Log_AUTH(tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), aaa.PASSWORD, strings.Repeat("*", len(string(password)))) + err = nil // 密码登录 + } return &ssh.Permissions{Extensions: meta}, err }, BannerCallback: func(conn ssh.ConnMetadata) string { m.Log_IMPORT(tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) - return m.Conf(SERVICE, "meta.welcome") + return m.Conf(SERVICE, kit.Keym(WELCOME)) }, } - if key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, path.Join(os.Getenv("HOME"), m.Option("private"))))); m.Assert(err) { + if key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, path.Join(os.Getenv(cli.HOME), m.Option(PRIVATE))))); m.Assert(err) { config.AddHostKey(key) } return config @@ -91,26 +89,40 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) { } } +const ( + WELCOME = "welcome" + GOODBYE = "goodbye" + PRIVATE = "private" + AUTHKEY = "authkey" + REQUEST = "request" +) const SERVICE = "service" func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data( - "welcome", "\r\nwelcome to context world\r\n", - "goodbye", "\r\ngoodbye of context world\r\n", + WELCOME, "\r\nwelcome to context world\r\n", + GOODBYE, "\r\ngoodbye of context world\r\n", kit.MDB_SHORT, tcp.PORT, )}, }, Commands: map[string]*ice.Command{ + ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Richs(SERVICE, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + if value = kit.GetMeta(value); kit.Value(value, kit.MDB_STATUS) == tcp.OPEN { + m.Cmd(SERVICE, tcp.LISTEN, tcp.PORT, value[tcp.PORT], value) + } + }) + }}, SERVICE: {Name: "service port id auto listen prunes", Help: "服务", Action: map[string]*ice.Action{ - tcp.LISTEN: {Name: "listen port=9030 private=.ssh/id_rsa auth=.ssh/authorized_keys", Help: "监听", Hand: func(m *ice.Message, arg ...string) { + tcp.LISTEN: {Name: "listen port=9030 private=.ssh/id_rsa authkey=.ssh/authorized_keys", Help: "添加", Hand: func(m *ice.Message, arg ...string) { if m.Richs(SERVICE, "", m.Option(tcp.PORT), func(key string, value map[string]interface{}) { - kit.Value(value, "meta.status", tcp.OPEN) + kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.OPEN) }) == nil { m.Cmd(mdb.INSERT, SERVICE, "", mdb.HASH, tcp.PORT, m.Option(tcp.PORT), - "private", m.Option("private"), "auth", m.Option("auth"), kit.MDB_STATUS, tcp.OPEN, arg) - m.Cmd(SERVICE, mdb.IMPORT, kit.MDB_FILE, m.Option("auth")) + PRIVATE, m.Option(PRIVATE), AUTHKEY, m.Option(AUTHKEY), kit.MDB_STATUS, tcp.OPEN, arg) + m.Cmd(SERVICE, mdb.IMPORT, AUTHKEY, m.Option(AUTHKEY)) } m.Option(kit.Keycb(tcp.LISTEN), func(c net.Conn) { m.Go(func() { _ssh_accept(m, kit.Hashs(m.Option(tcp.PORT)), c) }) }) @@ -120,53 +132,52 @@ func init() { }}, mdb.INSERT: {Name: "insert text:textarea", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - ls := kit.Split(m.Option(kit.MDB_TEXT)) - m.Cmdy(mdb.INSERT, SERVICE, kit.Keys(kit.MDB_HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST, - kit.MDB_TYPE, ls[0], kit.MDB_NAME, ls[len(ls)-1], kit.MDB_TEXT, strings.Join(ls[1:len(ls)-1], "+")) + if ls := kit.Split(m.Option(kit.MDB_TEXT)); len(ls) > 2 { + m.Cmdy(mdb.INSERT, SERVICE, kit.Keys(kit.MDB_HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST, + kit.MDB_TYPE, ls[0], kit.MDB_NAME, ls[len(ls)-1], kit.MDB_TEXT, strings.Join(ls[1:len(ls)-1], "+")) + } }}, - mdb.EXPORT: {Name: "export file=.ssh/authorized_keys", Help: "导出", Hand: func(m *ice.Message, arg ...string) { + mdb.EXPORT: {Name: "export authkey=.ssh/authorized_keys", Help: "导出", Hand: func(m *ice.Message, arg ...string) { list := []string{} m.Cmd(mdb.SELECT, SERVICE, kit.Keys(kit.MDB_HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST).Table(func(index int, value map[string]string, head []string) { list = append(list, fmt.Sprintf("%s %s %s", value[kit.MDB_TYPE], value[kit.MDB_TEXT], value[kit.MDB_NAME])) }) if len(list) > 0 { - m.Cmdy(nfs.SAVE, path.Join(os.Getenv("HOME"), m.Option(kit.MDB_FILE)), strings.Join(list, "\n")+"\n") + m.Cmdy(nfs.SAVE, path.Join(os.Getenv(cli.HOME), m.Option(AUTHKEY)), strings.Join(list, "\n")+"\n") } }}, - mdb.IMPORT: {Name: "import file=.ssh/authorized_keys", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - p := path.Join(os.Getenv("HOME"), m.Option(kit.MDB_FILE)) - for _, pub := range strings.Split(m.Cmdx(nfs.CAT, p), "\n") { - if ls := kit.Split(pub); len(pub) > 10 { - m.Cmd(mdb.INSERT, SERVICE, kit.Keys(kit.MDB_HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST, - kit.MDB_TYPE, ls[0], kit.MDB_NAME, ls[len(ls)-1], kit.MDB_TEXT, strings.Join(ls[1:len(ls)-1], "+")) - } + mdb.IMPORT: {Name: "import authkey=.ssh/authorized_keys", Help: "导入", Hand: func(m *ice.Message, arg ...string) { + p := path.Join(os.Getenv(cli.HOME), m.Option(AUTHKEY)) + for _, pub := range strings.Split(strings.TrimSpace(m.Cmdx(nfs.CAT, p)), "\n") { + m.Cmd(SERVICE, mdb.INSERT, kit.MDB_TEXT, pub) } m.Echo(p) }}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Option(mdb.FIELDS, "time,port,status,private,authkey,count") + m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR) m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) }}, aaa.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) { u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) - m.Option("hostname", strings.Split(u.Host, ":")[0]) + m.Option(cli.HOSTNAME, strings.Split(u.Host, ":")[0]) + m.ProcessInner() - m.Option("_process", "_inner") - if buf, err := kit.Render(` -ssh {{.Option "user.name"}}@{{.Option "hostname"}} -p {{.Option "port"}} -`, m); err == nil { - m.Cmdy("web.wiki.spark", "shell", string(buf)) + if buf, err := kit.Render(`ssh -p {{.Option "port"}} {{.Option "user.name"}}@{{.Option "hostname"}}`, m); err == nil { + m.EchoScript(string(buf)) } }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) == 0 { - m.Option(mdb.FIELDS, "time,status,port,private,auth,count") + if len(arg) == 0 { // 服务列表 + m.Fields(len(arg) == 0, "time,port,status,private,authkey,count") m.Cmdy(mdb.SELECT, SERVICE, "", mdb.HASH) m.PushAction(mdb.IMPORT, mdb.INSERT, mdb.EXPORT, aaa.INVITE) return } - m.Option(mdb.FIELDS, kit.Select("time,id,type,name,text", mdb.DETAIL, len(arg) > 1)) + // 公钥列表 + m.Fields(len(arg) == 1, "time,id,type,name,text") m.Cmdy(mdb.SELECT, SERVICE, kit.Keys(kit.MDB_HASH, kit.Hashs(arg[0])), mdb.LIST, kit.MDB_ID, arg[1:]) }}, }, diff --git a/base/ssh/service_linux.go b/base/ssh/service_linux.go index 789a1877..1a10e557 100644 --- a/base/ssh/service_linux.go +++ b/base/ssh/service_linux.go @@ -10,6 +10,7 @@ import ( "unsafe" ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/tcp" kit "github.com/shylinux/toolkits" @@ -28,7 +29,7 @@ func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) shell := kit.Select("bash", os.Getenv("SHELL")) - list := []string{"PATH=" + os.Getenv("PATH")} + list := []string{cli.PATH + "=" + os.Getenv(cli.PATH)} pty, tty, err := pty.Open() if m.Warn(err != nil, err) { @@ -40,7 +41,7 @@ func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh meta[CHANNEL] = h for request := range requests { - m.Logs("request", tcp.HOSTPORT, c.RemoteAddr(), kit.MDB_TYPE, request.Type) + m.Logs(REQUEST, tcp.HOSTPORT, c.RemoteAddr(), kit.MDB_TYPE, request.Type) switch request.Type { case "pty-req": diff --git a/base/ssh/session.go b/base/ssh/session.go index 955ff982..c6bfc40d 100644 --- a/base/ssh/session.go +++ b/base/ssh/session.go @@ -1,7 +1,6 @@ package ssh import ( - "golang.org/x/crypto/ssh" "io" ice "github.com/shylinux/icebergs" @@ -9,6 +8,7 @@ import ( "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/tcp" kit "github.com/shylinux/toolkits" + "golang.org/x/crypto/ssh" ) func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, error) { diff --git a/base/ssh/ssh.go b/base/ssh/ssh.go index 19ae8fbb..246d81c3 100644 --- a/base/ssh/ssh.go +++ b/base/ssh/ssh.go @@ -13,24 +13,16 @@ var Index = &ice.Context{Name: SSH, Help: "终端模块", Commands: map[string]* m.Load() m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_NAME), STDIO) m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_TIME), m.Time()) - - m.Richs(SERVICE, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - value = kit.GetMeta(value) - m.Cmd(SERVICE, tcp.LISTEN, tcp.PORT, value[tcp.PORT], value) - }) }}, ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if _, ok := m.Target().Server().(*Frame); ok { m.Done(true) } m.Richs(CHANNEL, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - kit.Value(value, "meta.status", tcp.CLOSE) + kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.CLOSE) }) m.Richs(SESSION, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - kit.Value(value, "meta.status", tcp.CLOSE) - }) - m.Richs(CONNECT, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - kit.Value(value, "status", tcp.CLOSE) + kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.CLOSE) }) m.Richs(SOURCE, "", STDIO, func(key string, value map[string]interface{}) { diff --git a/base/ssh/ssh.shy b/base/ssh/ssh.shy index f008d912..0f756872 100644 --- a/base/ssh/ssh.shy +++ b/base/ssh/ssh.shy @@ -7,8 +7,13 @@ refer ` field "服务" ssh.service field "通道" ssh.channel - field "连接" ssh.connect field "会话" ssh.session -field "脚本" ssh.source + +field "脚本" ssh.source +field "模块" ssh.target +field "提示" ssh.prompt +field "输出" ssh.printf +field "屏显" ssh.screen + diff --git a/conf.go b/conf.go index 6fcae4e6..9c4f6a5b 100644 --- a/conf.go +++ b/conf.go @@ -73,6 +73,7 @@ const ( // MSG MSG_RESULT = "result" MSG_ALIAS = "_alias" + MSG_SCRIPT = "_script" MSG_SOURCE = "_source" MSG_TARGET = "_target" MSG_HANDLE = "_handle"