mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-25 17:44:32 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			295 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package setting
 | |
| 
 | |
| import (
 | |
| 	"regexp"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"code.gitea.io/gitea/modules/glob"
 | |
| 	"code.gitea.io/gitea/modules/log"
 | |
| 	"code.gitea.io/gitea/modules/structs"
 | |
| )
 | |
| 
 | |
| // enumerates all the types of captchas
 | |
| const (
 | |
| 	ImageCaptcha = "image"
 | |
| 	ReCaptcha    = "recaptcha"
 | |
| 	HCaptcha     = "hcaptcha"
 | |
| 	MCaptcha     = "mcaptcha"
 | |
| 	CfTurnstile  = "cfturnstile"
 | |
| )
 | |
| 
 | |
| // Service settings
 | |
| var Service = struct {
 | |
| 	DefaultUserVisibility                   string
 | |
| 	DefaultUserVisibilityMode               structs.VisibleType
 | |
| 	AllowedUserVisibilityModes              []string
 | |
| 	AllowedUserVisibilityModesSlice         AllowedVisibility `ini:"-"`
 | |
| 	DefaultOrgVisibility                    string
 | |
| 	DefaultOrgVisibilityMode                structs.VisibleType
 | |
| 	ActiveCodeLives                         int
 | |
| 	ResetPwdCodeLives                       int
 | |
| 	RegisterEmailConfirm                    bool
 | |
| 	RegisterManualConfirm                   bool
 | |
| 	EmailDomainAllowList                    []glob.Glob
 | |
| 	EmailDomainBlockList                    []glob.Glob
 | |
| 	DisableRegistration                     bool
 | |
| 	AllowOnlyInternalRegistration           bool
 | |
| 	AllowOnlyExternalRegistration           bool
 | |
| 	ShowRegistrationButton                  bool
 | |
| 	EnablePasswordSignInForm                bool
 | |
| 	ShowMilestonesDashboardPage             bool
 | |
| 	RequireSignInViewStrict                 bool
 | |
| 	BlockAnonymousAccessExpensive           bool
 | |
| 	EnableNotifyMail                        bool
 | |
| 	EnableBasicAuth                         bool
 | |
| 	EnablePasskeyAuth                       bool
 | |
| 	EnableReverseProxyAuth                  bool
 | |
| 	EnableReverseProxyAuthAPI               bool
 | |
| 	EnableReverseProxyAutoRegister          bool
 | |
| 	EnableReverseProxyEmail                 bool
 | |
| 	EnableReverseProxyFullName              bool
 | |
| 	EnableCaptcha                           bool
 | |
| 	RequireCaptchaForLogin                  bool
 | |
| 	RequireExternalRegistrationCaptcha      bool
 | |
| 	RequireExternalRegistrationPassword     bool
 | |
| 	CaptchaType                             string
 | |
| 	RecaptchaSecret                         string
 | |
| 	RecaptchaSitekey                        string
 | |
| 	RecaptchaURL                            string
 | |
| 	CfTurnstileSecret                       string
 | |
| 	CfTurnstileSitekey                      string
 | |
| 	HcaptchaSecret                          string
 | |
| 	HcaptchaSitekey                         string
 | |
| 	McaptchaSecret                          string
 | |
| 	McaptchaSitekey                         string
 | |
| 	McaptchaURL                             string
 | |
| 	DefaultKeepEmailPrivate                 bool
 | |
| 	DefaultAllowCreateOrganization          bool
 | |
| 	DefaultUserIsRestricted                 bool
 | |
| 	EnableTimetracking                      bool
 | |
| 	DefaultEnableTimetracking               bool
 | |
| 	DefaultEnableDependencies               bool
 | |
| 	AllowCrossRepositoryDependencies        bool
 | |
| 	DefaultAllowOnlyContributorsToTrackTime bool
 | |
| 	NoReplyAddress                          string
 | |
| 	UserLocationMapURL                      string
 | |
| 	EnableUserHeatmap                       bool
 | |
| 	AutoWatchNewRepos                       bool
 | |
| 	AutoWatchOnChanges                      bool
 | |
| 	DefaultOrgMemberVisible                 bool
 | |
| 	UserDeleteWithCommentsMaxTime           time.Duration
 | |
| 	ValidSiteURLSchemes                     []string
 | |
| 
 | |
| 	// OpenID settings
 | |
| 	EnableOpenIDSignIn bool
 | |
| 	EnableOpenIDSignUp bool
 | |
| 	OpenIDWhitelist    []*regexp.Regexp
 | |
| 	OpenIDBlacklist    []*regexp.Regexp
 | |
| 
 | |
| 	// Explore page settings
 | |
| 	Explore struct {
 | |
| 		RequireSigninView        bool `ini:"REQUIRE_SIGNIN_VIEW"`
 | |
| 		DisableUsersPage         bool `ini:"DISABLE_USERS_PAGE"`
 | |
| 		DisableOrganizationsPage bool `ini:"DISABLE_ORGANIZATIONS_PAGE"`
 | |
| 		DisableCodePage          bool `ini:"DISABLE_CODE_PAGE"`
 | |
| 	} `ini:"service.explore"`
 | |
| 
 | |
| 	QoS struct {
 | |
| 		Enabled             bool
 | |
| 		MaxInFlightRequests int
 | |
| 		MaxWaitingRequests  int
 | |
| 		TargetWaitTime      time.Duration
 | |
| 	}
 | |
| }{
 | |
| 	AllowedUserVisibilityModesSlice: []bool{true, true, true},
 | |
| }
 | |
