loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at forgejo 323 lines 14 kB view raw
1// Copyright 2019 The Gitea Authors. All rights reserved. 2// Copyright 2025 The Forgejo Authors. All rights reserved 3// SPDX-License-Identifier: MIT 4 5package setting 6 7import ( 8 "net/url" 9 "regexp" 10 "slices" 11 "strings" 12 "time" 13 14 "forgejo.org/modules/log" 15 "forgejo.org/modules/structs" 16 17 "github.com/gobwas/glob" 18) 19 20// enumerates all the types of captchas 21const ( 22 ImageCaptcha = "image" 23 ReCaptcha = "recaptcha" 24 HCaptcha = "hcaptcha" 25 MCaptcha = "mcaptcha" 26 CfTurnstile = "cfturnstile" 27) 28 29// Service settings 30var Service = struct { 31 DefaultUserVisibility string 32 DefaultUserVisibilityMode structs.VisibleType 33 AllowedUserVisibilityModes []string 34 AllowedUserVisibilityModesSlice AllowedVisibility `ini:"-"` 35 DefaultOrgVisibility string 36 DefaultOrgVisibilityMode structs.VisibleType 37 ActiveCodeLives int 38 ResetPwdCodeLives int 39 RegisterEmailConfirm bool 40 RegisterManualConfirm bool 41 EmailDomainAllowList []glob.Glob 42 EmailDomainBlockList []glob.Glob 43 EmailDomainBlockDisposable bool 44 DisableRegistration bool 45 AllowOnlyInternalRegistration bool 46 AllowOnlyExternalRegistration bool 47 ShowRegistrationButton bool 48 EnableInternalSignIn bool 49 ShowMilestonesDashboardPage bool 50 RequireSignInView bool 51 EnableNotifyMail bool 52 EnableBasicAuth bool 53 EnableReverseProxyAuth bool 54 EnableReverseProxyAuthAPI bool 55 EnableReverseProxyAutoRegister bool 56 EnableReverseProxyEmail bool 57 EnableReverseProxyFullName bool 58 EnableCaptcha bool 59 RequireCaptchaForLogin bool 60 RequireExternalRegistrationCaptcha bool 61 RequireExternalRegistrationPassword bool 62 CaptchaType string 63 RecaptchaSecret string 64 RecaptchaSitekey string 65 RecaptchaURL string 66 CfTurnstileSecret string 67 CfTurnstileSitekey string 68 HcaptchaSecret string 69 HcaptchaSitekey string 70 McaptchaSecret string 71 McaptchaSitekey string 72 McaptchaURL string 73 DefaultKeepEmailPrivate bool 74 DefaultAllowCreateOrganization bool 75 DefaultUserIsRestricted bool 76 AllowDotsInUsernames bool 77 EnableTimetracking bool 78 DefaultEnableTimetracking bool 79 DefaultEnableDependencies bool 80 AllowCrossRepositoryDependencies bool 81 DefaultAllowOnlyContributorsToTrackTime bool 82 NoReplyAddress string 83 UserLocationMapURL string 84 EnableUserHeatmap bool 85 AutoWatchNewRepos bool 86 AutoWatchOnChanges bool 87 DefaultOrgMemberVisible bool 88 UserDeleteWithCommentsMaxTime time.Duration 89 ValidSiteURLSchemes []string 90 UsernameCooldownPeriod int64 91 MaxUserRedirects int64 92 93 // OpenID settings 94 EnableOpenIDSignIn bool 95 EnableOpenIDSignUp bool 96 OpenIDWhitelist []*regexp.Regexp 97 OpenIDBlacklist []*regexp.Regexp 98 99 // Explore page settings 100 Explore struct { 101 RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` 102 DisableUsersPage bool `ini:"DISABLE_USERS_PAGE"` 103 DisableOrganizationsPage bool `ini:"DISABLE_ORGANIZATIONS_PAGE"` 104 DisableCodePage bool `ini:"DISABLE_CODE_PAGE"` 105 } `ini:"service.explore"` 106}{ 107 AllowedUserVisibilityModesSlice: []bool{true, true, true}, 108} 109 110// AllowedVisibility store in a 3 item bool array what is allowed 111type AllowedVisibility []bool 112 113// IsAllowedVisibility check if a AllowedVisibility allow a specific VisibleType 114func (a AllowedVisibility) IsAllowedVisibility(t structs.VisibleType) bool { 115 if int(t) >= len(a) { 116 return false 117 } 118 return a[t] 119} 120 121// ToVisibleTypeSlice convert a AllowedVisibility into a VisibleType slice 122func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) { 123 for i, v := range a { 124 if v { 125 result = append(result, structs.VisibleType(i)) 126 } 127 } 128 return result 129} 130 131func CompileEmailGlobList(sec ConfigSection, keys ...string) (globs []glob.Glob) { 132 for _, key := range keys { 133 list := sec.Key(key).Strings(",") 134 for _, s := range list { 135 if g, err := glob.Compile(s); err == nil { 136 globs = append(globs, g) 137 } else { 138 log.Error("Skip invalid email allow/block list expression %q: %v", s, err) 139 } 140 } 141 } 142 return globs 143} 144 145// LoadServiceSetting loads the service settings 146func LoadServiceSetting() { 147 loadServiceFrom(CfgProvider) 148} 149 150func appURLAsGlob(fqdn string) (glob.Glob, error) { 151 localFqdn, err := url.ParseRequestURI(fqdn) 152 if err != nil { 153 log.Error("Error in EmailDomainAllowList: %v", err) 154 return nil, err 155 } 156 appFqdn, err := glob.Compile(localFqdn.Hostname(), ',') 157 if err != nil { 158 log.Error("Error in EmailDomainAllowList: %v", err) 159 return nil, err 160 } 161 return appFqdn, nil 162} 163 164func loadServiceFrom(rootCfg ConfigProvider) { 165 sec := rootCfg.Section("service") 166 Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) 167 Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) 168 Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool() 169 Service.AllowOnlyInternalRegistration = sec.Key("ALLOW_ONLY_INTERNAL_REGISTRATION").MustBool() 170 Service.AllowOnlyExternalRegistration = sec.Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").MustBool() 171 if Service.AllowOnlyExternalRegistration && Service.AllowOnlyInternalRegistration { 172 log.Warn("ALLOW_ONLY_INTERNAL_REGISTRATION and ALLOW_ONLY_EXTERNAL_REGISTRATION are true - disabling registration") 173 Service.DisableRegistration = true 174 } 175 if !sec.Key("REGISTER_EMAIL_CONFIRM").MustBool() { 176 Service.RegisterManualConfirm = sec.Key("REGISTER_MANUAL_CONFIRM").MustBool(false) 177 } else { 178 Service.RegisterManualConfirm = false 179 } 180 if sec.HasKey("EMAIL_DOMAIN_WHITELIST") { 181 deprecatedSetting(rootCfg, "service", "EMAIL_DOMAIN_WHITELIST", "service", "EMAIL_DOMAIN_ALLOWLIST", "1.21") 182 } 183 emailDomainAllowList := CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST") 184 185 if len(emailDomainAllowList) > 0 && Federation.Enabled { 186 appURL, err := appURLAsGlob(AppURL) 187 if err == nil { 188 emailDomainAllowList = append(emailDomainAllowList, appURL) 189 } 190 } 191 Service.EmailDomainAllowList = emailDomainAllowList 192 Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST") 193 Service.EmailDomainBlockDisposable = sec.Key("EMAIL_DOMAIN_BLOCK_DISPOSABLE").MustBool(false) 194 if Service.EmailDomainBlockDisposable { 195 toAdd := make([]glob.Glob, 0, len(DisposableEmailDomains())) 196 for _, domain := range DisposableEmailDomains() { 197 domain = strings.ToLower(domain) 198 // Only add domains that aren't blocked yet. 199 if !slices.ContainsFunc(Service.EmailDomainBlockList, func(g glob.Glob) bool { return g.Match(domain) }) { 200 if g, err := glob.Compile(domain); err != nil { 201 log.Error("Error in disposable domain %s: %v", domain, err) 202 } else { 203 toAdd = append(toAdd, g) 204 } 205 } 206 } 207 Service.EmailDomainBlockList = append(Service.EmailDomainBlockList, toAdd...) 208 } 209 Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration && !Service.AllowOnlyExternalRegistration) 210 Service.EnableInternalSignIn = sec.Key("ENABLE_INTERNAL_SIGNIN").MustBool(true) 211 Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true) 212 Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() 213 Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true) 214 Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() 215 Service.EnableReverseProxyAuthAPI = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool() 216 Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() 217 Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() 218 Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool() 219 Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false) 220 Service.RequireCaptchaForLogin = sec.Key("REQUIRE_CAPTCHA_FOR_LOGIN").MustBool(false) 221 Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha) 222 Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool() 223 Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha) 224 Service.RecaptchaSecret = sec.Key("RECAPTCHA_SECRET").MustString("") 225 Service.RecaptchaSitekey = sec.Key("RECAPTCHA_SITEKEY").MustString("") 226 Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/") 227 Service.CfTurnstileSecret = sec.Key("CF_TURNSTILE_SECRET").MustString("") 228 Service.CfTurnstileSitekey = sec.Key("CF_TURNSTILE_SITEKEY").MustString("") 229 Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("") 230 Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("") 231 Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/") 232 Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("") 233 Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("") 234 Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool() 235 Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true) 236 Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false) 237 Service.AllowDotsInUsernames = sec.Key("ALLOW_DOTS_IN_USERNAMES").MustBool(true) 238 Service.EnableTimetracking = sec.Key("ENABLE_TIMETRACKING").MustBool(true) 239 if Service.EnableTimetracking { 240 Service.DefaultEnableTimetracking = sec.Key("DEFAULT_ENABLE_TIMETRACKING").MustBool(true) 241 } 242 Service.DefaultEnableDependencies = sec.Key("DEFAULT_ENABLE_DEPENDENCIES").MustBool(true) 243 Service.AllowCrossRepositoryDependencies = sec.Key("ALLOW_CROSS_REPOSITORY_DEPENDENCIES").MustBool(true) 244 Service.DefaultAllowOnlyContributorsToTrackTime = sec.Key("DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME").MustBool(true) 245 Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply." + Domain) 246 Service.UserLocationMapURL = sec.Key("USER_LOCATION_MAP_URL").MustString("https://www.openstreetmap.org/search?query=") 247 Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true) 248 Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true) 249 Service.AutoWatchOnChanges = sec.Key("AUTO_WATCH_ON_CHANGES").MustBool(false) 250 modes := sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",") 251 if len(modes) != 0 { 252 Service.AllowedUserVisibilityModes = []string{} 253 Service.AllowedUserVisibilityModesSlice = []bool{false, false, false} 254 for _, sMode := range modes { 255 if tp, ok := structs.VisibilityModes[sMode]; ok { // remove unsupported modes 256 Service.AllowedUserVisibilityModes = append(Service.AllowedUserVisibilityModes, sMode) 257 Service.AllowedUserVisibilityModesSlice[tp] = true 258 } else { 259 log.Warn("ALLOWED_USER_VISIBILITY_MODES %s is unsupported", sMode) 260 } 261 } 262 } 263 264 if len(Service.AllowedUserVisibilityModes) == 0 { 265 Service.AllowedUserVisibilityModes = []string{"public", "limited", "private"} 266 Service.AllowedUserVisibilityModesSlice = []bool{true, true, true} 267 } 268 269 Service.DefaultUserVisibility = sec.Key("DEFAULT_USER_VISIBILITY").String() 270 if Service.DefaultUserVisibility == "" { 271 Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0] 272 } else if !Service.AllowedUserVisibilityModesSlice[structs.VisibilityModes[Service.DefaultUserVisibility]] { 273 log.Warn("DEFAULT_USER_VISIBILITY %s is wrong or not in ALLOWED_USER_VISIBILITY_MODES, using first allowed", Service.DefaultUserVisibility) 274 Service.DefaultUserVisibility = Service.AllowedUserVisibilityModes[0] 275 } 276 Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility] 277 Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) 278 Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] 279 Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool() 280 Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0) 281 sec.Key("VALID_SITE_URL_SCHEMES").MustString("http,https") 282 Service.ValidSiteURLSchemes = sec.Key("VALID_SITE_URL_SCHEMES").Strings(",") 283 schemes := make([]string, 0, len(Service.ValidSiteURLSchemes)) 284 for _, scheme := range Service.ValidSiteURLSchemes { 285 scheme = strings.ToLower(strings.TrimSpace(scheme)) 286 if scheme != "" { 287 schemes = append(schemes, scheme) 288 } 289 } 290 Service.ValidSiteURLSchemes = schemes 291 Service.UsernameCooldownPeriod = sec.Key("USERNAME_COOLDOWN_PERIOD").MustInt64(0) 292 293 // Only set a default if USERNAME_COOLDOWN_PERIOD's feature is active. 294 maxUserRedirectsDefault := int64(0) 295 if Service.UsernameCooldownPeriod > 0 { 296 maxUserRedirectsDefault = 5 297 } 298 Service.MaxUserRedirects = sec.Key("MAX_USER_REDIRECTS").MustInt64(maxUserRedirectsDefault) 299 300 mustMapSetting(rootCfg, "service.explore", &Service.Explore) 301 302 loadOpenIDSetting(rootCfg) 303} 304 305func loadOpenIDSetting(rootCfg ConfigProvider) { 306 sec := rootCfg.Section("openid") 307 Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock) 308 Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn) 309 pats := sec.Key("WHITELISTED_URIS").Strings(" ") 310 if len(pats) != 0 { 311 Service.OpenIDWhitelist = make([]*regexp.Regexp, len(pats)) 312 for i, p := range pats { 313 Service.OpenIDWhitelist[i] = regexp.MustCompilePOSIX(p) 314 } 315 } 316 pats = sec.Key("BLACKLISTED_URIS").Strings(" ") 317 if len(pats) != 0 { 318 Service.OpenIDBlacklist = make([]*regexp.Regexp, len(pats)) 319 for i, p := range pats { 320 Service.OpenIDBlacklist[i] = regexp.MustCompilePOSIX(p) 321 } 322 } 323}