diff --git a/base/nfs/nfs.go b/base/nfs/nfs.go index 19b01dfb..0d0626e2 100644 --- a/base/nfs/nfs.go +++ b/base/nfs/nfs.go @@ -36,14 +36,14 @@ func _file_list(m *ice.Message, root string, name string, level int, deep bool, } if fs, e := ioutil.ReadDir(path.Join(root, name)); e != nil { - if f, e := os.Open(path.Join(root, name)); e == nil { + if f, e := os.Open(path.Join(root, name)); e != nil { + } else { defer f.Close() if b, e := ioutil.ReadAll(f); e == nil { m.Echo(string(b)) return } } - m.Log(ice.LOG_WARN, "%s", e) } else { for _, f := range fs { if f.Name() == "." || f.Name() == ".." { @@ -170,16 +170,18 @@ func _file_list(m *ice.Message, root string, name string, level int, deep bool, } } func _file_show(m *ice.Message, name string) { - if n := m.Cmd("file_rewrite", name).Append("to"); n != "" { - m.Logs("rewrite", "from", name, "to", n) - name = n - } + // if n := m.Cmd("file_rewrite", name).Append("to"); n != "" { + // m.Logs("rewrite", "from", name, "to", n) + // name = n + // } if strings.HasPrefix(name, "http") { m.Cmdy("web.spide", "dev", "raw", "GET", name) return } - if f, e := os.OpenFile(path.Join(m.Option(DIR_ROOT), name), os.O_RDONLY, 0640); m.Assert(e) { + if f, e := os.OpenFile(path.Join(m.Option(DIR_ROOT), name), os.O_RDONLY, 0640); os.IsNotExist(e) { + m.Cmdy("web.spide", "dev", "raw", "GET", path.Join("/share/local/", name)) + } else if e == nil { defer f.Close() if s, e := f.Stat(); m.Assert(e) { diff --git a/base/ssh/server.go b/base/ssh/server.go index 7c7194ff..f1af69e6 100644 --- a/base/ssh/server.go +++ b/base/ssh/server.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "net" "os" "os/exec" @@ -62,9 +63,37 @@ func _ssh_close(m *ice.Message, c net.Conn, channel ssh.Channel) { defer channel.Close() channel.Write([]byte(m.Conf(PUBLIC, "meta.goodbye"))) } +func _ssh_watch(m *ice.Message, meta map[string]string, input io.Reader, output io.Writer) { + m.Gos(m, func(m *ice.Message) { + r, w := io.Pipe() + bio := io.TeeReader(input, w) + m.Gos(m, func(m *ice.Message) { + i, buf := 0, make([]byte, 1024) + for { + n, e := bio.Read(buf[i:]) + if e != nil { + break + } + switch buf[i] { + case ' ': + case '\r', '\n': + cmd := strings.TrimSpace(string(buf[:i+n])) + m.Log_IMPORT("hostname", meta["hostname"], "username", meta["username"], "cmd", cmd) + i = 0 + default: + m.Debug("what %v", buf[i]) + } + if i += n; i >= 1024 { + i = 0 + } + } + }) + io.Copy(output, r) + }) +} func _ssh_reopen(m *ice.Message, c net.Conn, channel ssh.Channel) { } -func _ssh_handle(m *ice.Message, hostname string, c net.Conn, channel ssh.Channel, requests <-chan *ssh.Request) { +func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh.Channel, requests <-chan *ssh.Request) { m.Logs(CHANNEL, aaa.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) defer m.Logs("dischan", aaa.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) @@ -78,6 +107,9 @@ func _ssh_handle(m *ice.Message, hostname string, c net.Conn, channel ssh.Channe defer f.Close() h := m.Cmdx(mdb.INSERT, m.Prefix(SESSION), "", mdb.HASH, aaa.HOSTPORT, c.RemoteAddr().String(), kit.MDB_STATUS, "open", "tty", tty.Name()) + m.Richs(SESSION, "", h, func(key string, value map[string]interface{}) { + value["channel"] = channel + }) for request := range requests { m.Logs(REQUEST, aaa.HOSTPORT, c.RemoteAddr(), "type", request.Type) @@ -103,41 +135,67 @@ func _ssh_handle(m *ice.Message, hostname string, c net.Conn, channel ssh.Channe list = append(list, env.Name+"="+env.Value) case "exec": + if meta["username"] == "revert" { + n, e := channel.Write([]byte("pwd")) + n, e = channel.Write([]byte("pwd")) + n, e = channel.Write([]byte("pwd")) + n, e = channel.Write([]byte("pwd")) + n, e = channel.Write([]byte("pwd")) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + break + } _ssh_exec(m, shell, []string{"-c", string(request.Payload[4 : request.Payload[3]+4])}, list, channel, func() { channel.Close() }) case "shell": - _ssh_exec(m, shell, nil, list, f, func() { - defer m.Cmd(mdb.MODIFY, m.Prefix(SESSION), "", mdb.HASH, kit.MDB_HASH, h, kit.MDB_STATUS, "close") - _ssh_close(m, c, channel) - }) - m.Gos(m, func(m *ice.Message) { - r, w := io.Pipe() - bio := io.TeeReader(channel, w) + if m.Richs(SESSION, "", meta["username"], func(key string, value map[string]interface{}) { + ttyp := value["channel"].(ssh.Channel) + m.Gos(m, func(m *ice.Message) { io.Copy(channel, tty) }) + _ssh_watch(m, meta, channel, ttyp) + }) != nil { + break + } + + if meta["username"] == "revert" { + n, e := channel.Write([]byte("pwd")) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + m.Debug("what %v %v", n, e) + break + + } else if meta["username"] == "ssh" { + m.I, m.O = f, f + m.Render(ice.RENDER_VOID) m.Gos(m, func(m *ice.Message) { - i, buf := 0, make([]byte, 1024) - for { - n, e := bio.Read(buf[i:]) - if e != nil { - break - } - switch buf[i] { - case ' ': - case '\r', '\n': - cmd := strings.TrimSpace(string(buf[:i+n])) - m.Cmd(mdb.MODIFY, m.Prefix(SESSION), "", mdb.HASH, kit.MDB_HASH, h, "cmd", cmd) - m.Log_IMPORT(h, hostname, "cmd", cmd) - i = 0 - } - if i += n; i >= 1024 { - i = 0 - } - } + m.Cmdy(SOURCE, tty.Name()) + _ssh_close(m, c, channel) }) - io.Copy(tty, r) - }) - m.Gos(m, func(m *ice.Message) { - io.Copy(channel, tty) - }) + } else { + _ssh_exec(m, shell, nil, list, f, func() { + defer m.Cmd(mdb.MODIFY, m.Prefix(SESSION), "", mdb.HASH, kit.MDB_HASH, h, kit.MDB_STATUS, "close") + _ssh_close(m, c, channel) + }) + } + + m.Gos(m, func(m *ice.Message) { io.Copy(channel, tty) }) + _ssh_watch(m, meta, channel, tty) } request.Reply(true, nil) } @@ -172,9 +230,11 @@ func _ssh_listen(m *ice.Message, hostport string) { } hostname := sc.Permissions.Extensions["hostname"] + username := sc.Permissions.Extensions["username"] begin := time.Now() - h := m.Cmdx(mdb.INSERT, m.Prefix(CONNECT), "", mdb.HASH, aaa.HOSTPORT, c.RemoteAddr().String(), kit.MDB_STATUS, "connect", "hostname", hostname) + h := m.Cmdx(mdb.INSERT, m.Prefix(CONNECT), "", mdb.HASH, aaa.HOSTPORT, c.RemoteAddr().String(), kit.MDB_STATUS, "connect", "hostname", hostname, "username", username) defer m.Cmd(mdb.MODIFY, m.Prefix(CONNECT), "", mdb.HASH, kit.MDB_HASH, h, kit.MDB_STATUS, "close", "close_time", time.Now().Format(ice.MOD_TIME), "duration", time.Now().Sub(begin).String()) + sc.Permissions.Extensions["connhash"] = h m.Gos(m, func(m *ice.Message) { ssh.DiscardRequests(req) @@ -188,7 +248,7 @@ func _ssh_listen(m *ice.Message, hostport string) { func(channel ssh.Channel, requests <-chan *ssh.Request) { m.Gos(m, func(m *ice.Message) { - _ssh_handle(m, hostname, c, channel, requests) + _ssh_handle(m, sc.Permissions.Extensions, c, channel, requests) }) }(channel, requests) } @@ -203,23 +263,25 @@ func _ssh_config(m *ice.Message) *ssh.ServerConfig { return m.Conf(PUBLIC, "meta.welcome") }, PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { - meta, res := map[string]string{}, errors.New(ice.ErrNotAuth) - m.Richs(PUBLIC, "", kit.MDB_FOREACH, func(k string, value map[string]interface{}) { - if !strings.HasPrefix(kit.Format(value[kit.MDB_NAME]), conn.User()+"@") { - return - } - if s, e := base64.StdEncoding.DecodeString(kit.Format(value[kit.MDB_TEXT])); !m.Warn(e != nil, e) { - if pub, e := ssh.ParsePublicKey([]byte(s)); !m.Warn(e != nil) { - if bytes.Compare(pub.Marshal(), key.Marshal()) == 0 { - m.Log_AUTH(aaa.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), "publickey", value[kit.MDB_NAME]) - meta["hostname"] = kit.Format(value[kit.MDB_NAME]) - res = nil + meta, res := map[string]string{"username": conn.User()}, errors.New(ice.ErrNotAuth) + if tcp.IPIsLocal(m, strings.Split(conn.RemoteAddr().String(), ":")[0]) { + m.Log_AUTH(aaa.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), "white", conn.RemoteAddr()) + res = nil + } else { + m.Richs(PUBLIC, "", kit.MDB_FOREACH, func(k string, value map[string]interface{}) { + if !strings.HasPrefix(kit.Format(value[kit.MDB_NAME]), conn.User()+"@") { + return + } + if s, e := base64.StdEncoding.DecodeString(kit.Format(value[kit.MDB_TEXT])); !m.Warn(e != nil, e) { + if pub, e := ssh.ParsePublicKey([]byte(s)); !m.Warn(e != nil) { + if bytes.Compare(pub.Marshal(), key.Marshal()) == 0 { + m.Log_AUTH(aaa.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), "publickey", value[kit.MDB_NAME]) + meta["hostname"] = kit.Format(value[kit.MDB_NAME]) + res = nil + } } } - } - }) - if tcp.IPIsLocal(m, strings.Split(conn.RemoteAddr().String(), ":")[0]) { - res = nil + }) } return &ssh.Permissions{Extensions: meta}, res }, @@ -284,7 +346,7 @@ func init() { mdb.FIELDS, "time,hash,hostport,status", )}, CONNECT: {Name: CONNECT, Help: "连接", Value: kit.Data( - mdb.FIELDS, "time,hash,hostport,status,duration,close_time,hostname", + mdb.FIELDS, "time,hash,hostport,status,duration,close_time,hostname,username", )}, SESSION: {Name: SESSION, Help: "会话", Value: kit.Data( mdb.FIELDS, "time,hash,hostport,status,tty,cmd", @@ -369,7 +431,7 @@ func init() { m.Cmdy(mdb.SELECT, m.Prefix(SESSION), "", mdb.HASH, kit.MDB_HASH, arg) }}, - DIAL: {Name: "dial hash auto 登录 cmd:textarea=pwd", Help: "连接", Action: map[string]*ice.Action{ + DIAL: {Name: "dial hash auto 受控 登录 cmd:textarea=pwd", Help: "连接", Action: map[string]*ice.Action{ mdb.CREATE: {Name: "create", Help: "登录", List: kit.List( kit.MDB_INPUT, "text", kit.MDB_NAME, aaa.USERNAME, kit.MDB_VALUE, "shy", kit.MDB_INPUT, "text", kit.MDB_NAME, aaa.HOSTPORT, kit.MDB_VALUE, "shylinux.com:22", @@ -388,6 +450,33 @@ func init() { )) m.Echo(h) }}, + "revert": {Name: "revert", Help: "受控", List: kit.List( + kit.MDB_INPUT, "text", kit.MDB_NAME, aaa.HOSTPORT, kit.MDB_VALUE, "192.168.0.105:9030", + ), Hand: func(m *ice.Message, arg ...string) { + for i := 0; i < len(arg); i += 2 { + m.Option(arg[i], arg[i+1]) + } + + connect, e := _ssh_dial(m, "revert", m.Option(aaa.HOSTPORT)) + m.Assert(e) + + h := m.Rich(DIAL, "", kit.Dict( + aaa.USERNAME, "revert", + aaa.HOSTPORT, m.Option(aaa.HOSTPORT), + CONNECT, connect, + )) + + session, e := connect.NewSession() + m.Assert(e) + + r, w := io.Pipe() + session.Stdout = w + + _ssh_watch(m, map[string]string{}, r, ioutil.Discard) + + session.Start("bash") + m.Echo(h) + }}, mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(mdb.DELETE, m.Prefix(DIAL), "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) diff --git a/base/ssh/ssh.go b/base/ssh/ssh.go index add3acfd..4a23060d 100644 --- a/base/ssh/ssh.go +++ b/base/ssh/ssh.go @@ -67,6 +67,30 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) { msg.Append(ice.MSG_OUTPUT, ice.RENDER_OUTPUT) } +func _ssh_script(m *ice.Message, name string) io.Reader { + if strings.Contains(m.Option("_script"), "/") { + name = path.Join(path.Dir(m.Option("_script")), name) + } + m.Option("_script", name) + + if s, e := os.Open(name); e == nil { + return s + } + + 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 + } + + if strings.HasPrefix(name, "usr") { + ls := strings.Split(name, "/") + m.Cmd("web.code.git.repos", ls[1], "usr/"+ls[1]) + if s, e := os.Open(name); e == nil { + return s + } + } + return nil +} func (f *Frame) history(m *ice.Message, line string) string { favor := m.Conf(SOURCE, kit.Keys(kit.MDB_META, web.FAVOR)) if strings.HasPrefix(strings.TrimSpace(line), "!!") { @@ -104,7 +128,7 @@ func (f *Frame) printf(m *ice.Message, res string, arg ...interface{}) *Frame { return f } func (f *Frame) prompt(m *ice.Message, list ...string) *Frame { - if f.stdout != os.Stdout { + if f.source != STDIO { return f } if len(list) == 0 { @@ -292,6 +316,13 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { m.Option(ice.MSG_USERZONE, "boot") aaa.UserRoot(m) default: + if strings.HasPrefix(arg[0], "/dev") { + // 脚本解析 + r, f.stdout = m.I, m.O + f.source, f.target = STDIO, m.Source() + m.Cap(ice.CTX_STREAM, STDIO) + break + } if b, ok := ice.BinPack[arg[0]]; ok { m.Debug("binpack %v %v", arg[0], len(b)) buf := bytes.NewBuffer(make([]byte, 0, 4096)) @@ -304,27 +335,15 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { f.target = m.Source() break } - s, e := os.Open(arg[0]) - if os.IsNotExist(e) && strings.HasPrefix(arg[0], "usr") { - ls := strings.Split(arg[0], "/") - m.Cmd("web.code.git.repos", ls[1], "usr/"+ls[1]) - s, e = os.Open(arg[0]) - } - if !m.Warn(e != nil, "%s", e) { - defer s.Close() + s := _ssh_script(m, arg[0]) + buf := bytes.NewBuffer(make([]byte, 0, 4096)) + defer func() { m.Echo(buf.String()) }() - buf := bytes.NewBuffer(make([]byte, 0, 4096)) - defer func() { m.Echo(buf.String()) }() - - // 脚本解析 - f.source = arg[0] - r, f.stdout = s, buf - m.Cap(ice.CTX_STREAM, arg[0]) - f.target = m.Source() - break - } - return true + // 脚本解析 + r, f.stdout = s, buf + f.source, f.target = arg[0], m.Source() + m.Cap(ice.CTX_STREAM, arg[0]) } f.scan(m, kit.Select(STDIO, arg, 0), "", r) @@ -371,10 +390,6 @@ var Index = &ice.Context{Name: "ssh", Help: "终端模块", }}, SOURCE: {Name: "source file", Help: "脚本解析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if _, e := os.Stat(arg[0]); e != nil { - arg[0] = path.Join(path.Dir(m.Option("_script")), arg[0]) - } - m.Option("_script", arg[0]) m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...) }}, TARGET: {Name: "target name", Help: "当前模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/base/web/spide.go b/base/web/spide.go index 0e42de4e..ea82ac30 100644 --- a/base/web/spide.go +++ b/base/web/spide.go @@ -203,10 +203,10 @@ func init() { // 请求地址 uri, arg := arg[0], arg[1:] - if n := m.Cmd("spide_rewrite", uri).Append("to"); n != "" && n != uri { - m.Logs("rewrite", "from", uri, "to", n) - uri = n - } + // if n := m.Cmd("spide_rewrite", uri).Append("to"); n != "" && n != uri { + // m.Logs("rewrite", "from", uri, "to", n) + // uri = n + // } // 渲染引擎 head := map[string]string{} @@ -315,7 +315,7 @@ func init() { // 检查结果 m.Cost("%s %s: %s", res.Status, res.Header.Get(ContentLength), res.Header.Get(ContentType)) - if m.Warn(res.StatusCode != http.StatusOK, "%s", res.Status) { + if m.Warn(res.StatusCode != http.StatusOK, res.Status) { m.Set(ice.MSG_RESULT) // return } diff --git a/core/wiki/wiki.go b/core/wiki/wiki.go index 306d1b67..40646c40 100644 --- a/core/wiki/wiki.go +++ b/core/wiki/wiki.go @@ -40,18 +40,19 @@ func _wiki_upload(m *ice.Message, cmd string) { func reply(m *ice.Message, cmd string, arg ...string) bool { // 文件列表 m.Option(nfs.DIR_ROOT, m.Conf(cmd, "meta.path")) - m.Option(nfs.DIR_REG, m.Conf(cmd, "meta.regs")) - m.Cmdy(nfs.DIR, kit.Select("./", arg, 0)) - m.Sort("time", "time_r") - if len(arg) == 0 || strings.HasSuffix(arg[0], "/") { m.Option("_display", "table") - if m.Option(nfs.DIR_DEEP) == "true" { - return true - } + // if m.Option(nfs.DIR_DEEP) == "true" { + // return true + // } + // 目录列表 - m.Option(nfs.DIR_REG, "") - m.Option(nfs.DIR_TYPE, "dir") + m.Option(nfs.DIR_TYPE, nfs.DIR) + m.Cmdy(nfs.DIR, kit.Select("./", arg, 0)) + + // 文件列表 + m.Option(nfs.DIR_TYPE, nfs.FILE) + m.Option(nfs.DIR_REG, m.Conf(cmd, "meta.regs")) m.Cmdy(nfs.DIR, kit.Select("./", arg, 0)) return true }