From bdc21c12070dc1f4c6a7987728e57c6b9ac32b21 Mon Sep 17 00:00:00 2001 From: harveyshao Date: Sat, 30 Apr 2022 15:15:11 +0800 Subject: [PATCH] add oauth --- base/aaa/role.go | 2 +- base/aaa/user.go | 1 + base/cli/runtime.go | 11 +++++--- base/ctx/command.go | 5 ++++ base/mdb/hash.go | 9 ++++--- base/mdb/mdb.go | 2 ++ base/web/cache.go | 2 +- base/web/serve.go | 1 + base/web/space.go | 6 ++++- base/web/spide.go | 1 + conf.go | 2 ++ core/chat/action.go | 4 +-- core/chat/cmd.go | 6 +++-- core/chat/header.go | 8 ++---- core/chat/oauth.go | 66 +++++++++++++++++++++++++++++++++++++++++++++ core/chat/pod.go | 7 +++-- core/wiki/field.go | 3 +++ core/wiki/word.go | 4 +++ go.sum | 2 ++ option.go | 13 +++++++-- render.go | 10 +++---- 21 files changed, 135 insertions(+), 30 deletions(-) create mode 100644 core/chat/oauth.go diff --git a/base/aaa/role.go b/base/aaa/role.go index aef70315..84db5da7 100644 --- a/base/aaa/role.go +++ b/base/aaa/role.go @@ -21,7 +21,7 @@ func _role_list(m *ice.Message, userrole string) { }) } func _role_chain(arg ...string) string { - return kit.ReplaceAll(kit.Keys(arg), ice.PS, ice.PT) + return kit.ReplaceAll(kit.ReplaceAll(kit.Keys(arg), ice.PS, ice.PT), "..", ".") } func _role_black(m *ice.Message, userrole, chain string) { m.Richs(ROLE, nil, userrole, func(key string, value map[string]interface{}) { diff --git a/base/aaa/user.go b/base/aaa/user.go index 97455826..9ab4bbcc 100644 --- a/base/aaa/user.go +++ b/base/aaa/user.go @@ -52,6 +52,7 @@ func UserRoot(m *ice.Message, arg ...string) *ice.Message { // password username userrole := m.Option(ice.MSG_USERROLE, kit.Select(ROOT, arg, 2)) if len(arg) > 0 { _user_create(m, userrole, username, kit.Select("", arg, 0)) + ice.Info.UserName = username } return m } diff --git a/base/cli/runtime.go b/base/cli/runtime.go index c1226e2b..6406b9ff 100644 --- a/base/cli/runtime.go +++ b/base/cli/runtime.go @@ -118,12 +118,15 @@ const ( CTX_DEV = "ctx_dev" CTX_OPS = "ctx_ops" CTX_ARG = "ctx_arg" + CTX_POD = "ctx_pod" CTX_PID = "ctx_pid" CTX_LOG = "ctx_log" CTX_USER = "ctx_user" CTX_SHARE = "ctx_share" CTX_RIVER = "ctx_river" + + MAKE_DOMAIN = "make.domain" ) const ( HOSTNAME = "hostname" @@ -204,11 +207,11 @@ func init() { } m.Sort(nfs.PATH) }}, - "make.domain": {Name: "make.domain", Help: "接口命令", Hand: func(m *ice.Message, arg ...string) { - if os.Getenv("ctx_dev") == "" || os.Getenv("ctx_pod") == "" { - m.Echo(m.Conf(RUNTIME, "make.domain")) + MAKE_DOMAIN: {Name: "make.domain", Help: "编译主机", Hand: func(m *ice.Message, arg ...string) { + if os.Getenv(CTX_DEV) == "" || os.Getenv(CTX_POD) == "" { + m.Echo(m.Conf(RUNTIME, MAKE_DOMAIN)) } else { - m.Echo(kit.MergePOD(os.Getenv("ctx_dev"), os.Getenv("ctx_pod"))) + m.Echo(kit.MergePOD(os.Getenv(CTX_DEV), os.Getenv(CTX_POD))) } }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/base/ctx/command.go b/base/ctx/command.go index b1773083..6fc953f7 100644 --- a/base/ctx/command.go +++ b/base/ctx/command.go @@ -4,6 +4,7 @@ import ( "strings" ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/mdb" kit "shylinux.com/x/toolkits" ) @@ -80,6 +81,10 @@ const COMMAND = "command" func init() { Index.Merge(&ice.Context{Commands: map[string]*ice.Command{ COMMAND: {Name: "command key auto", Help: "命令", Action: map[string]*ice.Action{ + ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { + m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, m.Prefix(COMMAND)) + m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, COMMAND) + }}, mdb.SEARCH: {Name: "search type name text", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { if arg[0] == m.CommandKey() || len(arg) > 1 && arg[1] != "" { _command_search(m, arg[0], kit.Select("", arg, 1), kit.Select("", arg, 2)) diff --git a/base/mdb/hash.go b/base/mdb/hash.go index b1c07b58..efce20f0 100644 --- a/base/mdb/hash.go +++ b/base/mdb/hash.go @@ -151,10 +151,10 @@ func AutoConfig(args ...interface{}) *ice.Action { } func HashAction(args ...interface{}) map[string]*ice.Action { _key := func(m *ice.Message) string { - if m.Config(HASH) == "uniq" { + if m.Config(HASH) == UNIQ { return HASH } - if m.Config(SHORT) == "uniq" { + if m.Config(SHORT) == UNIQ { return HASH } return kit.Select(HASH, m.Config(SHORT)) @@ -198,6 +198,9 @@ func HashActionStatus(args ...interface{}) map[string]*ice.Action { }} return list } +func HashCreate(m *ice.Message, arg ...interface{}) *ice.Message { + return m.Cmd(INSERT, m.PrefixKey(), "", HASH, kit.Simple(arg...)) +} func HashSelect(m *ice.Message, arg ...string) *ice.Message { m.Fields(len(arg), m.Config(FIELD)) m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg) @@ -207,7 +210,7 @@ func HashSelect(m *ice.Message, arg ...string) *ice.Message { } func HashPrunes(m *ice.Message, cb func(map[string]string) bool) *ice.Message { _key := func(m *ice.Message) string { - if m.Config(HASH) == "uniq" { + if m.Config(HASH) == UNIQ { return HASH } return kit.Select(HASH, m.Config(SHORT)) diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index ec8eca9f..86380399 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -62,6 +62,8 @@ const ( FOREACH = "*" RANDOMS = "%" + + UNIQ = kit.MDB_UNIQ ) const ( DETAIL = "detail" diff --git a/base/web/cache.go b/base/web/cache.go index 5c8beac2..ad72a745 100644 --- a/base/web/cache.go +++ b/base/web/cache.go @@ -80,7 +80,7 @@ func _cache_upload(m *ice.Message, r *http.Request) (kind, name, file, size stri func _cache_download(m *ice.Message, r *http.Response) (file, size string) { defer r.Body.Close() - if f, p, e := kit.Create(path.Join(ice.VAR_TMP, kit.Hashs("uniq"))); m.Assert(e) { + if f, p, e := kit.Create(path.Join(ice.VAR_TMP, kit.Hashs(mdb.UNIQ))); m.Assert(e) { step, total := 0, kit.Int(kit.Select("1", r.Header.Get(ContentLength))) size, buf := 0, make([]byte, ice.MOD_BUFS) diff --git a/base/web/serve.go b/base/web/serve.go index 0b689e9e..12b486c4 100644 --- a/base/web/serve.go +++ b/base/web/serve.go @@ -303,6 +303,7 @@ func init() { } return false }) + m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, nfs.CAT, "usr/publish/order.js") }}, ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(SERVE).Table(func(index int, value map[string]string, head []string) { diff --git a/base/web/space.go b/base/web/space.go index f306b344..2f09c7e1 100644 --- a/base/web/space.go +++ b/base/web/space.go @@ -92,8 +92,12 @@ func _space_handle(m *ice.Message, safe bool, send map[string]*ice.Message, c *w msg.Log("recv", "%v->%v %s %v", source, target, msg.Detailv(), msg.FormatMeta()) if len(target) == 0 { - msg.Log_AUTH(aaa.USERROLE, kit.Select(msg.Option(ice.MSG_USERROLE), m.Cmd(aaa.USER, msg.Option(ice.MSG_USERNAME)).Append(aaa.USERROLE)), aaa.USERNAME, msg.Option(ice.MSG_USERNAME)) if msg.Optionv(ice.MSG_HANDLE, ice.TRUE); safe { // 下行命令 + msg.Option(ice.MSG_USERROLE, kit.Select(msg.Option(ice.MSG_USERROLE), msg.Cmd(aaa.USER, msg.Option(ice.MSG_USERNAME)).Append(aaa.USERROLE))) + if msg.Option(ice.MSG_USERROLE) == aaa.VOID && ice.Info.UserName == "demo" { + msg.Option(ice.MSG_USERROLE, aaa.TECH) + } + msg.Log_AUTH(aaa.USERROLE, msg.Option(ice.MSG_USERROLE), aaa.USERNAME, msg.Option(ice.MSG_USERNAME)) msg.Go(func() { _space_exec(msg, source, target, c, name) }) } else { // 上行请求 msg.Push(mdb.LINK, kit.MergePOD(_space_domain(msg), name)) diff --git a/base/web/spide.go b/base/web/spide.go index 97d9f788..6fb536f8 100644 --- a/base/web/spide.go +++ b/base/web/spide.go @@ -317,6 +317,7 @@ const ( Authorization = "Authorization" ContentType = "Content-Type" ContentLength = "Content-Length" + UserAgent = "User-Agent" ContentFORM = "application/x-www-form-urlencoded" ContentJSON = "application/json" diff --git a/conf.go b/conf.go index 11336262..381c04e9 100644 --- a/conf.go +++ b/conf.go @@ -220,6 +220,8 @@ const ( // RENDER ) const ( // PROCESS PROCESS_LOCATION = "_location" + PROCESS_REPLACE = "_replace" + PROCESS_HISTORY = "_history" PROCESS_REFRESH = "_refresh" PROCESS_REWRITE = "_rewrite" PROCESS_DISPLAY = "_display" diff --git a/core/chat/action.go b/core/chat/action.go index 735e6476..dd09bb6c 100644 --- a/core/chat/action.go +++ b/core/chat/action.go @@ -39,7 +39,7 @@ func _action_exec(m *ice.Message, river, storm, index string, arg ...string) { if cmds = kit.Simple(kit.Keys(value[ice.CTX], value[ice.CMD])); kit.Format(value[ice.POD]) != "" { m.Option(ice.POD, value[ice.POD]) // 远程节点 } - }) == nil && !m.Right(cmds) { + }) == nil && m.Option(ice.MSG_USERPOD) == "" && !m.Right(cmds) { return // 没有授权 } @@ -189,7 +189,7 @@ func init() { if m.Warn(m.Option(ice.MSG_USERNAME) == "", ice.ErrNotLogin, arg) { return // 没有登录 } - if m.Warn(!_action_right(m, arg[0], arg[1]), ice.ErrNotRight, arg) { + if m.Option(ice.MSG_USERPOD) == "" && m.Warn(!_action_right(m, arg[0], arg[1]), ice.ErrNotRight, arg) { return // 没有授权 } diff --git a/core/chat/cmd.go b/core/chat/cmd.go index 5af32c80..278f7ebd 100644 --- a/core/chat/cmd.go +++ b/core/chat/cmd.go @@ -42,8 +42,10 @@ func init() { return // 插件 } - if m.PodCmd(ctx.COMMAND, arg[0]) && m.Length() > 0 { - m.RenderCmd(arg[0], arg[1:]) // 远程命令 + if m.PodCmd(ctx.COMMAND, arg[0]) { + if !m.IsErr() { + m.RenderCmd(arg[0], arg[1:]) // 远程命令 + } } else if m.Cmdy(ctx.COMMAND, arg[0]); m.Length() > 0 { m.RenderCmd(arg[0], arg[1:]) // 本地命令 } else { diff --git a/core/chat/header.go b/core/chat/header.go index d1817f53..a947ff09 100644 --- a/core/chat/header.go +++ b/core/chat/header.go @@ -8,8 +8,6 @@ import ( "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" - "shylinux.com/x/icebergs/base/nfs" - "shylinux.com/x/icebergs/base/ssh" "shylinux.com/x/icebergs/base/tcp" "shylinux.com/x/icebergs/base/web" "shylinux.com/x/icebergs/core/code" @@ -125,10 +123,8 @@ func init() { _header_users(m, m.ActionKey(), arg...) }}, - ctx.CONFIG: {Name: "config file", Help: "配置", Hand: func(m *ice.Message, arg ...string) { - pod := strings.Split(m.Cmdx(web.SPACE, m.Option(ice.MSG_USERPOD), cli.RUNTIME, "make.domain"), "/chat/pod/")[1] - m.Cmd(web.SPACE, m.Option(ice.MSG_USERPOD), nfs.SAVE, m.Option(nfs.FILE), m.Cmdx(web.SPACE, pod, nfs.CAT, m.Option(nfs.FILE))) - m.Cmd(web.SPACE, m.Option(ice.MSG_USERPOD), ssh.SOURCE, m.Option(nfs.FILE)) + ctx.CONFIG: {Name: "config scope", Help: "配置", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(web.SPACE, m.Option(ice.MSG_USERPOD), m.Prefix(OAUTH), CHECK, arg) }}, code.WEBPACK: {Name: "webpack", Help: "打包页面", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(code.WEBPACK, cli.BUILD, m.OptionSimple(mdb.NAME)) diff --git a/core/chat/oauth.go b/core/chat/oauth.go new file mode 100644 index 00000000..f2df5f60 --- /dev/null +++ b/core/chat/oauth.go @@ -0,0 +1,66 @@ +package chat + +import ( + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" + "shylinux.com/x/icebergs/base/cli" + "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/nfs" + "shylinux.com/x/icebergs/base/ssh" + "shylinux.com/x/icebergs/base/web" + kit "shylinux.com/x/toolkits" +) + +const OAUTH = "oauth" + +func init() { + const ( + CHECK = "check" + APPLY = "apply" + REPLY = "reply" + OFFER = "offer" + + OAUTH_APPLY = "/oauth/apply" + OAUTH_REPLY = "/oauth/reply" + OAUTH_OFFER = "/oauth/offer" + ) + const ( + SCOPE = "scope" + REDIRECT_URI = "redirect_uri" + ACCESS_TOKEN = "access_token" + EXPIRES = "expires" + ) + Index.Merge(&ice.Context{Commands: map[string]*ice.Command{ + OAUTH: {Name: "oauth hash auto prunes", Help: "授权", Action: ice.MergeAction(map[string]*ice.Action{ + ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { + m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, m.Prefix(OAUTH_APPLY)) + m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, m.Prefix(OAUTH_OFFER)) + }}, + CHECK: {Name: "check scope", Help: "检查", Hand: func(m *ice.Message, arg ...string) { + m.Echo(kit.MergeURL(m.Cmdx(cli.RUNTIME, cli.MAKE_DOMAIN)+OAUTH_APPLY, m.OptionSimple(SCOPE), REDIRECT_URI, m.MergePodURL(OAUTH_REPLY))) + }}, + APPLY: {Name: "apply redirect_uri", Help: "申请", Hand: func(m *ice.Message, arg ...string) { + if m.Right(m.Option(SCOPE)) { + token := mdb.HashCreate(m, mdb.TIME, m.Time(m.Config(EXPIRES)), aaa.USERNAME, m.Option(ice.MSG_USERNAME), m.OptionSimple(SCOPE, REDIRECT_URI)).Result() + m.ProcessReplace(kit.MergeURL(m.Option(REDIRECT_URI), OFFER, m.MergePodURL(OAUTH_OFFER, ACCESS_TOKEN, token))) + } + }}, + REPLY: {Name: "reply offer", Help: "通过", Hand: func(m *ice.Message, arg ...string) { + m.Option(web.SPIDE_HEADER, web.UserAgent, m.PrefixKey()) + m.Cmd(ssh.SOURCE, ice.ETC_LOCAL_SHY, kit.Dict(nfs.CAT_CONTENT, m.Cmdx(web.SPIDE, ice.DEV, web.SPIDE_GET, m.Option(OFFER)))) + m.ProcessHistory() + }}, + }, mdb.HashAction(mdb.SHORT, mdb.UNIQ, EXPIRES, "720h"))}, + OAUTH_APPLY: {Name: "/oauth/apply", Help: "授权申请", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.RenderCmd(m.Prefix(OAUTH), APPLY) + }}, + OAUTH_REPLY: {Name: "/oauth/reply", Help: "授权通过", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.RenderCmd(m.Prefix(OAUTH), REPLY) + }}, + OAUTH_OFFER: {Name: "/oauth/offer", Help: "授权资源", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if msg := m.Cmd(OAUTH, m.Option(ACCESS_TOKEN), ice.OptionFields("time,scope")); kit.Time(msg.Time()) < kit.Time(msg.Append(mdb.TIME)) { + aaa.UserRoot(m).Cmdy(nfs.CAT, msg.Append(SCOPE)).RenderResult() + } + }}, + }}) +} diff --git a/core/chat/pod.go b/core/chat/pod.go index 4d1964bb..004125fb 100644 --- a/core/chat/pod.go +++ b/core/chat/pod.go @@ -2,6 +2,7 @@ package chat import ( "path" + "strings" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" @@ -20,7 +21,7 @@ func init() { ice.CTX_INIT: {Name: "_init", Help: "初始化", Hand: func(m *ice.Message, arg ...string) { }}, }, ctx.CmdAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if m.IsCliUA() { + if strings.HasPrefix(m.R.Header.Get("User-Agent"), "curl") || strings.HasPrefix(m.R.Header.Get("User-Agent"), "Wget") { m.Option(ice.MSG_USERNAME, "root") m.Option(ice.MSG_USERROLE, "root") m.Option(ice.POD, kit.Select("", arg, 0)) @@ -40,8 +41,10 @@ func init() { } else if arg[1] == WEBSITE { // 节点网页 m.RenderWebsite(arg[0], path.Join(arg[2:]...)) - } else { // 节点命令 + } else if arg[1] == "cmd" { // 节点命令 m.Cmdy("/cmd/", path.Join(arg[2:]...)) + } else { + m.Cmdy(web.SPACE, m.Option(ice.MSG_USERPOD), "web.chat."+ice.PS+path.Join(arg[1:]...)) } }}, }}) diff --git a/core/wiki/field.go b/core/wiki/field.go index 442c37c0..d32d2497 100644 --- a/core/wiki/field.go +++ b/core/wiki/field.go @@ -40,6 +40,9 @@ func _field_show(m *ice.Message, name, text string, arg ...string) { name = cmd.Help } }) + if !m.Spawn().Right(cmds[0]) { + return + } name = strings.ReplaceAll(name, ice.SP, "_") meta[mdb.NAME], meta[mdb.INDEX] = name, text diff --git a/core/wiki/word.go b/core/wiki/word.go index e19176b7..38d63c0c 100644 --- a/core/wiki/word.go +++ b/core/wiki/word.go @@ -2,6 +2,7 @@ package wiki import ( ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/lex" "shylinux.com/x/icebergs/base/mdb" @@ -38,6 +39,9 @@ func init() { )}, }, Commands: map[string]*ice.Command{ WORD: {Name: "word path=src/main.shy@key auto play", Help: "语言文字", Meta: kit.Dict(ice.DisplayLocal("")), Action: ice.MergeAction(map[string]*ice.Action{ + ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { + m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, m.PrefixKey("src/main.shy")) + }}, mdb.SEARCH: {Name: "search", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { if arg[0] == mdb.FOREACH && arg[1] == "" { m.PushSearch(mdb.TYPE, "shy", mdb.NAME, "src/main.shy", mdb.TEXT, m.MergeCmd("")) diff --git a/go.sum b/go.sum index 96f6e8b8..6f21b039 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ +shylinux.com/x/go-qrcode v0.0.1 h1:/eOGqMj1qtgs9Ymd12zTUa1gcJZs9S92kj2lb0QzKsE= shylinux.com/x/go-qrcode v0.0.1/go.mod h1:KAbtU+KwiiABMZ/CJ0zh9PI2AX82Uf9rRYcQ4ODm4po= shylinux.com/x/toolkits v0.5.8 h1:8MhHLmglPTPiXAdUgAJXx+gOxJoQzmpNeC7QzsZcjJw= shylinux.com/x/toolkits v0.5.8/go.mod h1:8LbYHe7oxBIqb6s4MSOD+4d28QvPdvkyCVtwB/JW7AA= +shylinux.com/x/websocket v0.0.1 h1:OBc21DxqsGlQ2+Pz76xqLyDNo1LV+PUUqfWi+1PZPDE= shylinux.com/x/websocket v0.0.1/go.mod h1:AaSpMToOxbMULKQytzczeHPuqb708vK1vrAzCxLo/XE= diff --git a/option.go b/option.go index f7bad878..6d1dc3ee 100644 --- a/option.go +++ b/option.go @@ -217,6 +217,12 @@ func (m *Message) Process(action string, arg ...interface{}) { func (m *Message) ProcessLocation(arg ...interface{}) { m.Process(PROCESS_LOCATION, arg...) } +func (m *Message) ProcessReplace(arg ...interface{}) { + m.Process(PROCESS_REPLACE, arg...) +} +func (m *Message) ProcessHistory(arg ...interface{}) { + m.Process(PROCESS_HISTORY, arg...) +} func (m *Message) ProcessRewrite(arg ...interface{}) { m.Process(PROCESS_REWRITE, arg...) } @@ -264,11 +270,14 @@ func (m *Message) ProcessBack() { m.Process(PROCESS_BACK) } func (m *Message) OptionUserWeb() *url.URL { return kit.ParseURL(m.Option(MSG_USERWEB)) } +func (m *Message) MergeURL2(url string, arg ...interface{}) string { + return kit.MergeURL2(m.Option(MSG_USERWEB), url, arg...) +} func (m *Message) MergeLink(url string, arg ...interface{}) string { return strings.Split(m.MergeURL2(url, arg...), "?")[0] } -func (m *Message) MergeURL2(url string, arg ...interface{}) string { - return kit.MergeURL2(m.Option(MSG_USERWEB), url, arg...) +func (m *Message) MergePodURL(url string, arg ...interface{}) string { + return kit.MergeURL(m.MergeLink(path.Join("/chat/pod/", m.Option(MSG_USERPOD), url)), arg...) } func (m *Message) MergePod(pod string, arg ...interface{}) string { return kit.MergePOD(kit.Select(Info.Domain, m.Option(MSG_USERWEB)), pod, arg...) diff --git a/render.go b/render.go index b082e738..1c197d85 100644 --- a/render.go +++ b/render.go @@ -87,13 +87,11 @@ func (m *Message) RenderCmd(index string, args ...interface{}) { if index != "" { msg := m.Cmd(COMMAND, index) list = kit.Format(kit.List(kit.Dict( - INDEX, index, ARGS, kit.Simple(args), - msg.AppendSimple(NAME, HELP), - FEATURE, kit.UnMarshal(msg.Append(META)), - INPUTS, kit.UnMarshal(msg.Append(LIST)), + INDEX, index, ARGS, kit.Simple(args), msg.AppendSimple(NAME, HELP), + INPUTS, kit.UnMarshal(msg.Append(LIST)), FEATURE, kit.UnMarshal(msg.Append(META)), ))) } - m.RenderResult(kit.Format(` + m.Echo(kit.Format(` @@ -103,7 +101,7 @@ func (m *Message) RenderCmd(index string, args ...interface{}) { -`, list)) +`, list)).RenderResult() } func (m *Message) IsCliUA() bool {