| 
 | |
| // AllowedVisibility store in a 3 item bool array what is allowed
 | |
| type AllowedVisibility []bool
 | |
| 
 | |
| // IsAllowedVisibility check if a AllowedVisibility allow a specific VisibleType
 | |
| func (a AllowedVisibility) IsAllowedVisibility(t structs.VisibleType) bool {
 | |
| 	if int(t) >= len(a) {
 | |
| 		return false
 | |
| 	}
 | |
| 	return a[t]
 | |
| }
 | |
| 
 | |
| // ToVisibleTypeSlice convert a AllowedVisibility into a VisibleType slice
 | |
| func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) {
 | |
| 	for i, v := range a {
 | |
| 		if v {
 | |
| 			result = append(result, structs.VisibleType(i))
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func CompileEmailGlobList(sec ConfigSection, keys ...string) (globs []glob.Glob) {
 | |
| 	for _, key := range keys {
 | |
| 		list := sec.Key(key).Strings(",")
 | |
| 		for _, s := range list {
 | |
| 			if g, err := glob.Compile(s); err == nil {
 | |
| 				globs = append(globs, g)
 | |
| 			} else {
 | |
| 				log.Error("Skip invalid email allow/block list expression %q: %v", s, err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return globs
 | |
| }
 | |
| 
 | |
| func loadServiceFrom(rootCfg ConfigProvider) {
 | |
| 	sec := rootCfg.Section("service")
 | |
| 	Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
 | |
| 	Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
 | |
| 	Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
 | |
| 	Service.AllowOnlyInternalRegistration = sec.Key("ALLOW_ONLY_INTERNAL_REGISTRATION").MustBool()
 | |
| 	Service.AllowOnlyExternalRegistration = sec.Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").MustBool()
 | |
| 	if Service.AllowOnlyExternalRegistration && Service.AllowOnlyInternalRegistration {
 | |
| 		log.Warn("ALLOW_ONLY_INTERNAL_REGISTRATION and ALLOW_ONLY_EXTERNAL_REGISTRATION are true - disabling registration")
 | |
| 		Service.DisableRegistration = true
 | |
| 	}
 | |
| 	if !sec.Key("REGISTER_EMAIL_CONFIRM").MustBool() {
 | |
| 		Service.RegisterManualConfirm = sec.Key("REGISTER_MANUAL_CONFIRM").MustBool(false)
 | |
| 	} else {
 | |
| 		Service.RegisterManualConfirm = false
 | |
| 	}
 | |
| 	if sec.HasKey("EMAIL_DOMAIN_WHITELIST") {
 | |
| 		deprecatedSetting(rootCfg, "service", "EMAIL_DOMAIN_WHITELIST", "service", "EMAIL_DOMAIN_ALLOWLIST", "1.21")
 | |
| 	}
 | |
| 	Service.EmailDomainAllowList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST")
 | |
| 	Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST")
 | |
| 	Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
 | |
| 	Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
 | |
| 
 | |
| 	// boolean values are considered as "strict"
 | |
| 	var err error
 | |
| 	Service.RequireSignInViewStrict, err = sec.Key("REQUIRE_SIGNIN_VIEW").Bool()
 | |
| 	if s := sec.Key("REQUIRE_SIGNIN_VIEW").String(); err != nil && s != "" {
 | |
| 		// non-boolean value only supports "expensive" at the moment
 | |
| 		Service.BlockAnonymousAccessExpensive = s == "expensive"
 | |
| 		if !Service.BlockAnonymousAccessExpensive {
 | |
| 			log.Fatal("Invalid config option: REQUIRE_SIGNIN_VIEW = %s", s)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true)
 | |
| 	Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").MustBool(true)
 | |
| 	Service.EnablePasskeyAuth = sec.Key("ENABLE_PASSKEY_AUTHENTICATION").MustBool(true)
 | |
| 	Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
 | |
| 	Service.EnableReverseProxyAuthAPI = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool()
 | |
| 	Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
 | |
| 	Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool()
 | |
| 	Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool()
 | |
| 	Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false)
 | |
| 	Service.RequireCaptchaForLogin = sec.Key("REQUIRE_CAPTCHA_FOR_LOGIN").MustBool(false)
 | |
| 	Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha)
 | |
| 	Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool()
 | |
| 	Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha)
 | |
| 	Service.RecaptchaSecret = sec.Key("RECAPTCHA_SECRET").MustString("")
 | |
| 	Service.RecaptchaSitekey = sec.Key("RECAPTCHA_SITEKEY").MustString("")
 | |
| 	Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/")
 | |
| 	Service.CfTurnstileSecret = sec.Key("CF_TURNSTILE_SECRET").MustString("")
 | |
| 	Service.CfTurnstileSitekey = sec.Key("CF_TURNSTILE_SITEKEY").MustString("")
 | |
| 	Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("")
 | |
| 	Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("")
 | |
| 	Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/")
 | |
| 	Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("")
 | |
| 	Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("")
 | |
| 	Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool()
 | |
| 	Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true)
 | |
| 	Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false)
 | |
| 	Service.EnableTimetracking = sec.Key("ENABLE_TIMETRACKING").MustBool(true)
 | |
| 	if Service.EnableTimetracking {
 | |
| 		Service.DefaultEnableTimetracking = sec.Key("DEFAULT_ENABLE_TIMETRACKING").MustBool(true)
 | |
| 	}
 | |
| 	Service.DefaultEnableDependencies = sec.Key("DEFAULT_ENABLE_DEPENDENCIES").MustBool(true)
 | |
| 	Service.AllowCrossRepositoryDependencies = sec.Key("ALLOW_CROSS_REPOSITORY_DEPENDENCIES").MustBool(true)
 | |
| 	Service.DefaultAllowOnlyContributorsToTrackTime = sec.Key("DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME").MustBool(true)
 | |
| 	Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply." + Domain)
 | |
| 	Service.UserLocationMapURL = sec.Key("USER_LOCATION_MAP_URL").String()
 | |
| 	Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true)
 | |
| 	Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true)
 | |
| 	Service.AutoWatchOnChanges = sec.Key("AUTO_WATCH_ON_CHANGES").MustBool(false)
 | |
| 	modes := sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",")
 | |
| 	if len(modes) != 0 {
 | |
| 		Service.AllowedUserVisibilityModes = []string{}
 | |
| 		Service.AllowedUserVisibilityModesSlice = []bool{false, false, false}
 | |
| 		for _, sMode := range modes {
 | |
| 			if tp, ok := structs.VisibilityModes[sMode]; ok { // remove unsupported modes
 | |
| 				Service.AllowedUserVisibilityModes = append(Service.AllowedUserVisibilityModes, sMode)
 | |
| 				Service.AllowedUserVisibilityModesSlice[tp] = true
 | |
| 			} else {
 | |
| 				log.Warn("ALLOWED_USER_VISIBILITY_MODES %s is unsupported", sMode)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(Service.AllowedUserVisibilityModes) == 0 {
 | |
| 		Service.AllowedUserVisibilityModes = []string{"public", "limited", "private"}
 | |
| 		Service.AllowedUserVisibilityModesSlice = []bool{true, true, true}
 | |
| 	}
 | |
| 
 | |
| 	Service.DefaultUserVisibility = sec.Key("DEFAULT_USER_VISIBILITY").String()
 | |
| 	if Service.DefaultUserVisibility == "" {
 | |
| 		Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0]
 | |
| 	} else if !Service.AllowedUserVisibilityModesSlice[structs.VisibilityModes[Service.DefaultUserVisibility]] {
 | |
| 		log.Warn("DEFAULT_USER_VISIBILITY %s is wrong or not in ALLOWED_USER_VISIBILITY_MODES, using first allowed", Service.DefaultUserVisibility)
 | |
| 		Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0]
 | |
| 	}
 | |
| 	Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility]
 | |
| 	Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes))
 | |
| 	Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility]
 | |
| 	Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool()
 | |
| 	Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0)
 | |
| 	sec.Key("VALID_SITE_URL_SCHEMES").MustString("http,https")
 | |
| 	Service.ValidSiteURLSchemes = sec.Key("VALID_SITE_URL_SCHEMES").Strings(",")
 | |
| 	schemes := make([]string, 0, len(Service.ValidSiteURLSchemes))
 | |
| 	for _, scheme := range Service.ValidSiteURLSchemes {
 | |
| 		scheme = strings.ToLower(strings.TrimSpace(scheme))
 | |
| 		if scheme != "" {
 | |
| 			schemes = append(schemes, scheme)
 | |
| 		}
 | |
| 	}
 | |
| 	Service.ValidSiteURLSchemes = schemes
 | |
| 
 | |
| 	mustMapSetting(rootCfg, "service.explore", &Service.Explore)
 | |
| 
 | |
| 	loadOpenIDSetting(rootCfg)
 | |
| 	loadQosSetting(rootCfg)
 | |
| }
 | |
| 
 | |
| func loadOpenIDSetting(rootCfg ConfigProvider) {
 | |
| 	sec := rootCfg.Section("openid")
 | |
| 	Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock)
 | |
| 	Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn)
 | |
| 	pats := sec.Key("WHITELISTED_URIS").Strings(" ")
 | |
