gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package generic
  4. import (
  5. "errors"
  6. "net/http"
  7. "regexp"
  8. "strings"
  9. "unicode"
  10. packages_model "code.gitea.io/gitea/models/packages"
  11. packages_module "code.gitea.io/gitea/modules/packages"
  12. "code.gitea.io/gitea/routers/api/packages/helper"
  13. "code.gitea.io/gitea/services/context"
  14. packages_service "code.gitea.io/gitea/services/packages"
  15. )
  16. var (
  17. packageNameRegex = regexp.MustCompile(`\A[-_+.\w]+\z`)
  18. filenameRegex = regexp.MustCompile(`\A[-_+=:;.()\[\]{}~!@#$%^& \w]+\z`)
  19. )
  20. func apiError(ctx *context.Context, status int, obj any) {
  21. message := helper.ProcessErrorForUser(ctx, status, obj)
  22. ctx.PlainText(status, message)
  23. }
  24. // DownloadPackageFile serves the specific generic package.
  25. func DownloadPackageFile(ctx *context.Context) {
  26. s, u, pf, err := packages_service.OpenFileForDownloadByPackageNameAndVersion(
  27. ctx,
  28. &packages_service.PackageInfo{
  29. Owner: ctx.Package.Owner,
  30. PackageType: packages_model.TypeGeneric,
  31. Name: ctx.PathParam("packagename"),
  32. Version: ctx.PathParam("packageversion"),
  33. },
  34. &packages_service.PackageFileInfo{
  35. Filename: ctx.PathParam("filename"),
  36. },
  37. ctx.Req.Method,
  38. )
  39. if err != nil {
  40. if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
  41. apiError(ctx, http.StatusNotFound, err)
  42. return
  43. }
  44. apiError(ctx, http.StatusInternalServerError, err)
  45. return
  46. }
  47. helper.ServePackageFile(ctx, s, u, pf)
  48. }
  49. func isValidPackageName(packageName string) bool {
  50. if len(packageName) == 1 && !unicode.IsLetter(rune(packageName[0])) && !unicode.IsNumber(rune(packageName[0])) {
  51. return false
  52. }
  53. return packageNameRegex.MatchString(packageName) && packageName != ".."
  54. }
  55. func isValidFileName(filename string) bool {
  56. return filenameRegex.MatchString(filename) &&
  57. strings.TrimSpace(filename) == filename &&
  58. filename != "." && filename != ".."
  59. }
  60. // UploadPackage uploads the specific generic package.
  61. // Duplicated packages get rejected.
  62. func UploadPackage(ctx *context.Context) {
  63. packageName := ctx.PathParam("packagename")
  64. filename := ctx.PathParam("filename")
  65. if !isValidPackageName(packageName) {
  66. apiError(ctx, http.StatusBadRequest, errors.New("invalid package name"))
  67. return
  68. }
  69. if !isValidFileName(filename) {
  70. apiError(ctx, http.StatusBadRequest, errors.New("invalid filename"))
  71. return
  72. }
  73. packageVersion := ctx.PathParam("packageversion")
  74. if packageVersion != strings.TrimSpace(packageVersion) {
  75. apiError(ctx, http.StatusBadRequest, errors.New("invalid package version"))
  76. return
  77. }
  78. upload, needToClose, err := ctx.UploadStream()
  79. if err != nil {
  80. apiError(ctx, http.StatusInternalServerError, err)
  81. return
  82. }
  83. if needToClose {
  84. defer upload.Close()
  85. }
  86. buf, err := packages_module.CreateHashedBufferFromReader(upload)
  87. if err != nil {
  88. apiError(ctx, http.StatusInternalServerError, err)
  89. return
  90. }
  91. defer buf.Close()
  92. _, _, err = packages_service.CreatePackageOrAddFileToExisting(
  93. ctx,
  94. &packages_service.PackageCreationInfo{
  95. PackageInfo: packages_service.PackageInfo{
  96. Owner: ctx.Package.Owner,
  97. PackageType: packages_model.TypeGeneric,
  98. Name: packageName,
  99. Version: packageVersion,
  100. },
  101. Creator: ctx.Doer,
  102. },
  103. &packages_service.PackageFileCreationInfo{
  104. PackageFileInfo: packages_service.PackageFileInfo{
  105. Filename: filename,
  106. },
  107. Creator: ctx.Doer,
  108. Data: buf,
  109. IsLead: true,
  110. },
  111. )
  112. if err != nil {
  113. switch err {
  114. case packages_model.ErrDuplicatePackageFile:
  115. apiError(ctx, http.StatusConflict, err)
  116. case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
  117. apiError(ctx, http.StatusForbidden, err)
  118. default:
  119. apiError(ctx, http.StatusInternalServerError, err)
  120. }
  121. return
  122. }
  123. ctx.Status(http.StatusCreated)
  124. }
  125. // DeletePackage deletes the specific generic package.
  126. func DeletePackage(ctx *context.Context) {
  127. err := packages_service.RemovePackageVersionByNameAndVersion(
  128. ctx,
  129. ctx.Doer,
  130. &packages_service.PackageInfo{
  131. Owner: ctx.Package.Owner,
  132. PackageType: packages_model.TypeGeneric,
  133. Name: ctx.PathParam("packagename"),
  134. Version: ctx.PathParam("packageversion"),
  135. },
  136. )
  137. if err != nil {
  138. if errors.Is(err, packages_model.ErrPackageNotExist) {
  139. apiError(ctx, http.StatusNotFound, err)
  140. return
  141. }
  142. apiError(ctx, http.StatusInternalServerError, err)
  143. return
  144. }
  145. ctx.Status(http.StatusNoContent)
  146. }
  147. // DeletePackageFile deletes the specific file of a generic package.
  148. func DeletePackageFile(ctx *context.Context) {
  149. pv, pf, err := func() (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  150. pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeGeneric, ctx.PathParam("packagename"), ctx.PathParam("packageversion"))
  151. if err != nil {
  152. return nil, nil, err
  153. }
  154. pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.PathParam("filename"), packages_model.EmptyFileKey)
  155. if err != nil {
  156. return nil, nil, err
  157. }
  158. return pv, pf, nil
  159. }()
  160. if err != nil {
  161. if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, packages_model.ErrPackageFileNotExist) {
  162. apiError(ctx, http.StatusNotFound, err)
  163. return
  164. }
  165. apiError(ctx, http.StatusInternalServerError, err)
  166. return
  167. }
  168. pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
  169. if err != nil {
  170. apiError(ctx, http.StatusInternalServerError, err)
  171. return
  172. }
  173. if len(pfs) == 1 {
  174. if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil {
  175. apiError(ctx, http.StatusInternalServerError, err)
  176. return
  177. }
  178. } else {
  179. if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
  180. apiError(ctx, http.StatusInternalServerError, err)
  181. return
  182. }
  183. }
  184. ctx.Status(http.StatusNoContent)
  185. }