db_gin.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package db
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "os"
  8. "path/filepath"
  9. "regexp"
  10. "strings"
  11. "github.com/G-Node/git-module"
  12. "github.com/G-Node/gogs/internal/conf"
  13. "github.com/G-Node/libgin/libgin"
  14. "github.com/G-Node/libgin/libgin/annex"
  15. "github.com/unknwon/com"
  16. "golang.org/x/crypto/bcrypt"
  17. log "gopkg.in/clog.v1"
  18. )
  19. // StartIndexing sends an indexing request to the configured indexing service
  20. // for a repository.
  21. func StartIndexing(repo Repository) {
  22. go func() {
  23. if conf.Search.IndexURL == "" {
  24. log.Trace("Indexing not enabled")
  25. return
  26. }
  27. log.Trace("Indexing repository %d", repo.ID)
  28. ireq := libgin.IndexRequest{
  29. RepoID: repo.ID,
  30. RepoPath: repo.FullName(),
  31. }
  32. data, err := json.Marshal(ireq)
  33. if err != nil {
  34. log.Error(2, "Could not marshal index request: %v", err)
  35. return
  36. }
  37. key := []byte(conf.Search.Key)
  38. encdata, err := libgin.EncryptString(key, string(data))
  39. if err != nil {
  40. log.Error(2, "Could not encrypt index request: %v", err)
  41. }
  42. req, err := http.NewRequest(http.MethodPost, conf.Search.IndexURL, strings.NewReader(encdata))
  43. if err != nil {
  44. log.Error(2, "Error creating index request")
  45. }
  46. client := http.Client{}
  47. resp, err := client.Do(req)
  48. if err != nil || resp.StatusCode != http.StatusOK {
  49. log.Error(2, "Error submitting index request for [%d: %s]: %v", repo.ID, repo.FullName(), err)
  50. return
  51. }
  52. }()
  53. }
  54. // RebuildIndex sends all repositories to the indexing service to be indexed.
  55. func RebuildIndex() error {
  56. indexurl := conf.Search.IndexURL
  57. if indexurl == "" {
  58. return fmt.Errorf("Indexing service not configured")
  59. }
  60. // collect all repo ID -> Path mappings directly from the DB
  61. repos := make(RepositoryList, 0, 100)
  62. if err := x.Find(&repos); err != nil {
  63. return fmt.Errorf("get all repos: %v", err)
  64. }
  65. log.Trace("Found %d repositories to index", len(repos))
  66. for _, repo := range repos {
  67. StartIndexing(*repo)
  68. }
  69. log.Trace("Rebuilding search index")
  70. return nil
  71. }
  72. func annexUninit(path string) {
  73. // walker sets the permission for any file found to 0660, to allow deletion
  74. var mode os.FileMode
  75. walker := func(path string, info os.FileInfo, err error) error {
  76. if info == nil {
  77. return nil
  78. }
  79. mode = 0660
  80. if info.IsDir() {
  81. mode = 0770
  82. }
  83. if err := os.Chmod(path, mode); err != nil {
  84. log.Error(3, "failed to change permissions on '%s': %v", path, err)
  85. }
  86. return nil
  87. }
  88. log.Trace("Uninit annex at '%s'", path)
  89. if msg, err := annex.Uninit(path); err != nil {
  90. log.Error(3, "uninit failed: %v (%s)", err, msg)
  91. if werr := filepath.Walk(path, walker); werr != nil {
  92. log.Error(3, "file permission change failed: %v", werr)
  93. }
  94. }
  95. }
  96. func annexSetup(path string) {
  97. log.Trace("Running annex add (with filesize filter) in '%s'", path)
  98. // Initialise annex in case it's a new repository
  99. if msg, err := annex.Init(path); err != nil {
  100. log.Error(2, "Annex init failed: %v (%s)", err, msg)
  101. return
  102. }
  103. // Upgrade to v8 in case the directory was here before and wasn't cleaned up properly
  104. if msg, err := annex.Upgrade(path); err != nil {
  105. log.Error(2, "Annex upgrade failed: %v (%s)", err, msg)
  106. return
  107. }
  108. // Enable addunlocked for annex v8
  109. if msg, err := annex.SetAddUnlocked(path); err != nil {
  110. log.Error(2, "Failed to set 'addunlocked' annex option: %v (%s)", err, msg)
  111. }
  112. // Set MD5 as default backend
  113. if msg, err := annex.MD5(path); err != nil {
  114. log.Error(2, "Failed to set default backend to 'MD5': %v (%s)", err, msg)
  115. }
  116. // Set size filter in config
  117. if msg, err := annex.SetAnnexSizeFilter(path, conf.Repository.Upload.AnnexFileMinSize*annex.MEGABYTE); err != nil {
  118. log.Error(2, "Failed to set size filter for annex: %v (%s)", err, msg)
  119. }
  120. }
  121. func annexSync(path string) error {
  122. log.Trace("Synchronising annexed data")
  123. if msg, err := annex.ASync(path, "--content"); err != nil {
  124. // TODO: This will also DOWNLOAD content, which is unnecessary for a simple upload
  125. // TODO: Use gin-cli upload function instead
  126. log.Error(2, "Annex sync failed: %v (%s)", err, msg)
  127. return fmt.Errorf("git annex sync --content [%s]", path)
  128. }
  129. // run twice; required if remote annex is not initialised
  130. if msg, err := annex.ASync(path, "--content"); err != nil {
  131. log.Error(2, "Annex sync failed: %v (%s)", err, msg)
  132. return fmt.Errorf("git annex sync --content [%s]", path)
  133. }
  134. return nil
  135. }
  136. func annexAdd(repoPath string, all bool, files ...string) error {
  137. cmd := git.NewCommand("annex", "add")
  138. if all {
  139. cmd.AddArguments(".")
  140. }
  141. _, err := cmd.AddArguments(files...).RunInDir(repoPath)
  142. return err
  143. }
  144. func annexUpload(repoPath, remote string) error {
  145. log.Trace("Synchronising annex info")
  146. if msg, err := git.NewCommand("annex", "sync").RunInDir(repoPath); err != nil {
  147. log.Error(2, "git-annex sync failed: %v (%s)", err, msg)
  148. }
  149. log.Trace("Uploading annexed data")
  150. cmd := git.NewCommand("annex", "copy", fmt.Sprintf("--to=%s", remote), "--all")
  151. if msg, err := cmd.RunInDir(repoPath); err != nil {
  152. log.Error(2, "git-annex copy failed: %v (%s)", err, msg)
  153. return fmt.Errorf("git annex copy [%s]", repoPath)
  154. }
  155. return nil
  156. }
  157. // isAddressAllowed returns true if the email address is allowed to sign up
  158. // based on the regular expressions found in the email filter file
  159. // (custom/addressfilters).
  160. // In case of errors (opening or reading file) or no matches, the function
  161. // defaults to 'true'.
  162. func isAddressAllowed(email string) bool {
  163. fpath := filepath.Join(conf.CustomDir(), "addressfilters")
  164. if !com.IsExist(fpath) {
  165. // file doesn't exist: default allow everything
  166. return true
  167. }
  168. f, err := os.Open(fpath)
  169. if err != nil {
  170. log.Error(2, "Failed to open file %q: %v", fpath, err)
  171. // file read error: default allow everything
  172. return true
  173. }
  174. defer f.Close()
  175. emailBytes := []byte(email)
  176. scanner := bufio.NewScanner(f)
  177. for scanner.Scan() {
  178. // Check provided email address against each line regex
  179. // Failure to match any line returns true (allowed)
  180. // Matching a line prefixed with + returns true (allowed)
  181. // Matching a line prefixed with - returns false (blocked)
  182. // Erroneous patterns are logged and ignored
  183. var allow bool
  184. line := scanner.Text()
  185. if line[0] == '-' {
  186. allow = false
  187. } else if line[0] == '+' {
  188. allow = true
  189. } else {
  190. log.Error(2, "Invalid line in addressfilters: %s", line)
  191. log.Error(2, "Prefix invalid (must be '-' or '+')")
  192. continue
  193. }
  194. pattern := strings.TrimSpace(line[1:])
  195. match, err := regexp.Match(pattern, emailBytes)
  196. if err != nil {
  197. log.Error(2, "Invalid line in addressfilters: %s", line)
  198. log.Error(2, "Invalid pattern: %v", err)
  199. }
  200. if match {
  201. return allow
  202. }
  203. }
  204. // No match: Default to allow
  205. return true
  206. }
  207. func (u *User) OldGinVerifyPassword(plain string) bool {
  208. err := bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(plain))
  209. return err == nil
  210. }