Browse Source

fix #749

tags/v2.1.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
26fd3e69a8
11 changed files with 208 additions and 95 deletions
  1. 14
    10
      irc/accounts.go
  2. 49
    26
      irc/client_lookup_set.go
  3. 58
    14
      irc/config.go
  4. 2
    2
      irc/errors.go
  5. 0
    4
      irc/getters.go
  6. 2
    2
      irc/handlers.go
  7. 4
    4
      irc/hostserv.go
  8. 13
    20
      irc/nickname.go
  9. 43
    10
      irc/nickserv.go
  10. 5
    1
      irc/strings.go
  11. 18
    2
      oragono.yaml

+ 14
- 10
irc/accounts.go View File

@@ -337,24 +337,28 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
337 337
 		return errAccountAlreadyRegistered
338 338
 	}
339 339
 
340
-	config := am.server.AccountConfig()
340
+	config := am.server.Config()
341 341
 
342 342
 	// final "is registration allowed" check, probably redundant:
343
-	if !(config.Registration.Enabled || callbackNamespace == "admin") {
343
+	if !(config.Accounts.Registration.Enabled || callbackNamespace == "admin") {
344 344
 		return errFeatureDisabled
345 345
 	}
346 346
 
347 347
 	// if nick reservation is enabled, you can only register your current nickname
348 348
 	// as an account; this prevents "land-grab" situations where someone else
349 349
 	// registers your nick out from under you and then NS GHOSTs you
350
-	// n.b. client is nil during a SAREGISTER:
351
-	if config.NickReservation.Enabled && client != nil && client.NickCasefolded() != casefoldedAccount {
350
+	// n.b. client is nil during a SAREGISTER
351
+	// n.b. if EnforceGuestFormat, then there's no concern, because you can't
352
+	// register a guest nickname anyway, and the actual registration system
353
+	// will prevent any double-register
354
+	if client != nil && config.Accounts.NickReservation.Enabled &&
355
+		!config.Accounts.NickReservation.EnforceGuestFormat &&
356
+		client.NickCasefolded() != casefoldedAccount {
352 357
 		return errAccountMustHoldNick
353 358
 	}
354 359
 
355 360
 	// can't register a guest nickname
356
-	renamePrefix := strings.ToLower(config.NickReservation.RenamePrefix)
357
-	if renamePrefix != "" && strings.HasPrefix(casefoldedAccount, renamePrefix) {
361
+	if config.Accounts.NickReservation.guestRegexpFolded.MatchString(casefoldedAccount) {
358 362
 		return errAccountAlreadyRegistered
359 363
 	}
360 364
 
@@ -382,7 +386,7 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
382 386
 	callbackSpec := fmt.Sprintf("%s:%s", callbackNamespace, callbackValue)
383 387
 
384 388
 	var setOptions *buntdb.SetOptions
385
-	ttl := time.Duration(config.Registration.VerifyTimeout)
389
+	ttl := time.Duration(config.Accounts.Registration.VerifyTimeout)
386 390
 	if ttl != 0 {
387 391
 		setOptions = &buntdb.SetOptions{Expires: true, TTL: ttl}
388 392
 	}
@@ -652,7 +656,7 @@ func (am *AccountManager) dispatchCallback(client *Client, casefoldedAccount str
652 656
 }
653 657
 
654 658
 func (am *AccountManager) dispatchMailtoCallback(client *Client, casefoldedAccount string, callbackValue string) (code string, err error) {
655
-	config := am.server.AccountConfig().Registration.Callbacks.Mailto
659
+	config := am.server.Config().Accounts.Registration.Callbacks.Mailto
656 660
 	code = utils.GenerateSecretToken()
657 661
 
658 662
 	subject := config.VerifyMessageSubject
@@ -811,7 +815,7 @@ func (am *AccountManager) SetNickReserved(client *Client, nick string, saUnreser
811 815
 	cfnick, err := CasefoldName(nick)
812 816
 	skeleton, skerr := Skeleton(nick)
813 817
 	// garbage nick, or garbage options, or disabled
814
-	nrconfig := am.server.AccountConfig().NickReservation
818
+	nrconfig := am.server.Config().Accounts.NickReservation
815 819
 	if err != nil || skerr != nil || cfnick == "" || (reserve && saUnreserve) || !nrconfig.Enabled {
816 820
 		return errAccountNickReservationFailed
817 821
 	}
@@ -1536,7 +1540,7 @@ func (am *AccountManager) VHostListRequests(limit int) (requests []PendingVHostR
1536 1540
 func (am *AccountManager) applyVHostInfo(client *Client, info VHostInfo) {
1537 1541
 	// if hostserv is disabled in config, then don't grant vhosts
1538 1542
 	// that were previously approved while it was enabled
1539
-	if !am.server.AccountConfig().VHosts.Enabled {
1543
+	if !am.server.Config().Accounts.VHosts.Enabled {
1540 1544
 		return
1541 1545
 	}
1542 1546
 

+ 49
- 26
irc/client_lookup_set.go View File

@@ -116,23 +116,9 @@ func (clients *ClientManager) Resume(oldClient *Client, session *Session) (err e
116 116
 // SetNick sets a client's nickname, validating it against nicknames in use
117 117
 func (clients *ClientManager) SetNick(client *Client, session *Session, newNick string) (setNick string, err error) {
118 118
 	config := client.server.Config()
119
-	newcfnick, err := CasefoldName(newNick)
120
-	if err != nil {
121
-		return "", errNicknameInvalid
122
-	}
123
-	if len(newNick) > config.Limits.NickLen || len(newcfnick) > config.Limits.NickLen {
124
-		return "", errNicknameInvalid
125
-	}
126
-	newSkeleton, err := Skeleton(newNick)
127
-	if err != nil {
128
-		return "", errNicknameInvalid
129
-	}
130 119
 
131
-	if restrictedCasefoldedNicks[newcfnick] || restrictedSkeletons[newSkeleton] {
132
-		return "", errNicknameInvalid
133
-	}
120
+	var newcfnick, newSkeleton string
134 121
 
135
-	reservedAccount, method := client.server.accounts.EnforcementStatus(newcfnick, newSkeleton)
136 122
 	client.stateMutex.RLock()
137 123
 	account := client.account
138 124
 	accountName := client.accountName
@@ -141,19 +127,58 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick
141 127
 	realname := client.realname
142 128
 	client.stateMutex.RUnlock()
143 129
 
144
-	// recompute this (client.alwaysOn is not set for unregistered clients):
145
-	alwaysOn := account != "" && persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, settings.AlwaysOn)
130
+	// recompute always-on status, because client.alwaysOn is not set for unregistered clients
131
+	var alwaysOn, useAccountName bool
132
+	if account != "" {
133
+		alwaysOn = persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, settings.AlwaysOn)
134
+		useAccountName = alwaysOn || config.Accounts.NickReservation.EnforceAccountName
135
+	}
136
+
137
+	if useAccountName {
138
+		if registered && newNick != accountName && newNick != "" {
139
+			return "", errNickAccountMismatch
140
+		}
141
+		newNick = accountName
142
+		newcfnick = account
143
+		newSkeleton, err = Skeleton(newNick)
144
+		if err != nil {
145
+			return "", errNicknameInvalid
146
+		}
147
+	} else {
148
+		newNick = strings.TrimSpace(newNick)
149
+		if len(newNick) == 0 {
150
+			return "", errNickMissing
151
+		}
146 152
 
147
-	if alwaysOn && registered {
148
-		return "", errCantChangeNick
153
+		if account == "" && config.Accounts.NickReservation.EnforceGuestFormat {
154
+			newNick = strings.Replace(config.Accounts.NickReservation.GuestFormat, "*", newNick, 1)
155
+		}
156
+
157
+		newcfnick, err = CasefoldName(newNick)
158
+		if err != nil {
159
+			return "", errNicknameInvalid
160
+		}
161
+		if len(newNick) > config.Limits.NickLen || len(newcfnick) > config.Limits.NickLen {
162
+			return "", errNicknameInvalid
163
+		}
164
+		newSkeleton, err = Skeleton(newNick)
165
+		if err != nil {
166
+			return "", errNicknameInvalid
167
+		}
168
+
169
+		if restrictedCasefoldedNicks[newcfnick] || restrictedSkeletons[newSkeleton] {
170
+			return "", errNicknameInvalid
171
+		}
172
+
173
+		reservedAccount, method := client.server.accounts.EnforcementStatus(newcfnick, newSkeleton)
174
+		if method == NickEnforcementStrict && reservedAccount != "" && reservedAccount != account {
175
+			return "", errNicknameReserved
176
+		}
149 177
 	}
150 178
 
151 179
 	var bouncerAllowed bool
152 180
 	if config.Accounts.Multiclient.Enabled {
153
-		if alwaysOn {
154
-			// ignore the pre-reg nick, force a reattach
155
-			newNick = accountName
156
-			newcfnick = account
181
+		if useAccountName {
157 182
 			bouncerAllowed = true
158 183
 		} else {
159 184
 			if config.Accounts.Multiclient.AllowedByDefault && settings.AllowBouncer != MulticlientDisallowedByUser {
@@ -198,9 +223,7 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick
198 223
 	if skeletonHolder != nil && skeletonHolder != client {
199 224
 		return "", errNicknameInUse
200 225
 	}
201
-	if method == NickEnforcementStrict && reservedAccount != "" && reservedAccount != account {
202
-		return "", errNicknameReserved
203
-	}
226
+
204 227
 	clients.removeInternal(client)
205 228
 	clients.byNick[newcfnick] = client
206 229
 	clients.bySkeleton[newSkeleton] = client

+ 58
- 14
irc/config.go View File

@@ -7,6 +7,7 @@ package irc
7 7
 
8 8
 import (
9 9
 	"crypto/tls"
10
+	"errors"
10 11
 	"fmt"
11 12
 	"io/ioutil"
12 13
 	"log"
@@ -242,11 +243,24 @@ type AccountConfig struct {
242 243
 		Duration    time.Duration
243 244
 		MaxAttempts int `yaml:"max-attempts"`
244 245
 	} `yaml:"login-throttling"`
245
-	SkipServerPassword bool                  `yaml:"skip-server-password"`
246
-	NickReservation    NickReservationConfig `yaml:"nick-reservation"`
247
-	Multiclient        MulticlientConfig
248
-	Bouncer            *MulticlientConfig // # handle old name for 'multiclient'
249
-	VHosts             VHostConfig
246
+	SkipServerPassword bool `yaml:"skip-server-password"`
247
+	NickReservation    struct {
248
+		Enabled                bool
249
+		AdditionalNickLimit    int `yaml:"additional-nick-limit"`
250
+		Method                 NickEnforcementMethod
251
+		AllowCustomEnforcement bool          `yaml:"allow-custom-enforcement"`
252
+		RenameTimeout          time.Duration `yaml:"rename-timeout"`
253
+		// RenamePrefix is the legacy field, GuestFormat is the new version
254
+		RenamePrefix       string `yaml:"rename-prefix"`
255
+		GuestFormat        string `yaml:"guest-nickname-format"`
256
+		guestRegexp        *regexp.Regexp
257
+		guestRegexpFolded  *regexp.Regexp
258
+		EnforceGuestFormat bool `yaml:"enforce-guest-format"`
259
+		EnforceAccountName bool `yaml:"enforce-account-name"`
260
+	} `yaml:"nick-reservation"`
261
+	Multiclient MulticlientConfig
262
+	Bouncer     *MulticlientConfig // # handle old name for 'multiclient'
263
+	VHosts      VHostConfig
250 264
 }
251 265
 
252 266
 // AccountRegistrationConfig controls account registration.
@@ -371,15 +385,6 @@ func (cm *Casemapping) UnmarshalYAML(unmarshal func(interface{}) error) (err err
371 385
 	return nil
372 386
 }
373 387
 
374
-type NickReservationConfig struct {
375
-	Enabled                bool
376
-	AdditionalNickLimit    int `yaml:"additional-nick-limit"`
377
-	Method                 NickEnforcementMethod
378
-	AllowCustomEnforcement bool          `yaml:"allow-custom-enforcement"`
379
-	RenameTimeout          time.Duration `yaml:"rename-timeout"`
380
-	RenamePrefix           string        `yaml:"rename-prefix"`
381
-}
382
-
383 388
 // ChannelRegistrationConfig controls channel registration.
384 389
 type ChannelRegistrationConfig struct {
385 390
 	Enabled               bool
@@ -883,6 +888,19 @@ func LoadConfig(filename string) (config *Config, err error) {
883 888
 		config.Accounts.Multiclient.AllowedByDefault = true
884 889
 	}
885 890
 
891
+	// handle guest format, including the legacy key rename-prefix
892
+	if config.Accounts.NickReservation.GuestFormat == "" {
893
+		renamePrefix := config.Accounts.NickReservation.RenamePrefix
894
+		if renamePrefix == "" {
895
+			renamePrefix = "Guest-"
896
+		}
897
+		config.Accounts.NickReservation.GuestFormat = renamePrefix + "*"
898
+	}
899
+	config.Accounts.NickReservation.guestRegexp, config.Accounts.NickReservation.guestRegexpFolded, err = compileGuestRegexp(config.Accounts.NickReservation.GuestFormat, config.Server.Casemapping)
900
+	if err != nil {
901
+		return nil, err
902
+	}
903
+
886 904
 	var newLogConfigs []logger.LoggingConfig
887 905
 	for _, logConfig := range config.Logging {
888 906
 		// methods
@@ -1163,3 +1181,29 @@ func (config *Config) Diff(oldConfig *Config) (addedCaps, removedCaps *caps.Set)
1163 1181
 
1164 1182
 	return
1165 1183
 }
1184
+
1185
+func compileGuestRegexp(guestFormat string, casemapping Casemapping) (standard, folded *regexp.Regexp, err error) {
1186
+	starIndex := strings.IndexByte(guestFormat, '*')
1187
+	if starIndex == -1 {
1188
+		return nil, nil, errors.New("guest format must contain exactly one *")
1189
+	}
1190
+	initial := guestFormat[:starIndex]
1191
+	final := guestFormat[starIndex+1:]
1192
+	if strings.IndexByte(final, '*') != -1 {
1193
+		return nil, nil, errors.New("guest format must contain exactly one *")
1194
+	}
1195
+	standard, err = regexp.Compile(fmt.Sprintf("^%s(.*)%s$", initial, final))
1196
+	if err != nil {
1197
+		return
1198
+	}
1199
+	initialFolded, err := casefoldWithSetting(initial, casemapping)
1200
+	if err != nil {
1201
+		return
1202
+	}
1203
+	finalFolded, err := casefoldWithSetting(final, casemapping)
1204
+	if err != nil {
1205
+		return
1206
+	}
1207
+	folded, err = regexp.Compile(fmt.Sprintf("^%s(.*)%s$", initialFolded, finalFolded))
1208
+	return
1209
+}

+ 2
- 2
irc/errors.go View File

@@ -41,8 +41,8 @@ var (
41 41
 	errNicknameInvalid                = errors.New("invalid nickname")
42 42
 	errNicknameInUse                  = errors.New("nickname in use")
43 43
 	errNicknameReserved               = errors.New("nickname is reserved")
44
-	errCantChangeNick                 = errors.New(`Always-on clients can't change nicknames`)
45
-	errNickAccountMismatch            = errors.New(`Your nickname doesn't match your account name`)
44
+	errCantChangeNick                 = errors.New(`You must use your account name as your nickname`)
45
+	errNickAccountMismatch            = errors.New(`Your nickname must match your account name`)
46 46
 	errNoExistingBan                  = errors.New("Ban does not exist")
47 47
 	errNoSuchChannel                  = errors.New(`No such channel`)
48 48
 	errChannelPurged                  = errors.New(`This channel was purged by the server operators and cannot be used`)

+ 0
- 4
irc/getters.go View File

@@ -25,10 +25,6 @@ func (server *Server) ChannelRegistrationEnabled() bool {
25 25
 	return server.Config().Channels.Registration.Enabled
26 26
 }
27 27
 
28
-func (server *Server) AccountConfig() *AccountConfig {
29
-	return &server.Config().Accounts
30
-}
31
-
32 28
 func (server *Server) GetOperator(name string) (oper *Oper) {
33 29
 	name, err := CasefoldName(name)
34 30
 	if err != nil {

+ 2
- 2
irc/handlers.go View File

@@ -32,7 +32,7 @@ import (
32 32
 )
33 33
 
34 34
 // helper function to parse ACC callbacks, e.g., mailto:person@example.com, tel:16505551234
35
-func parseCallback(spec string, config *AccountConfig) (callbackNamespace string, callbackValue string) {
35
+func parseCallback(spec string, config AccountConfig) (callbackNamespace string, callbackValue string) {
36 36
 	callback := strings.ToLower(spec)
37 37
 	if callback == "*" {
38 38
 		callbackNamespace = "*"
@@ -127,7 +127,7 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage,
127 127
 	}
128 128
 
129 129
 	// sasl abort
130
-	if !server.AccountConfig().AuthenticationEnabled || len(msg.Params) == 1 && msg.Params[0] == "*" {
130
+	if !config.Accounts.AuthenticationEnabled || len(msg.Params) == 1 && msg.Params[0] == "*" {
131 131
 		rb.Add(nil, server.name, ERR_SASLABORTED, details.nick, client.t("SASL authentication aborted"))
132 132
 		session.sasl.Clear()
133 133
 		return false

+ 4
- 4
irc/hostserv.go View File

@@ -178,7 +178,7 @@ func hsNotice(rb *ResponseBuffer, text string) {
178 178
 
179 179
 // hsNotifyChannel notifies the designated channel of new vhost activity
180 180
 func hsNotifyChannel(server *Server, message string) {
181
-	chname := server.AccountConfig().VHosts.UserRequests.Channel
181
+	chname := server.Config().Accounts.VHosts.UserRequests.Channel
182 182
 	channel := server.channels.Get(chname)
183 183
 	if channel == nil {
184 184
 		return
@@ -280,11 +280,11 @@ func hsStatusHandler(server *Server, client *Client, command string, params []st
280 280
 }
281 281
 
282 282
 func validateVhost(server *Server, vhost string, oper bool) error {
283
-	ac := server.AccountConfig()
284
-	if len(vhost) > ac.VHosts.MaxLength {
283
+	config := server.Config()
284
+	if len(vhost) > config.Accounts.VHosts.MaxLength {
285 285
 		return errVHostTooLong
286 286
 	}
287
-	if !ac.VHosts.ValidRegexp.MatchString(vhost) {
287
+	if !config.Accounts.VHosts.ValidRegexp.MatchString(vhost) {
288 288
 		return errVHostBadCharacters
289 289
 	}
290 290
 	return nil

+ 13
- 20
irc/nickname.go View File

@@ -6,7 +6,6 @@ package irc
6 6
 
7 7
 import (
8 8
 	"crypto/rand"
9
-	"encoding/hex"
10 9
 	"fmt"
11 10
 	"strings"
12 11
 
@@ -27,22 +26,15 @@ var (
27 26
 )
28 27
 
29 28
 // returns whether the change succeeded or failed
30
-func performNickChange(server *Server, client *Client, target *Client, session *Session, newnick string, rb *ResponseBuffer) bool {
31
-	nickname := strings.TrimSpace(newnick)
29
+func performNickChange(server *Server, client *Client, target *Client, session *Session, nickname string, rb *ResponseBuffer) bool {
32 30
 	currentNick := client.Nick()
33
-
34
-	if len(nickname) < 1 {
35
-		rb.Add(nil, server.name, ERR_NONICKNAMEGIVEN, currentNick, client.t("No nickname given"))
36
-		return false
37
-	}
38
-
39
-	if target.Nick() == nickname {
31
+	details := target.Details()
32
+	if details.nick == nickname {
40 33
 		return true
41 34
 	}
35
+	hadNick := details.nick != "*"
36
+	origNickMask := details.nickMask
42 37
 
43
-	hadNick := target.HasNick()
44
-	origNickMask := target.NickMaskString()
45
-	details := target.Details()
46 38
 	assignedNickname, err := client.server.clients.SetNick(target, session, nickname)
47 39
 	if err == errNicknameInUse {
48 40
 		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, currentNick, nickname, client.t("Nickname is already in use"))
@@ -50,8 +42,12 @@ func performNickChange(server *Server, client *Client, target *Client, session *
50 42
 		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, currentNick, nickname, client.t("Nickname is reserved by a different account"))
51 43
 	} else if err == errNicknameInvalid {
52 44
 		rb.Add(nil, server.name, ERR_ERRONEUSNICKNAME, currentNick, utils.SafeErrorParam(nickname), client.t("Erroneous nickname"))
53
-	} else if err == errCantChangeNick {
54
-		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, currentNick, utils.SafeErrorParam(nickname), client.t(err.Error()))
45
+	} else if err == errNickAccountMismatch {
46
+		// this used to use ERR_NICKNAMEINUSE, but it displayed poorly in some clients;
47
+		// ERR_UNKNOWNERROR at least has a better chance of displaying our error text
48
+		rb.Add(nil, server.name, ERR_UNKNOWNERROR, currentNick, "NICK", client.t(err.Error()))
49
+	} else if err == errNickMissing {
50
+		rb.Add(nil, server.name, ERR_NONICKNAMEGIVEN, currentNick, client.t("No nickname given"))
55 51
 	} else if err != nil {
56 52
 		rb.Add(nil, server.name, ERR_UNKNOWNERROR, currentNick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
57 53
 	}
@@ -96,13 +92,10 @@ func performNickChange(server *Server, client *Client, target *Client, session *
96 92
 }
97 93
 
98 94
 func (server *Server) RandomlyRename(client *Client) {
99
-	prefix := server.AccountConfig().NickReservation.RenamePrefix
100
-	if prefix == "" {
101
-		prefix = "Guest-"
102
-	}
95
+	format := server.Config().Accounts.NickReservation.GuestFormat
103 96
 	buf := make([]byte, 8)
104 97
 	rand.Read(buf)
105
-	nick := fmt.Sprintf("%s%s", prefix, hex.EncodeToString(buf))
98
+	nick := strings.Replace(format, "*", utils.B32Encoder.EncodeToString(buf), -1)
106 99
 	sessions := client.Sessions()
107 100
 	if len(sessions) == 0 {
108 101
 		return

+ 43
- 10
irc/nickserv.go View File

@@ -610,6 +610,23 @@ func nsLoginThrottleCheck(client *Client, rb *ResponseBuffer) (success bool) {
610 610
 	return true
611 611
 }
612 612
 
613
+// if enforce-account-name is set, account name and nickname must be equal,
614
+// so we need to re-NICK automatically on every login event (IDENTIFY,
615
+// VERIFY, and a REGISTER that auto-verifies). if we can't get the nick
616
+// then we log them out (they will be able to reattach with SASL)
617
+func nsFixNickname(client *Client, rb *ResponseBuffer, config *Config) (success bool) {
618
+	if !config.Accounts.NickReservation.EnforceAccountName {
619
+		return true
620
+	}
621
+	// don't need to supply a nickname, SetNick will use the account name
622
+	if !performNickChange(client.server, client, client, rb.session, "", rb) {
623
+		client.server.accounts.Logout(client)
624
+		nsNotice(rb, client.t("A client is already using that account; try logging out and logging back in with SASL"))
625
+		return false
626
+	}
627
+	return true
628
+}
629
+
613 630
 func nsIdentifyHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
614 631
 	if client.LoggedIntoAccount() {
615 632
 		nsNotice(rb, client.t("You're already logged into an account"))
@@ -649,11 +666,16 @@ func nsIdentifyHandler(server *Server, client *Client, command string, params []
649 666
 		loginSuccessful = (err == nil)
650 667
 	}
651 668
 
669
+	if loginSuccessful {
670
+		if !nsFixNickname(client, rb, server.Config()) {
671
+			loginSuccessful = false
672
+			err = errNickAccountMismatch
673
+		}
674
+	}
675
+
652 676
 	if loginSuccessful {
653 677
 		sendSuccessfulAccountAuth(client, rb, true, true)
654
-	} else if err == errNickAccountMismatch {
655
-		nsNotice(rb, client.t("That account is set to always-on; try logging out and logging back in with SASL"))
656
-	} else {
678
+	} else if err != errNickAccountMismatch {
657 679
 		nsNotice(rb, client.t("Could not login with your TLS certificate or supplied username/password"))
658 680
 	}
659 681
 }
@@ -667,7 +689,7 @@ func nsInfoHandler(server *Server, client *Client, command string, params []stri
667 689
 	var accountName string
668 690
 	if len(params) > 0 {
669 691
 		nick := params[0]
670
-		if server.AccountConfig().NickReservation.Enabled {
692
+		if server.Config().Accounts.NickReservation.Enabled {
671 693
 			accountName = server.accounts.NickToAccount(nick)
672 694
 			if accountName == "" {
673 695
 				nsNotice(rb, client.t("That nickname is not registered"))
@@ -704,7 +726,6 @@ func nsInfoHandler(server *Server, client *Client, command string, params []stri
704 726
 
705 727
 func nsRegisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
706 728
 	details := client.Details()
707
-	account := details.nick
708 729
 	passphrase := params[0]
709 730
 	var email string
710 731
 	if 1 < len(params) {
@@ -730,10 +751,20 @@ func nsRegisterHandler(server *Server, client *Client, command string, params []
730 751
 		return
731 752
 	}
732 753
 
733
-	config := server.AccountConfig()
754
+	config := server.Config()
755
+	account := details.nick
756
+	if config.Accounts.NickReservation.EnforceGuestFormat {
757
+		matches := config.Accounts.NickReservation.guestRegexp.FindStringSubmatch(account)
758
+		if matches == nil || len(matches) < 2 {
759
+			nsNotice(rb, client.t("Erroneous nickname"))
760
+			return
761
+		}
762
+		account = matches[1]
763
+	}
764
+
734 765
 	var callbackNamespace, callbackValue string
735 766
 	noneCallbackAllowed := false
736
-	for _, callback := range config.Registration.EnabledCallbacks {
767
+	for _, callback := range config.Accounts.Registration.EnabledCallbacks {
737 768
 		if callback == "*" {
738 769
 			noneCallbackAllowed = true
739 770
 		}
@@ -744,7 +775,7 @@ func nsRegisterHandler(server *Server, client *Client, command string, params []
744 775
 	if noneCallbackAllowed {
745 776
 		callbackNamespace = "*"
746 777
 	} else {
747
-		callbackNamespace, callbackValue = parseCallback(email, config)
778
+		callbackNamespace, callbackValue = parseCallback(email, config.Accounts)
748 779
 		if callbackNamespace == "" || callbackValue == "" {
749 780
 			nsNotice(rb, client.t("Registration requires a valid e-mail address"))
750 781
 			return
@@ -755,7 +786,7 @@ func nsRegisterHandler(server *Server, client *Client, command string, params []
755 786
 	if err == nil {
756 787
 		if callbackNamespace == "*" {
757 788
 			err = server.accounts.Verify(client, account, "")
758
-			if err == nil {
789
+			if err == nil && nsFixNickname(client, rb, config) {
759 790
 				sendSuccessfulRegResponse(client, rb, true)
760 791
 			}
761 792
 		} else {
@@ -861,7 +892,9 @@ func nsVerifyHandler(server *Server, client *Client, command string, params []st
861 892
 		return
862 893
 	}
863 894
 
864
-	sendSuccessfulRegResponse(client, rb, true)
895
+	if nsFixNickname(client, rb, server.Config()) {
896
+		sendSuccessfulRegResponse(client, rb, true)
897
+	}
865 898
 }
866 899
 
867 900
 func nsPasswdHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {

+ 5
- 1
irc/strings.go View File

@@ -76,7 +76,11 @@ func iterateFolding(profile *precis.Profile, oldStr string) (str string, err err
76 76
 
77 77
 // Casefold returns a casefolded string, without doing any name or channel character checks.
78 78
 func Casefold(str string) (string, error) {
79
-	switch globalCasemappingSetting {
79
+	return casefoldWithSetting(str, globalCasemappingSetting)
80
+}
81
+
82
+func casefoldWithSetting(str string, setting Casemapping) (string, error) {
83
+	switch setting {
80 84
 	default:
81 85
 		return iterateFolding(precis.UsernameCaseMapped, str)
82 86
 	case CasemappingASCII:

+ 18
- 2
oragono.yaml View File

@@ -343,8 +343,24 @@ accounts:
343 343
         # rename-timeout - this is how long users have 'til they're renamed
344 344
         rename-timeout: 30s
345 345
 
346
-        # rename-prefix - this is the prefix to use when renaming clients (e.g. Guest-AB54U31)
347
-        rename-prefix: Guest-
346
+        # format for guest nicknames:
347
+        # 1. these nicknames cannot be registered or reserved
348
+        # 2. if a client is automatically renamed by the server,
349
+        #    this is the template that will be used (e.g., Guest-nccj6rgmt97cg)
350
+        # 3. if enforce-guest-format (see below) is enabled, clients without
351
+        #    a registered account will have this template applied to their
352
+        #    nicknames (e.g., 'katie' will become 'Guest-katie')
353
+        guest-nickname-format: "Guest-*"
354
+
355
+        # when enabled, forces users not logged into an account to use
356
+        # a nickname matching the guest template:
357
+        enforce-guest-format: false
358
+
359
+        # when enabled, forces users logged into an account to use the
360
+        # account name as their nickname. when combined with strict nickname
361
+        # enforcement, this lets users treat nicknames and account names
362
+        # as equivalent for the purpose of ban/invite/exception lists.
363
+        enforce-account-name: false
348 364
 
349 365
     # multiclient controls whether oragono allows multiple connections to
350 366
     # attach to the same client/nickname identity; this is part of the

Loading…
Cancel
Save