[GITEA] add option for banning dots in usernames
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)
This commit is contained in:
		
							parent
							
								
									66e1d3f082
								
							
						
					
					
						commit
						a3cda092b8
					
				
					 7 changed files with 57 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -801,6 +801,11 @@ LEVEL = Info
 | 
			
		|||
;; Every new user will have restricted permissions depending on this setting
 | 
			
		||||
;DEFAULT_USER_IS_RESTRICTED = false
 | 
			
		||||
;;
 | 
			
		||||
;; Users will be able to use dots when choosing their username. Disabling this is
 | 
			
		||||
;; helpful if your usersare having issues with e.g. RSS feeds or advanced third-party
 | 
			
		||||
;; extensions that use strange regex patterns.
 | 
			
		||||
; ALLOW_DOTS_IN_USERNAMES = true
 | 
			
		||||
;;
 | 
			
		||||
;; Either "public", "limited" or "private", default is "public"
 | 
			
		||||
;; Limited is for users visible only to signed users
 | 
			
		||||
;; Private is for users visible only to members of their organizations
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,7 @@ var Service = struct {
 | 
			
		|||
	DefaultKeepEmailPrivate                 bool
 | 
			
		||||
	DefaultAllowCreateOrganization          bool
 | 
			
		||||
	DefaultUserIsRestricted                 bool
 | 
			
		||||
	AllowDotsInUsernames                    bool
 | 
			
		||||
	EnableTimetracking                      bool
 | 
			
		||||
	DefaultEnableTimetracking               bool
 | 
			
		||||
	DefaultEnableDependencies               bool
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +178,7 @@ func loadServiceFrom(rootCfg ConfigProvider) {
 | 
			
		|||
	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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,13 +92,20 @@ func IsValidExternalTrackerURLFormat(uri string) bool {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	validUsernamePattern   = regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`)
 | 
			
		||||
	invalidUsernamePattern = regexp.MustCompile(`[-._]{2,}|[-._]$`) // No consecutive or trailing non-alphanumeric chars
 | 
			
		||||
	validUsernamePatternWithDots    = regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`)
 | 
			
		||||
	validUsernamePatternWithoutDots = regexp.MustCompile(`^[\da-zA-Z][-\w]*$`)
 | 
			
		||||
 | 
			
		||||
	// No consecutive or trailing non-alphanumeric chars, catches both cases
 | 
			
		||||
	invalidUsernamePattern = regexp.MustCompile(`[-._]{2,}|[-._]$`)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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)
 | 
			
		||||
	if setting.Service.AllowDotsInUsernames {
 | 
			
		||||
		return validUsernamePatternWithDots.MatchString(name) && !invalidUsernamePattern.MatchString(name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return validUsernamePatternWithoutDots.MatchString(name) && !invalidUsernamePattern.MatchString(name)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,7 +155,8 @@ func Test_IsValidExternalTrackerURLFormat(t *testing.T) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsValidUsername(t *testing.T) {
 | 
			
		||||
func TestIsValidUsernameAllowDots(t *testing.T) {
 | 
			
		||||
	setting.Service.AllowDotsInUsernames = true
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		arg  string
 | 
			
		||||
		want bool
 | 
			
		||||
| 
						 | 
				
			
			@ -185,3 +186,31 @@ func TestIsValidUsername(t *testing.T) {
 | 
			
		|||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsValidUsernameBanDots(t *testing.T) {
 | 
			
		||||
	setting.Service.AllowDotsInUsernames = false
 | 
			
		||||
	defer func() {
 | 
			
		||||
		setting.Service.AllowDotsInUsernames = true
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		arg  string
 | 
			
		||||
		want bool
 | 
			
		||||
	}{
 | 
			
		||||
		{arg: "a", want: true},
 | 
			
		||||
		{arg: "abc", want: true},
 | 
			
		||||
		{arg: "0.b-c", want: false},
 | 
			
		||||
		{arg: "a.b-c_d", want: false},
 | 
			
		||||
		{arg: ".abc", want: false},
 | 
			
		||||
		{arg: "abc.", want: false},
 | 
			
		||||
		{arg: "a..bc", want: false},
 | 
			
		||||
		{arg: "a...bc", want: false},
 | 
			
		||||
		{arg: "a.-bc", want: false},
 | 
			
		||||
		{arg: "a._bc", want: false},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.arg, func(t *testing.T) {
 | 
			
		||||
			assert.Equalf(t, tt.want, IsValidUsername(tt.arg), "IsValidUsername[AllowDotsInUsernames=false](%v)", tt.arg)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/translation"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
	"code.gitea.io/gitea/modules/validation"
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +136,11 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
 | 
			
		|||
			case validation.ErrRegexPattern:
 | 
			
		||||
				data["ErrorMsg"] = trName + l.Tr("form.regex_pattern_error", errs[0].Message)
 | 
			
		||||
			case validation.ErrUsername:
 | 
			
		||||
				data["ErrorMsg"] = trName + l.Tr("form.username_error")
 | 
			
		||||
				if setting.Service.AllowDotsInUsernames {
 | 
			
		||||
					data["ErrorMsg"] = trName + l.Tr("form.username_error")
 | 
			
		||||
				} else {
 | 
			
		||||
					data["ErrorMsg"] = trName + l.Tr("form.username_error_no_dots")
 | 
			
		||||
				}
 | 
			
		||||
			case validation.ErrInvalidGroupTeamMap:
 | 
			
		||||
				data["ErrorMsg"] = trName + l.Tr("form.invalid_group_team_map_error", errs[0].Message)
 | 
			
		||||
			default:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -289,6 +289,7 @@ default_allow_create_organization = Allow Creation of Organizations by Default
 | 
			
		|||
default_allow_create_organization_popup = Allow new user accounts to create organizations by default.
 | 
			
		||||
default_enable_timetracking = Enable Time Tracking by Default
 | 
			
		||||
default_enable_timetracking_popup = Enable time tracking for new repositories by default.
 | 
			
		||||
allow_dots_in_usernames = Allow users to use dots in their usernames. Doesn't affect existing accounts.
 | 
			
		||||
no_reply_address = Hidden Email Domain
 | 
			
		||||
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
 | 
			
		||||
password_algorithm = Password Hash Algorithm
 | 
			
		||||
| 
						 | 
				
			
			@ -527,6 +528,7 @@ include_error = ` must contain substring "%s".`
 | 
			
		|||
glob_pattern_error = ` glob pattern is invalid: %s.`
 | 
			
		||||
regex_pattern_error = ` regex pattern is invalid: %s.`
 | 
			
		||||
username_error = ` can only contain alphanumeric chars ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric chars, and consecutive non-alphanumeric chars are also forbidden.`
 | 
			
		||||
username_error_no_dots = ` can only contain alphanumeric chars ('0-9','a-z','A-Z'), dash ('-') and underscore ('_'). It cannot begin or end with non-alphanumeric chars, and consecutive non-alphanumeric chars are also forbidden.`
 | 
			
		||||
invalid_group_team_map_error = ` mapping is invalid: %s`
 | 
			
		||||
unknown_error = Unknown error:
 | 
			
		||||
captcha_incorrect = The CAPTCHA code is incorrect.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,6 +159,8 @@
 | 
			
		|||
				<dd>{{if .Service.DefaultKeepEmailPrivate}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
 | 
			
		||||
				<dt>{{.locale.Tr "admin.config.default_allow_create_organization"}}</dt>
 | 
			
		||||
				<dd>{{if .Service.DefaultAllowCreateOrganization}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
 | 
			
		||||
				<dt>{{.locale.Tr "admin.config.allow_dots_in_usernames"}}</dt>
 | 
			
		||||
				<dd>{{if .Service.AllowDotsInUsernames}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
 | 
			
		||||
				<dt>{{.locale.Tr "admin.config.enable_timetracking"}}</dt>
 | 
			
		||||
				<dd>{{if .Service.EnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
 | 
			
		||||
				{{if .Service.EnableTimetracking}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue