diff --git a/go.sum b/go.sum index b5a9aafe..62ac4f17 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/AaronO/go-git-http v0.0.0-20161214145340-1d9485b3a98f h1:x/RDwGRneK2/891S2o7KhZt3MhHMSCssoeDOfvolTMk= github.com/AaronO/go-git-http v0.0.0-20161214145340-1d9485b3a98f/go.mod h1:+6Yuq73F9068Na+mSBNXCvyuxvgw4f/g5ii40e3U8Sc= github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -9,6 +10,8 @@ github.com/shylinux/toolkits v0.2.3 h1:UdE5dUKtc+iVeco9sFrlj98BxVJADYoLNeywTnLrS github.com/shylinux/toolkits v0.2.3/go.mod h1:oMwi/N00I2cXenmcAkqikEncTzB4u5JhTQ9mO5xj7sY= github.com/shylinux/toolkits v0.2.4 h1:2TaRBYdt15dE9vTUTO++6aF66vOZNd+ruP3be1C4zaY= github.com/shylinux/toolkits v0.2.4/go.mod h1:oMwi/N00I2cXenmcAkqikEncTzB4u5JhTQ9mO5xj7sY= +github.com/shylinux/toolkits v0.2.5 h1:dAqUrWjUSl/QuhUN9jRrALqmICsX5sFMmWm4LsiIi0s= +github.com/shylinux/toolkits v0.2.5/go.mod h1:oMwi/N00I2cXenmcAkqikEncTzB4u5JhTQ9mO5xj7sY= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= diff --git a/misc/git/config.go b/misc/git/config.go index e19b482d..4f651f2e 100644 --- a/misc/git/config.go +++ b/misc/git/config.go @@ -9,62 +9,73 @@ import ( kit "github.com/shylinux/toolkits" ) +func _config_set(m *ice.Message, key, value string) { + m.Cmd(cli.SYSTEM, GIT, CONFIG, "--global", key, value) +} +func _config_get(m *ice.Message, key string) string { + return m.Cmdx(cli.SYSTEM, GIT, CONFIG, "--global", key) +} +func _config_list(m *ice.Message) { + for _, v := range strings.Split(_config_get(m, "--list"), "\n") { + if ls := strings.Split(v, "="); len(ls) > 1 { + m.Push(kit.MDB_NAME, ls[0]) + m.Push(kit.MDB_VALUE, ls[1]) + m.PushButton(mdb.REMOVE) + } + } + m.Sort(kit.MDB_NAME) + + m.Cmd(mdb.SELECT, m.Prefix(CONFIG), "", mdb.HASH, ice.OptionFields("name,value")).Table(func(index int, value map[string]string, head []string) { + m.Push("", value, head) + m.PushButton(mdb.CREATE) + }) +} + const CONFIG = "config" func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ - CONFIG: {Name: CONFIG, Help: "配置键", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME, "init", kit.Dict( - "alias", kit.Dict("s", "status", "b", "branch"), - "credential", kit.Dict("helper", "store"), - "core", kit.Dict("quotepath", "false"), - "push", kit.Dict("default", "simple"), - "color", kit.Dict("ui", "always"), - ))}, + CONFIG: {Name: CONFIG, Help: "配置键", Value: kit.Data( + kit.MDB_SHORT, kit.MDB_NAME, "init", kit.Dict( + "alias", kit.Dict("s", "status", "b", "branch"), + "credential", kit.Dict("helper", "store"), + "core", kit.Dict("quotepath", "false"), + "push", kit.Dict("default", "simple"), + "color", kit.Dict("ui", "always"), + ))}, }, Commands: map[string]*ice.Command{ - CONFIG: {Name: "server name auto create", Help: "配置键", Action: map[string]*ice.Action{ - "init": {Name: "create name value", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - kit.Fetch(m.Confv(GIT, kit.Keym("config")), func(conf string, value interface{}) { + CONFIG: {Name: "server name auto create import", Help: "配置键", Action: map[string]*ice.Action{ + mdb.IMPORT: {Name: "import", Help: "初始化", Hand: func(m *ice.Message, arg ...string) { + kit.Fetch(m.Confv(CONFIG, kit.Keym("init")), func(conf string, value interface{}) { kit.Fetch(value, func(key string, value string) { - m.Cmd(cli.SYSTEM, "bin/git", "config", "--global", conf+"."+key, value) + _config_set(m, kit.Keys(conf, key), value) }) }) }}, - mdb.CREATE: {Name: "create name value", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - m.Cmd(cli.SYSTEM, GIT, CONFIG, "--global", m.Option(kit.MDB_NAME), m.Option(kit.MDB_VALUE)) - m.Cmd(mdb.DELETE, m.Prefix(CONFIG), "", kit.MDB_HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME)) - m.ProcessRefresh("0ms") + m.Cmd(mdb.DELETE, m.Prefix(CONFIG), "", mdb.HASH, m.OptionSimple(kit.MDB_NAME)) + _config_set(m, m.Option(kit.MDB_NAME), m.Option(kit.MDB_VALUE)) + m.ProcessRefresh30ms() }}, mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { if arg[0] == kit.MDB_VALUE { - m.Cmd(cli.SYSTEM, GIT, CONFIG, "--global", m.Option(kit.MDB_NAME), arg[1]) + m.Cmd(mdb.DELETE, m.Prefix(CONFIG), "", mdb.HASH, m.OptionSimple(kit.MDB_NAME)) + _config_set(m, m.Option(kit.MDB_NAME), arg[1]) + m.ProcessRefresh30ms() } }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - m.Cmd(cli.SYSTEM, GIT, CONFIG, "--global", "--unset", m.Option(kit.MDB_NAME)) - m.Cmd(mdb.INSERT, m.Prefix(CONFIG), "", kit.MDB_HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME), kit.MDB_VALUE, m.Option(kit.MDB_VALUE)) + m.Cmd(mdb.INSERT, m.Prefix(CONFIG), "", mdb.HASH, m.OptionSimple(kit.MDB_NAME, kit.MDB_VALUE)) + _config_set(m, "--unset", m.Option(kit.MDB_NAME)) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) > 0 { - m.Echo(m.Cmdx(cli.SYSTEM, GIT, CONFIG, "--global", arg[0])) + if len(arg) == 0 { + _config_list(m) return } - - for _, v := range strings.Split(m.Cmdx(cli.SYSTEM, GIT, CONFIG, "--global", "--list"), "\n") { - if ls := strings.Split(v, "="); len(ls) > 1 { - m.Push(kit.MDB_NAME, ls[0]) - m.Push(kit.MDB_VALUE, ls[1]) - m.PushButton(mdb.REMOVE) - } - } - m.Sort(kit.MDB_NAME) - - m.Cmd(mdb.SELECT, m.Prefix(CONFIG), "", kit.MDB_HASH, ice.OptionFields("name,value")).Table(func(index int, value map[string]string, head []string) { - m.Push("", value, head) - m.PushButton(mdb.CREATE) - }) + m.Echo(_config_get(m, arg[0])) }}, }}) } diff --git a/misc/git/server.go b/misc/git/server.go index 3b85d5e6..5f6c5a39 100644 --- a/misc/git/server.go +++ b/misc/git/server.go @@ -1,12 +1,15 @@ package git import ( + "encoding/base64" + "fmt" + "net/http" "os" "path" + "regexp" "strings" githttp "github.com/AaronO/go-git-http" - "github.com/AaronO/go-git-http/auth" ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" @@ -16,65 +19,85 @@ import ( kit "github.com/shylinux/toolkits" ) +var basicAuthRegex = regexp.MustCompile("^([^:]*):(.*)$") + +func _server_login(m *ice.Message) error { + parts := strings.SplitN(m.R.Header.Get("Authorization"), " ", 2) + if len(parts) < 2 { + return fmt.Errorf("Invalid authorization header, not enought parts") + } + + authType, authData := parts[0], parts[1] + if strings.ToLower(authType) != "basic" { + return fmt.Errorf("Authentication '%s' was not of 'Basic' type", authType) + } + + data, err := base64.StdEncoding.DecodeString(authData) + if err != nil { + return err + } + + matches := basicAuthRegex.FindStringSubmatch(string(data)) + if matches == nil { + return fmt.Errorf("Authorization data '%s' did not match auth regexp", data) + } + + username, password := matches[1], matches[2] + if !aaa.UserLogin(m, username, password) { + return fmt.Errorf("username or password error") + } + if aaa.UserRole(m, username) == aaa.VOID { + return fmt.Errorf("userrole error") + } + return nil +} +func _server_repos(m *ice.Message, arg ...string) { + m.Option(cli.CMD_DIR, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)) + p := strings.TrimSuffix(path.Join(arg...), "info/refs") + if _, e := os.Stat(path.Join(m.Option(cli.CMD_DIR), p)); os.IsNotExist(e) { + m.Cmd(cli.SYSTEM, GIT, INIT, "--bare", p) // 创建仓库 + } +} + const SERVER = "server" func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ - SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data(kit.MDB_PATH, "usr/local")}, + SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data(kit.MDB_PATH, ice.USR_LOCAL)}, }, Commands: map[string]*ice.Command{ + web.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Render(ice.RENDER_VOID) + }}, + "/repos/": {Name: "/repos/", Help: "代码库", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + switch m.Option("service") { + case "git-receive-pack": // 上传代码 + if err := _server_login(m); err != nil { + m.W.Header().Set("WWW-Authenticate", `Basic realm="git server"`) + http.Error(m.W, err.Error(), 401) // 认证失败 + return + } + _server_repos(m, arg...) + + case "git-upload-pack": // 下载代码 + + } + + githttp.New(kit.Path(m.Conf(SERVER, kit.META_PATH))).ServeHTTP(m.W, m.R) + }}, SERVER: {Name: "server path auto create", Help: "服务器", Action: map[string]*ice.Action{ mdb.CREATE: {Name: "create name", Help: "添加", Hand: func(m *ice.Message, arg ...string) { m.Option(cli.CMD_DIR, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)) m.Cmd(cli.SYSTEM, GIT, INIT, "--bare", m.Option(kit.MDB_NAME)) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) == 0 { - m.Option(nfs.DIR_ROOT, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)) + if m.Option(nfs.DIR_ROOT, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)); len(arg) == 0 { m.Cmdy(nfs.DIR, "./") return } - m.Cmdy("_sum", path.Join("usr/local/repos", arg[0])) - }}, - - web.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Render(ice.RENDER_VOID) - }}, - "/repos/": {Name: "/github.com/", Help: "/github.com/", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - auth.Authenticator(func(info auth.AuthInfo) (bool, error) { - if !aaa.UserLogin(m, info.Username, info.Password) { - return false, nil - } - - if info.Push { - if aaa.UserRole(m, info.Username) == aaa.VOID { - return false, nil - } - - m.Option(cli.CMD_DIR, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)) - p := strings.Trim(path.Join(arg...), "info/refs") - if _, e := os.Stat(path.Join(m.Option(cli.CMD_DIR), p)); os.IsNotExist(e) { - m.Cmd(cli.SYSTEM, GIT, INIT, "--bare", p) - } - } - - return true, nil - })(githttp.New(kit.Path(m.Conf(SERVER, kit.META_PATH)))).ServeHTTP(m.W, m.R) - }}, - "/github.com/": {Name: "/github.com/", Help: "/github.com/", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - auth.Authenticator(func(info auth.AuthInfo) (bool, error) { - if !aaa.UserLogin(m, info.Username, info.Password) { - // return false, nil - } - - if info.Push && aaa.UserRole(m, info.Username) == aaa.VOID { - return false, nil - } - - return true, nil - })(githttp.New(kit.Path(m.Conf(SERVER, kit.META_PATH)))).ServeHTTP(m.W, m.R) + m.Cmdy("_sum", path.Join(m.Option(nfs.DIR_ROOT), arg[0])) }}, }, }) diff --git a/misc/git/status.go b/misc/git/status.go index e74c349c..ada13917 100644 --- a/misc/git/status.go +++ b/misc/git/status.go @@ -19,19 +19,18 @@ func _status_each(m *ice.Message, title string, cmds ...string) { m.Cmd(REPOS, ice.OptionFields("name,path")).Table(func(index int, value map[string]string, head []string) { toast(value[kit.MDB_NAME], count, total) - msg := m.Cmd(cmds, ice.Option{cli.CMD_DIR, value[kit.MDB_PATH]}) - if msg.Append(cli.CMD_CODE) != "0" { - list = append(list, value[kit.MDB_NAME]) + if msg := m.Cmd(cmds, ice.Option{cli.CMD_DIR, value[kit.MDB_PATH]}); msg.Append(cli.CMD_CODE) != "0" { m.Toast(msg.Append(cli.CMD_ERR), "error: "+value[kit.MDB_NAME], "3s") + list = append(list, value[kit.MDB_NAME]) m.Sleep("3s") } count++ }) if len(list) > 0 { - m.Toast(strings.Join(list, "\n"), "failure", "30s") + m.Toast(strings.Join(list, "\n"), ice.FAILURE, "30s") } else { - toast("success", count, total) + toast(ice.SUCCESS, count, total) } }) @@ -53,8 +52,7 @@ func _status_stat(m *ice.Message, files, adds, dels int) (int, int, int) { } func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) { m.Cmd(REPOS, ice.OptionFields("name,path")).Table(func(index int, value map[string]string, head []string) { - m.Option(cli.CMD_DIR, value[kit.MDB_PATH]) - diff := m.Cmdx(cli.SYSTEM, GIT, STATUS, "-sb") + diff := m.Cmdx(cli.SYSTEM, GIT, STATUS, "-sb", ice.Option{cli.CMD_DIR, value[kit.MDB_PATH]}) for _, v := range strings.Split(strings.TrimSpace(diff), "\n") { vs := strings.SplitN(strings.TrimSpace(v), " ", 2) @@ -80,7 +78,7 @@ func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) { list = append(list, COMMIT) } } - m.PushButton(strings.Join(list, ",")) + m.PushButton(list...) } files, adds, dels = _status_stat(m, files, adds, dels) @@ -116,7 +114,7 @@ func init() { }}, MAKE: {Name: "make", Help: "编译", Hand: func(m *ice.Message, arg ...string) { m.Toast("building", MAKE, 100000) - defer m.Toast("success", MAKE, 1000) + defer m.Toast(ice.SUCCESS, MAKE, 1000) m.Cmdy(cli.SYSTEM, MAKE) }}, @@ -127,13 +125,11 @@ func init() { return } - m.Option(cli.CMD_DIR, _repos_path(m.Option(kit.MDB_NAME))) - m.Cmdy(cli.SYSTEM, GIT, PUSH) + m.Cmdy(cli.SYSTEM, GIT, PUSH, ice.Option{cli.CMD_DIR, _repos_path(m.Option(kit.MDB_NAME))}) }}, ADD: {Name: "add", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - m.Option(cli.CMD_DIR, _repos_path(m.Option(kit.MDB_NAME))) - m.Cmdy(cli.SYSTEM, GIT, ADD, m.Option(kit.MDB_FILE)) + m.Cmdy(cli.SYSTEM, GIT, ADD, m.Option(kit.MDB_FILE), ice.Option{cli.CMD_DIR, _repos_path(m.Option(kit.MDB_NAME))}) }}, OPT: {Name: "opt", Help: "优化"}, PRO: {Name: "pro", Help: "自举"}, COMMIT: {Name: "commit action=opt,add,pro comment=some@key", Help: "提交", Hand: func(m *ice.Message, arg ...string) { @@ -143,8 +139,7 @@ func init() { m.Option(kit.MDB_TEXT, kit.Select("opt some", strings.Join(arg, " "))) } - m.Option(cli.CMD_DIR, _repos_path(m.Option(kit.MDB_NAME))) - m.Cmdy(cli.SYSTEM, GIT, COMMIT, "-am", m.Option(kit.MDB_TEXT)) + m.Cmdy(cli.SYSTEM, GIT, COMMIT, "-am", m.Option(kit.MDB_TEXT), ice.Option{cli.CMD_DIR, _repos_path(m.Option(kit.MDB_NAME))}) m.ProcessBack() }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {