mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 14:31:02 +00:00 
			
		
		
		
	Refs: https://codeberg.org/forgejo/forgejo/pulls/676 Author: Panagiotis "Ivory" Vasilopoulos <git@n0toose.net> Date: Mon Jun 12 13:57:01 2023 +0200 Co-authored-by: Gusted <postmaster@gusted.xyz> (cherry picked from commitfabdda5c6e) (cherry picked from commitd2c7f45621) (cherry picked from commitdfdbaba3d6) (cherry picked from commita3cda092b8) (cherry picked from commitf0fdb5905c) (cherry picked from commit9697e48c1f) (cherry picked from commit46e31009a8) (cherry picked from commit5bb2c54b6f) (cherry picked from commit682f9d24e1) (cherry picked from commit1863481005) (cherry picked from commit4f1b7c4ddb) (cherry picked from commit6afe70bbf1) (cherry picked from commit5cec1d9c2d) Conflicts: templates/admin/config.tmpl https://codeberg.org/forgejo/forgejo/pulls/1512 (cherry picked from commitde2d172473) (cherry picked from commit37a3172dd9) (cherry picked from commit92dfca0c5a) (cherry picked from commita713d59b0c) (cherry picked from commitbf18b10982) (cherry picked from commit11d77f40a1) (cherry picked from commit17ca5ff2d6) (cherry picked from commitfc50a7f74e)
		
			
				
	
	
		
			262 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package setting
 | |
| 
 | |
| import (
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"code.gitea.io/gitea/modules/log"
 | |
| 	"code.gitea.io/gitea/modules/structs"
 | |
| 
 | |
| 	"github.com/gobwas/glob"
 | |
| )
 | |
| 
 | |
| // 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
 | |
| 	ShowMilestonesDashboardPage             bool
 | |
| 	RequireSignInView                       bool
 | |
| 	EnableNotifyMail                        bool
 | |
| 	EnableBasicAuth                         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
 | |
| 	AllowDotsInUsernames                    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"`
 | |
| 	} `ini:"service.explore"`
 | |
| }{
 | |
| 	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)
 | |
| 	Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
 | |
| 	Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_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.AllowDotsInUsernames = sec.Key("ALLOW_DOTS_IN_USERNAMES").MustBool(true)
 | |
| 	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").MustString("https://www.openstreetmap.org/search?query=")
 | |
| 	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)
 | |
| }
 | |
| 
 | |
| 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)
 | |
| 		}
 | |
| 	}
 | |
| }
 |