You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
3.5 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "strconv"
  7. "strings"
  8. "github.com/codegangsta/cli"
  9. "github.com/gogits/gogs/models"
  10. )
  11. var (
  12. COMMANDS_READONLY = map[string]int{
  13. "git-upload-pack": models.AU_WRITABLE,
  14. "git upload-pack": models.AU_WRITABLE,
  15. "git-upload-archive": models.AU_WRITABLE,
  16. }
  17. COMMANDS_WRITE = map[string]int{
  18. "git-receive-pack": models.AU_READABLE,
  19. "git receive-pack": models.AU_READABLE,
  20. }
  21. )
  22. var CmdServ = cli.Command{
  23. Name: "serv",
  24. Usage: "This command just should be called by ssh shell",
  25. Description: `
  26. gogs serv provide access auth for repositories`,
  27. Action: runServ,
  28. Flags: []cli.Flag{},
  29. }
  30. func In(b string, sl map[string]int) bool {
  31. _, e := sl[b]
  32. return e
  33. }
  34. func runServ(*cli.Context) {
  35. keys := strings.Split(os.Args[2], "-")
  36. if len(keys) != 2 {
  37. fmt.Println("auth file format error")
  38. return
  39. }
  40. keyId, err := strconv.ParseInt(keys[1], 10, 64)
  41. if err != nil {
  42. fmt.Println("auth file format error")
  43. return
  44. }
  45. user, err := models.GetUserByKeyId(keyId)
  46. if err != nil {
  47. fmt.Println("You have no right to access")
  48. return
  49. }
  50. cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
  51. if cmd == "" {
  52. println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
  53. return
  54. }
  55. verb, args := parseCmd(cmd)
  56. rRepo := strings.Trim(args, "'")
  57. rr := strings.SplitN(rRepo, "/", 2)
  58. if len(rr) != 2 {
  59. println("Unavilable repository", args)
  60. return
  61. }
  62. repoName := rr[1]
  63. if strings.HasSuffix(repoName, ".git") {
  64. repoName = repoName[:len(repoName)-4]
  65. }
  66. os.Setenv("userName", user.Name)
  67. os.Setenv("userId", strconv.Itoa(int(user.Id)))
  68. repo, err := models.GetRepositoryByName(user, repoName)
  69. if err != nil {
  70. println("Unavilable repository", err)
  71. return
  72. }
  73. os.Setenv("repoId", strconv.Itoa(int(repo.Id)))
  74. os.Setenv("repoName", repoName)
  75. isWrite := In(verb, COMMANDS_WRITE)
  76. isRead := In(verb, COMMANDS_READONLY)
  77. switch {
  78. case isWrite:
  79. has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
  80. if err != nil {
  81. println("Inernel error:", err)
  82. return
  83. }
  84. if !has {
  85. println("You have no right to write this repository")
  86. return
  87. }
  88. case isRead:
  89. has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE)
  90. if err != nil {
  91. println("Inernel error")
  92. return
  93. }
  94. if !has {
  95. has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
  96. if err != nil {
  97. println("Inernel error")
  98. return
  99. }
  100. }
  101. if !has {
  102. println("You have no right to access this repository")
  103. return
  104. }
  105. default:
  106. println("Unknown command")
  107. return
  108. }
  109. isExist, err := models.IsRepositoryExist(user, repoName)
  110. if err != nil {
  111. println("Inernel error:", err.Error())
  112. return
  113. }
  114. if !isExist {
  115. if isRead {
  116. println("Repository", user.Name+"/"+repoName, "is not exist")
  117. return
  118. } else if isWrite {
  119. _, err := models.CreateRepository(user, repoName, "", "", "", false, true)
  120. if err != nil {
  121. println("Create repository failed")
  122. return
  123. }
  124. }
  125. }
  126. gitcmd := exec.Command(verb, rRepo)
  127. gitcmd.Dir = models.RepoRootPath
  128. gitcmd.Stdout = os.Stdout
  129. gitcmd.Stdin = os.Stdin
  130. gitcmd.Stderr = os.Stderr
  131. err = gitcmd.Run()
  132. if err != nil {
  133. println("execute command error:", err.Error())
  134. }
  135. }
  136. func parseCmd(cmd string) (string, string) {
  137. ss := strings.SplitN(cmd, " ", 2)
  138. if len(ss) != 2 {
  139. return "", ""
  140. }
  141. verb, args := ss[0], ss[1]
  142. if verb == "git" {
  143. ss = strings.SplitN(args, " ", 2)
  144. args = ss[1]
  145. verb = fmt.Sprintf("%s %s", verb, ss[0])
  146. }
  147. return verb, args
  148. }