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