code.gitea.io/gitea@v1.22.3/modules/validation/helpers.go (about)

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