1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-26 09:34:05 +08:00

opt ssh.scripts

This commit is contained in:
shylinux 2021-06-01 06:58:45 +08:00
parent c714a7be57
commit 545ec26ea8
10 changed files with 165 additions and 125 deletions

View File

@ -170,9 +170,9 @@ func _list_select(m *ice.Message, prefix, chain, field, value string) {
} }
} }
}) })
if m.Option(FIELDS) != DETAIL { // if m.Option(FIELDS) != DETAIL {
m.SortIntR(kit.MDB_ID) // m.SortIntR(kit.MDB_ID)
} // }
} }
func _list_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) { 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{}) { m.Grows(prefix, chain, field, value, func(index int, val map[string]interface{}) {
@ -415,6 +415,7 @@ const (
CACHE_LIMIT = "cache.limit" CACHE_LIMIT = "cache.limit"
CACHE_FIELD = "cache.field" CACHE_FIELD = "cache.field"
CACHE_VALUE = "cache.value" CACHE_VALUE = "cache.value"
CACHE_OFFEND = "cache.offend"
CACHE_CLEAR_ON_EXIT = "cache.clear.on.exit" CACHE_CLEAR_ON_EXIT = "cache.clear.on.exit"
) )

View File

@ -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) { func _ssh_close(m *ice.Message, c net.Conn, channel ssh.Channel) {
defer channel.Close() 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) { 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() 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)) 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) { 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) m.Cmdy(mdb.PRUNES, CHANNEL, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE)
}}, }},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 { // 通道列表
m.Option(mdb.FIELDS, "time,hash,status,username,hostname,hostport,tty,count") m.Fields(len(arg) == 0, "time,hash,status,username,hostport,tty,count")
if m.Cmdy(mdb.SELECT, CHANNEL, "", mdb.HASH); len(arg) == 0 { if m.Cmdy(mdb.SELECT, CHANNEL, "", mdb.HASH); len(arg) == 0 {
m.Table(func(index int, value map[string]string, head []string) { m.Table(func(index int, value map[string]string, head []string) {
m.PushButton(kit.Select("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) m.PushButton(kit.Select("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE))
@ -90,7 +92,8 @@ func init() {
return 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:]) m.Cmdy(mdb.SELECT, CHANNEL, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:])
}}, }},
}, },

View File

