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.

helpers.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2018 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package validation
  4. import (
  5. "net"
  6. "net/url"
  7. "regexp"
  8. "strings"
  9. "code.gitea.io/gitea/modules/setting"
  10. "github.com/gobwas/glob"
  11. )
  12. var externalTrackerRegex = regexp.MustCompile(`({?)(?:user|repo|index)+?(}?)`)
  13. func isLoopbackIP(ip string) bool {
  14. return net.ParseIP(ip).IsLoopback()
  15. }
  16. // IsValidURL checks if URL is valid
  17. func IsValidURL(uri string) bool {
  18. if u, err := url.ParseRequestURI(uri); err != nil ||
  19. (u.Scheme != "http" && u.Scheme != "https") ||
  20. !validPort(portOnly(u.Host)) {
  21. return false
  22. }
  23. return true
  24. }
  25. // IsValidSiteURL checks if URL is valid
  26. func IsValidSiteURL(uri string) bool {
  27. u, err := url.ParseRequestURI(uri)
  28. if err != nil {
  29. return false
  30. }
  31. if !validPort(portOnly(u.Host)) {
  32. return false
  33. }
  34. for _, scheme := range setting.Service.ValidSiteURLSchemes {
  35. if scheme == u.Scheme {
  36. return true
  37. }
  38. }
  39. return false
  40. }
  41. // IsEmailDomainListed checks whether the domain of an email address
  42. // matches a list of domains
  43. func IsEmailDomainListed(globs []glob.Glob, email string) bool {
  44. if len(globs) == 0 {
  45. return false
  46. }
  47. n := strings.LastIndex(email, "@")
  48. if n <= 0 {
  49. return false
  50. }
  51. domain := strings.ToLower(email[n+1:])
  52. for _, g := range globs {
  53. if g.Match(domain) {
  54. return true
  55. }
  56. }
  57. return false
  58. }
  59. // IsAPIURL checks if URL is current Gitea instance API URL
  60. func IsAPIURL(uri string) bool {
  61. return strings.HasPrefix(strings.ToLower(uri), strings.ToLower(setting.AppURL+"api"))
  62. }
  63. // IsValidExternalURL checks if URL is valid external URL
  64. func IsValidExternalURL(uri string) bool {
  65. if !IsValidURL(uri) || IsAPIURL(uri) {
  66. return false
  67. }
  68. u, err := url.ParseRequestURI(uri)
  69. if err != nil {
  70. return false
  71. }
  72. // Currently check only if not loopback IP is provided to keep compatibility
  73. if isLoopbackIP(u.Hostname()) || strings.ToLower(u.Hostname()) == "localhost" {
  74. return false
  75. }
  76. // TODO: Later it should be added to allow local network IP addresses
  77. // only if allowed by special setting
  78. return true
  79. }
  80. // IsValidExternalTrackerURLFormat checks if URL matches required syntax for external trackers
  81. func IsValidExternalTrackerURLFormat(uri string) bool {
  82. if !IsValidExternalURL(uri) {
  83. return false
  84. }
  85. // check for typoed variables like /{index/ or /[repo}
  86. for _, match := range externalTrackerRegex.FindAllStringSubmatch(uri, -1) {
  87. if (match[1] == "{" || match[2] == "}") && (match[1] != "{" || match[2] != "}") {
  88. return false
  89. }
  90. }
  91. return true
  92. }
  93. var (
  94. validUsernamePattern = regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`)
  95. invalidUsernamePattern = regexp.MustCompile(`[-._]{2,}|[-._]$`) // No consecutive or trailing non-alphanumeric chars
  96. )
  97. // IsValidUsername checks if username is valid
  98. func IsValidUsername(name string) bool {
  99. // It is difficult to find a single pattern that is both readable and effective,
  100. // but it's easier to use positive and negative checks.
  101. return validUsernamePattern.MatchString(name) && !invalidUsernamePattern.MatchString(name)
  102. }