| 	if len(pats) != 0 {
 | |
| 		Service.OpenIDWhitelist = make([]*regexp.Regexp, len(pats))
 | |
| 		for i, p := range pats {
 | |
| 			Service.OpenIDWhitelist[i] = regexp.MustCompilePOSIX(p)
 | |
| 		}
 | |
| 	}
 | |
| 	pats = sec.Key("BLACKLISTED_URIS").Strings(" ")
 | |
| 	if len(pats) != 0 {
 | |
| 		Service.OpenIDBlacklist = make([]*regexp.Regexp, len(pats))
 | |
| 		for i, p := range pats {
 | |
| 			Service.OpenIDBlacklist[i] = regexp.MustCompilePOSIX(p)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func loadQosSetting(rootCfg ConfigProvider) {
 | |
| 	sec := rootCfg.Section("qos")
 | |
| 	Service.QoS.Enabled = sec.Key("ENABLED").MustBool(false)
 | |
| 	Service.QoS.MaxInFlightRequests = sec.Key("MAX_INFLIGHT").MustInt(4 * runtime.NumCPU())
 | |
| 	Service.QoS.MaxWaitingRequests = sec.Key("MAX_WAITING").MustInt(100)
 | |
| 	Service.QoS.TargetWaitTime = sec.Key("TARGET_WAIT_TIME").MustDuration(250 * time.Millisecond)
 | |
| }
 |