2018-08-15 09:29:37 +03:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2018-08-15 09:29:37 +03:00
package validation
import (
"net"
"net/url"
2019-05-31 12:21:15 +03:00
"regexp"
2018-08-15 09:29:37 +03:00
"strings"
"code.gitea.io/gitea/modules/setting"
2023-08-30 18:46:49 +03:00
"github.com/gobwas/glob"
2018-08-15 09:29:37 +03:00
)
2019-05-31 12:21:15 +03:00
var externalTrackerRegex = regexp . MustCompile ( ` ( { ?)(?:user|repo|index)+?(}?) ` )
2018-08-15 09:29:37 +03:00
func isLoopbackIP ( ip string ) bool {
2022-04-25 08:55:12 +03:00
return net . ParseIP ( ip ) . IsLoopback ( )
2018-08-15 09:29:37 +03:00
}
// IsValidURL checks if URL is valid
func IsValidURL ( uri string ) bool {
if u , err := url . ParseRequestURI ( uri ) ; err != nil ||
( u . Scheme != "http" && u . Scheme != "https" ) ||
! validPort ( portOnly ( u . Host ) ) {
return false
}
return true
}
2021-06-26 01:38:27 +03:00
// IsValidSiteURL checks if URL is valid
func IsValidSiteURL ( uri string ) bool {
u , err := url . ParseRequestURI ( uri )
if err != nil {
return false
}
if ! validPort ( portOnly ( u . Host ) ) {
return false
}
for _ , scheme := range setting . Service . ValidSiteURLSchemes {
if scheme == u . Scheme {
return true
}
}
return false
}
2023-08-30 18:46:49 +03:00
// IsEmailDomainListed checks whether the domain of an email address
// matches a list of domains
func IsEmailDomainListed ( globs [ ] glob . Glob , email string ) bool {
if len ( globs ) == 0 {
return false
}
n := strings . LastIndex ( email , "@" )
if n <= 0 {
return false
}
domain := strings . ToLower ( email [ n + 1 : ] )
for _ , g := range globs {
if g . Match ( domain ) {
return true
}
}
return false
}
2018-08-15 09:29:37 +03:00
// IsAPIURL checks if URL is current Gitea instance API URL
func IsAPIURL ( uri string ) bool {
return strings . HasPrefix ( strings . ToLower ( uri ) , strings . ToLower ( setting . AppURL + "api" ) )
}
// IsValidExternalURL checks if URL is valid external URL
func IsValidExternalURL ( uri string ) bool {
if ! IsValidURL ( uri ) || IsAPIURL ( uri ) {
return false
}
u , err := url . ParseRequestURI ( uri )
if err != nil {
return false
}
// Currently check only if not loopback IP is provided to keep compatibility
if isLoopbackIP ( u . Hostname ( ) ) || strings . ToLower ( u . Hostname ( ) ) == "localhost" {
return false
}
2021-07-08 14:38:13 +03:00
// TODO: Later it should be added to allow local network IP addresses
2018-08-15 09:29:37 +03:00
// only if allowed by special setting
return true
}
2019-05-31 12:21:15 +03:00
// IsValidExternalTrackerURLFormat checks if URL matches required syntax for external trackers
func IsValidExternalTrackerURLFormat ( uri string ) bool {
if ! IsValidExternalURL ( uri ) {
return false
}
// check for typoed variables like /{index/ or /[repo}
for _ , match := range externalTrackerRegex . FindAllStringSubmatch ( uri , - 1 ) {
if ( match [ 1 ] == "{" || match [ 2 ] == "}" ) && ( match [ 1 ] != "{" || match [ 2 ] != "}" ) {
return false
}
}
return true
}
2022-11-04 12:04:08 +03:00
var (
validUsernamePattern = regexp . MustCompile ( ` ^[\da-zA-Z][-.\w]*$ ` )
invalidUsernamePattern = regexp . MustCompile ( ` [-._] { 2,}|[-._]$ ` ) // No consecutive or trailing non-alphanumeric chars
)
// IsValidUsername checks if username is valid
func IsValidUsername ( name string ) bool {
// It is difficult to find a single pattern that is both readable and effective,
// but it's easier to use positive and negative checks.
return validUsernamePattern . MatchString ( name ) && ! invalidUsernamePattern . MatchString ( name )
}