@ -172,6 +172,13 @@ func init() {
CONNECT: {Name: CONNECT, Help: "连接", Value: kit.Data()}, CONNECT: {Name: CONNECT, Help: "连接", Value: kit.Data()},
}, },
Commands: map[string]*ice.Command{ 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{ 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) { 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...) _ssh_open(m, arg...)

View File

@ -21,17 +21,10 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) {
switch arg := kit.Simple(args...); cmd { switch arg := kit.Simple(args...); cmd {
case ice.RENDER_VOID: case ice.RENDER_VOID:
case ice.RENDER_RESULT: case ice.RENDER_RESULT:
fmt.Fprint(msg.O, msg.Result()) if len(arg) > 0 {
msg.Resultv(arg)
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)
} }
fmt.Fprint(msg.O, msg.Result())
default: default:
// 转换结果 // 转换结果
@ -39,7 +32,6 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) {
if res == "" { if res == "" {
res = msg.Table().Result() res = msg.Table().Result()
} }
args = append(args, "length:", len(res))
// 输出结果 // 输出结果
if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, "\n") { 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 { func Script(m *ice.Message, name string) io.Reader {
if strings.Contains(m.Option("_script"), "/") { if strings.Contains(m.Option(ice.MSG_SCRIPT), "/") {
name = path.Join(path.Dir(m.Option("_script")), name) 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)) back := kit.Split(m.Option(nfs.DIR_ROOT))
for i := len(back) - 1; i >= 0; i-- { for i := len(back) - 1; i >= 0; i-- {
if s, e := os.Open(path.Join(path.Join(back[:i]...), name)); e == nil { 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] { switch strings.Split(name, "/")[0] {
case "etc", "var": case kit.SSH_ETC, kit.SSH_VAR:
m.Warn(true, ice.ErrNotFound) m.Warn(true, ice.ErrNotFound)
return nil return nil
} }
// 打包文件
if b, ok := ice.BinPack["/"+name]; ok { if b, ok := ice.BinPack["/"+name]; ok {
m.Info("binpack %v %v", len(b), name) m.Info("binpack %v %v", len(b), name)
return bytes.NewReader(b) return bytes.NewReader(b)
} }
// 远程文件
if msg := m.Cmd("web.spide", "dev", "GET", path.Join("/share/local/", name)); msg.Result(0) != ice.ErrWarn { 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 bytes.NewBuffer([]byte(msg.Result()))
return bio
} }
if strings.HasPrefix(name, "usr") { // 源码文件
if strings.HasPrefix(name, kit.SSH_USR) {
ls := strings.Split(name, "/") 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 { if s, e := os.Open(name); e == nil {
return s return s
} }
@ -93,6 +88,8 @@ type Frame struct {
source string source string
target *ice.Context target *ice.Context
stdout io.Writer stdout io.Writer
stdin io.Reader
pipe io.Writer
count int count int
ps1 []string ps1 []string
@ -113,11 +110,11 @@ func (f *Frame) prompt(m *ice.Message, list ...string) *Frame {
fmt.Fprintf(f.stdout, "\r") fmt.Fprintf(f.stdout, "\r")
for _, v := range list { for _, v := range list {
switch v { switch v {
case "count": case kit.MDB_COUNT:
fmt.Fprintf(f.stdout, "%d", f.count) fmt.Fprintf(f.stdout, "%d", f.count)
case "time": case kit.MDB_TIME:
fmt.Fprintf(f.stdout, time.Now().Format("15:04:05")) fmt.Fprintf(f.stdout, time.Now().Format("15:04:05"))
case "target": case TARGET:
fmt.Fprintf(f.stdout, f.target.Name) fmt.Fprintf(f.stdout, f.target.Name)
default: default:
fmt.Fprintf(f.stdout, v) 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 { func (f *Frame) option(m *ice.Message, ls []string) []string {
ln := []string{} ln := []string{}
m.Option("cache.limit", 10) m.Option(mdb.CACHE_LIMIT, 10)
for i := 0; i < len(ls); i++ { for i := 0; i < len(ls); i++ {
if ls[i] == "--" { if ls[i] == "--" {
ln = append(ln, ls[i+1:]...) ln = append(ln, ls[i+1:]...)
@ -161,11 +158,10 @@ func (f *Frame) option(m *ice.Message, ls []string) []string {
return ln return ln
} }
func (f *Frame) change(m *ice.Message, ls []string) []string { 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"} 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:] target := ls[0][1:]
if ls = ls[1:]; len(target) == 0 && len(ls) > 0 { if ls = ls[1:]; len(target) == 0 && len(ls) > 0 {
target, ls = ls[0], ls[1:] target, ls = ls[0], ls[1:]
@ -231,21 +227,21 @@ func (f *Frame) parse(m *ice.Message, line string) string {
} }
return "" return ""
} }
func (f *Frame) scan(m *ice.Message, h, line string, r io.Reader) *Frame { func (f *Frame) scan(m *ice.Message, h, line string) *Frame {
m.Option("ssh.return", func() { f.exit = true }) m.Option(kit.Keycb(RETURN), func() { f.exit = true })
f.ps1 = kit.Simple(m.Confv("prompt", "meta.PS1")) f.ps1 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS1)))
f.ps2 = kit.Simple(m.Confv("prompt", "meta.PS2")) f.ps2 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS2)))
ps := f.ps1 ps := f.ps1
m.I, m.O = r, f.stdout
bio := bufio.NewScanner(r)
m.Sleep("300ms") 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...) { for f.prompt(m, ps...); bio.Scan() && !f.exit; f.prompt(m, ps...) {
if h == STDIO && len(bio.Text()) == 0 { if h == STDIO && len(bio.Text()) == 0 {
continue // 空行 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++ f.count++
if len(bio.Text()) == 0 { 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 { func (f *Frame) Start(m *ice.Message, arg ...string) bool {
f.source, f.target = kit.Select(STDIO, arg, 0), m.Target() f.source, f.target = kit.Select(STDIO, arg, 0), m.Target()
var r io.Reader
switch m.Cap(ice.CTX_STREAM, f.source) { switch m.Cap(ice.CTX_STREAM, f.source) {
case STDIO: // 终端交互 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) m.Option(ice.MSG_OPTS, ice.MSG_USERNAME)
aaa.UserRoot(m) aaa.UserRoot(m)
default: default: // 脚本文件
f.target = m.Source() f.target = m.Source()
if strings.HasPrefix(f.source, "/dev") { if strings.HasPrefix(f.source, "/dev") {
r, f.stdout = m.I, m.O f.stdin, f.stdout = m.I, m.O
break break
} }
buf := bytes.NewBuffer(make([]byte, 0, 4096)) buf := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
defer func() { m.Echo(buf.String()) }() defer func() { m.Echo(buf.String()) }()
if s := Script(m, f.source); s != nil { if s := Script(m, f.source); s != nil {
r, f.stdout = s, buf f.stdin, f.stdout = s, buf
break break
} }
// 查找失败
return true return true
} }
// 解析脚本
if f.count = 1; f.source == STDIO { if f.count = 1; f.source == STDIO {
// m.Option("_disable_log", "true") f.count = kit.Int(m.Conf(SOURCE, kit.Keys("hash.stdio.meta.count"))) + 1
f.count = kit.Int(m.Conf(SOURCE, "hash.stdio.meta.count")) + 1 f.scan(m, STDIO, "")
f.scan(m, STDIO, "", r)
} else { } else {
h := m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, kit.MDB_NAME, f.source) h := m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, kit.MDB_NAME, f.source)
f.scan(m, h, "", r) f.scan(m, h, "")
} }
return true return true
} }
@ -327,60 +326,80 @@ func (f *Frame) Close(m *ice.Message, arg ...string) bool {
const ( const (
STDIO = "stdio" STDIO = "stdio"
PS1 = "PS1"
PS2 = "PS2"
) )
const ( const (
SOURCE = "source" SOURCE = "source"
TARGET = "target" TARGET = "target"
PROMPT = "prompt" PROMPT = "prompt"
PRINTF = "printf"
RETURN = "return" RETURN = "return"
SCREEN = "screen"
) )
func init() { func init() {
Index.Merge(&ice.Context{ Index.Merge(&ice.Context{
Configs: map[string]*ice.Config{ 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( 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"}, 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{}{"count", " ", "target", "> "}, PS2, []interface{}{kit.MDB_COUNT, " ", TARGET, "> "},
)}, )},
}, },
Commands: map[string]*ice.Command{ Commands: map[string]*ice.Command{
SOURCE: {Name: "source hash id auto", Help: "脚本解析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { 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 && strings.HasSuffix(arg[0], ".shy") { if len(arg) > 0 && kit.Ext(arg[0]) == "shy" { // 解析脚本
m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...) m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...)
return return
} }
if len(arg) == 0 { if len(arg) == 0 { // 脚本列表
m.Option(mdb.FIELDS, "time,hash,name,count") m.Fields(len(arg) == 0, "time,hash,name,count")
m.Cmdy(mdb.SELECT, SOURCE, "", mdb.HASH) m.Cmdy(mdb.SELECT, SOURCE, "", mdb.HASH)
m.Sort(kit.MDB_NAME) m.Sort(kit.MDB_NAME)
return return
} }
if arg[0] == STDIO { if m.Option(mdb.CACHE_OFFEND, kit.Select("0", arg, 3)); arg[0] == STDIO {
m.Option("_control", "_page") m.Option(mdb.CACHE_LIMIT, kit.Select("10", arg, 2))
} else { } 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.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) { TARGET: {Name: "target name 执行:button", 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 := m.Target().Server().(*Frame)
f.target = s m.Search(arg[0]+".", func(p *ice.Context, s *ice.Context, key string) { f.target = s })
f.prompt(m) 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 := m.Target().Server().(*Frame)
f.ps1 = arg f.ps1 = arg
f.prompt(m) 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) { 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(): case func():
cb() cb()
} }

View File

@ -12,6 +12,7 @@ import (
ice "github.com/shylinux/icebergs" ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/aaa"
"github.com/shylinux/icebergs/base/cli"
"github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/nfs" "github.com/shylinux/icebergs/base/nfs"
"github.com/shylinux/icebergs/base/tcp" "github.com/shylinux/icebergs/base/tcp"
@ -22,7 +23,6 @@ import (
func _ssh_meta(conn ssh.ConnMetadata) map[string]string { func _ssh_meta(conn ssh.ConnMetadata) map[string]string {
return map[string]string{aaa.USERNAME: conn.User(), tcp.HOSTPORT: conn.RemoteAddr().String()} return map[string]string{aaa.USERNAME: conn.User(), tcp.HOSTPORT: conn.RemoteAddr().String()}
} }
func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig { func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig {
config := &ssh.ServerConfig{ config := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { 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) { PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight) meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight)
m.Richs(aaa.USER, "", conn.User(), func(k string, value map[string]interface{}) { if aaa.UserLogin(m, conn.User(), string(password)) {
if string(password) == kit.Format(value[aaa.PASSWORD]) { m.Log_AUTH(tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), aaa.PASSWORD, strings.Repeat("*", len(string(password))))
m.Log_AUTH(tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), aaa.PASSWORD, strings.Repeat("*", len(kit.Format(value[aaa.PASSWORD]))))
err = nil // 密码登录 err = nil // 密码登录
} }
})
return &ssh.Permissions{Extensions: meta}, err return &ssh.Permissions{Extensions: meta}, err
}, },
BannerCallback: func(conn ssh.ConnMetadata) string { BannerCallback: func(conn ssh.ConnMetadata) string {
m.Log_IMPORT(tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) 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) config.AddHostKey(key)
} }
return config 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" const SERVICE = "service"
func init() { func init() {
Index.Merge(&ice.Context{ Index.Merge(&ice.Context{
Configs: map[string]*ice.Config{ Configs: map[string]*ice.Config{
SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data( SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data(
"welcome", "\r\nwelcome to context world\r\n", WELCOME, "\r\nwelcome to context world\r\n",
"goodbye", "\r\ngoodbye of context world\r\n", GOODBYE, "\r\ngoodbye of context world\r\n",
kit.MDB_SHORT, tcp.PORT, kit.MDB_SHORT, tcp.PORT,
)}, )},
}, },
Commands: map[string]*ice.Command{ 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{ 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{}) { 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 { }) == nil {
m.Cmd(mdb.INSERT, SERVICE, "", mdb.HASH, tcp.PORT, m.Option(tcp.PORT), 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) PRIVATE, m.Option(PRIVATE), AUTHKEY, m.Option(AUTHKEY), kit.MDB_STATUS, tcp.OPEN, arg)
m.Cmd(SERVICE, mdb.IMPORT, kit.MDB_FILE, m.Option("auth")) 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) }) }) 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) { mdb.INSERT: {Name: "insert text:textarea", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
ls := kit.Split(m.Option(kit.MDB_TEXT)) 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, 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], "+")) 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{} 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) { 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])) list = append(list, fmt.Sprintf("%s %s %s", value[kit.MDB_TYPE], value[kit.MDB_TEXT], value[kit.MDB_NAME]))
}) })
if len(list) > 0 { 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) { mdb.IMPORT: {Name: "import authkey=.ssh/authorized_keys", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
p := path.Join(os.Getenv("HOME"), m.Option(kit.MDB_FILE)) p := path.Join(os.Getenv(cli.HOME), m.Option(AUTHKEY))
for _, pub := range strings.Split(m.Cmdx(nfs.CAT, p), "\n") { for _, pub := range strings.Split(strings.TrimSpace(m.Cmdx(nfs.CAT, p)), "\n") {
if ls := kit.Split(pub); len(pub) > 10 { m.Cmd(SERVICE, mdb.INSERT, kit.MDB_TEXT, pub)
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], "+"))
}
} }
m.Echo(p) m.Echo(p)
}}, }},
mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { 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) m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE)
}}, }},
aaa.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) { aaa.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) 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 -p {{.Option "port"}} {{.Option "user.name"}}@{{.Option "hostname"}}`, m); err == nil {
if buf, err := kit.Render(` m.EchoScript(string(buf))
ssh {{.Option "user.name"}}@{{.Option "hostname"}} -p {{.Option "port"}}
`, m); err == nil {
m.Cmdy("web.wiki.spark", "shell", string(buf))
} }
}}, }},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 { // 服务列表
m.Option(mdb.FIELDS, "time,status,port,private,auth,count") m.Fields(len(arg) == 0, "time,port,status,private,authkey,count")
m.Cmdy(mdb.SELECT, SERVICE, "", mdb.HASH) m.Cmdy(mdb.SELECT, SERVICE, "", mdb.HASH)
m.PushAction(mdb.IMPORT, mdb.INSERT, mdb.EXPORT, aaa.INVITE) m.PushAction(mdb.IMPORT, mdb.INSERT, mdb.EXPORT, aaa.INVITE)
return 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:]) m.Cmdy(mdb.SELECT, SERVICE, kit.Keys(kit.MDB_HASH, kit.Hashs(arg[0])), mdb.LIST, kit.MDB_ID, arg[1:])
}}, }},
}, },

View File

@ -10,6 +10,7 @@ import (
"unsafe" "unsafe"
ice "github.com/shylinux/icebergs" ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/cli"
"github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/tcp" "github.com/shylinux/icebergs/base/tcp"
kit "github.com/shylinux/toolkits" 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()) defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr())
shell := kit.Select("bash", os.Getenv("SHELL")) 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() pty, tty, err := pty.Open()
if m.Warn(err != nil, err) { 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 meta[CHANNEL] = h
for request := range requests { 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 { switch request.Type {
case "pty-req": case "pty-req":

View File

@ -1,7 +1,6 @@
package ssh package ssh
import ( import (
"golang.org/x/crypto/ssh"
"io" "io"
ice "github.com/shylinux/icebergs" ice "github.com/shylinux/icebergs"
@ -9,6 +8,7 @@ import (
"github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/tcp" "github.com/shylinux/icebergs/base/tcp"
kit "github.com/shylinux/toolkits" kit "github.com/shylinux/toolkits"
"golang.org/x/crypto/ssh"
) )
func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, error) { func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, error) {

View File

@ -13,24 +13,16 @@ var Index = &ice.Context{Name: SSH, Help: "终端模块", Commands: map[string]*
m.Load() 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_NAME), STDIO)
m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_TIME), m.Time()) 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) { ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if _, ok := m.Target().Server().(*Frame); ok { if _, ok := m.Target().Server().(*Frame); ok {
m.Done(true) m.Done(true)
} }
m.Richs(CHANNEL, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { 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{}) { m.Richs(SESSION, "", 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(CONNECT, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
kit.Value(value, "status", tcp.CLOSE)
}) })
m.Richs(SOURCE, "", STDIO, func(key string, value map[string]interface{}) { m.Richs(SOURCE, "", STDIO, func(key string, value map[string]interface{}) {

View File

@ -7,8 +7,13 @@ refer `
field "服务" ssh.service field "服务" ssh.service
field "通道" ssh.channel field "通道" ssh.channel
field "连接" ssh.connect field "连接" ssh.connect
field "会话" ssh.session field "会话" ssh.session
field "脚本" ssh.source
field "脚本" ssh.source
field "模块" ssh.target
field "提示" ssh.prompt
field "输出" ssh.printf
field "屏显" ssh.screen

View File

@ -73,6 +73,7 @@ const ( // MSG
MSG_RESULT = "result" MSG_RESULT = "result"
MSG_ALIAS = "_alias" MSG_ALIAS = "_alias"
MSG_SCRIPT = "_script"
MSG_SOURCE = "_source" MSG_SOURCE = "_source"
MSG_TARGET = "_target" MSG_TARGET = "_target"
MSG_HANDLE = "_handle" MSG_HANDLE = "_handle"