db_gin.go 7.2 KB

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