Просмотр исходного кода

Merge pull request #352 from slingamn/chanreglimit.1

track channel registrations per account
tags/v1.0.0-rc1
Daniel Oaks 5 лет назад
Родитель
Сommit
7cf8aaccf6
Аккаунт пользователя с таким Email не найден
10 измененных файлов: 154 добавлений и 14 удалений
  1. 45
    0
      irc/accounts.go
  2. 4
    1
      irc/channel.go
  3. 30
    1
      irc/channelreg.go
  4. 16
    7
      irc/chanserv.go
  5. 13
    4
      irc/config.go
  6. 25
    1
      irc/database.go
  7. 6
    0
      irc/getters.go
  8. 6
    0
      irc/handlers.go
  9. 3
    0
      irc/nickserv.go
  10. 6
    0
      oragono.yaml

+ 45
- 0
irc/accounts.go Просмотреть файл

@@ -33,6 +33,7 @@ const (
33 33
 	keyAccountEnforcement      = "account.customenforcement %s"
34 34
 	keyAccountVHost            = "account.vhost %s"
35 35
 	keyCertToAccount           = "account.creds.certfp %s"
36
+	keyAccountChannels         = "account.channels %s"
36 37
 
37 38
 	keyVHostQueueAcctToId = "vhostQueue %s"
38 39
 	vhostRequestIdx       = "vhostQueue"
@@ -856,9 +857,25 @@ func (am *AccountManager) Unregister(account string) error {
856 857
 	nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
857 858
 	vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
858 859
 	vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
860
+	channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
859 861
 
860 862
 	var clients []*Client
861 863
 
864
+	var registeredChannels []string
865
+	// on our way out, unregister all the account's channels and delete them from the db
866
+	defer func() {
867
+		for _, channelName := range registeredChannels {
868
+			info := am.server.channelRegistry.LoadChannel(channelName)
869
+			if info != nil && info.Founder == casefoldedAccount {
870
+				am.server.channelRegistry.Delete(channelName, *info)
871
+			}
872
+			channel := am.server.channels.Get(channelName)
873
+			if channel != nil {
874
+				channel.SetUnregistered(casefoldedAccount)
875
+			}
876
+		}
877
+	}()
878
+
862 879
 	var credText string
863 880
 	var rawNicks string
864 881
 
@@ -866,6 +883,7 @@ func (am *AccountManager) Unregister(account string) error {
866 883
 	defer am.serialCacheUpdateMutex.Unlock()
867 884
 
868 885
 	var accountName string
886
+	var channelsStr string
869 887
 	am.server.store.Update(func(tx *buntdb.Tx) error {
870 888
 		tx.Delete(accountKey)
871 889
 		accountName, _ = tx.Get(accountNameKey)
@@ -879,6 +897,9 @@ func (am *AccountManager) Unregister(account string) error {
879 897
 		credText, err = tx.Get(credentialsKey)
880 898
 		tx.Delete(credentialsKey)
881 899
 		tx.Delete(vhostKey)
900
+		channelsStr, _ = tx.Get(channelsKey)
901
+		tx.Delete(channelsKey)
902
+
882 903
 		_, err := tx.Delete(vhostQueueKey)
883 904
 		am.decrementVHostQueueCount(casefoldedAccount, err)
884 905
 		return nil
@@ -899,6 +920,7 @@ func (am *AccountManager) Unregister(account string) error {
899 920
 
900 921
 	skeleton, _ := Skeleton(accountName)
901 922
 	additionalNicks := unmarshalReservedNicks(rawNicks)
923
+	registeredChannels = unmarshalRegisteredChannels(channelsStr)
902 924
 
903 925
 	am.Lock()
904 926
 	defer am.Unlock()
@@ -925,9 +947,32 @@ func (am *AccountManager) Unregister(account string) error {
925 947
 	if err != nil {
926 948
 		return errAccountDoesNotExist
927 949
 	}
950
+
928 951
 	return nil
929 952
 }
930 953
 
954
+func unmarshalRegisteredChannels(channelsStr string) (result []string) {
955
+	if channelsStr != "" {
956
+		result = strings.Split(channelsStr, ",")
957
+	}
958
+	return
959
+}
960
+
961
+func (am *AccountManager) ChannelsForAccount(account string) (channels []string) {
962
+	cfaccount, err := CasefoldName(account)
963
+	if err != nil {
964
+		return
965
+	}
966
+
967
+	var channelStr string
968
+	key := fmt.Sprintf(keyAccountChannels, cfaccount)
969
+	am.server.store.View(func(tx *buntdb.Tx) error {
970
+		channelStr, _ = tx.Get(key)
971
+		return nil
972
+	})
973
+	return unmarshalRegisteredChannels(channelStr)
974
+}
975
+
931 976
 func (am *AccountManager) AuthenticateByCertFP(client *Client) error {
932 977
 	if client.certfp == "" {
933 978
 		return errAccountInvalidCredentials

+ 4
- 1
irc/channel.go Просмотреть файл

@@ -165,10 +165,13 @@ func (channel *Channel) SetRegistered(founder string) error {
165 165
 }
166 166
 
167 167
 // SetUnregistered deletes the channel's registration information.
168
-func (channel *Channel) SetUnregistered() {
168
+func (channel *Channel) SetUnregistered(expectedFounder string) {
169 169
 	channel.stateMutex.Lock()
170 170
 	defer channel.stateMutex.Unlock()
171 171
 
172
+	if channel.registeredFounder != expectedFounder {
173
+		return
174
+	}
172 175
 	channel.registeredFounder = ""
173 176
 	var zeroTime time.Time
174 177
 	channel.registeredTime = zeroTime

+ 30
- 1
irc/channelreg.go Просмотреть файл

@@ -254,14 +254,43 @@ func (reg *ChannelRegistry) deleteChannel(tx *buntdb.Tx, key string, info Regist
254 254
 			for _, keyFmt := range channelKeyStrings {
255 255
 				tx.Delete(fmt.Sprintf(keyFmt, key))
256 256
 			}
257
+
258
+			// remove this channel from the client's list of registered channels
259
+			channelsKey := fmt.Sprintf(keyAccountChannels, info.Founder)
260
+			channelsStr, err := tx.Get(channelsKey)
261
+			if err == buntdb.ErrNotFound {
262
+				return
263
+			}
264
+			registeredChannels := unmarshalRegisteredChannels(channelsStr)
265
+			var nowRegisteredChannels []string
266
+			for _, channel := range registeredChannels {
267
+				if channel != key {
268
+					nowRegisteredChannels = append(nowRegisteredChannels, channel)
269
+				}
270
+			}
271
+			tx.Set(channelsKey, strings.Join(nowRegisteredChannels, ","), nil)
257 272
 		}
258 273
 	}
259 274
 }
260 275
 
261 276
 // saveChannel saves a channel to the store.
262 277
 func (reg *ChannelRegistry) saveChannel(tx *buntdb.Tx, channelKey string, channelInfo RegisteredChannel, includeFlags uint) {
278
+	// maintain the mapping of account -> registered channels
279
+	chanExistsKey := fmt.Sprintf(keyChannelExists, channelKey)
280
+	_, existsErr := tx.Get(chanExistsKey)
281
+	if existsErr == buntdb.ErrNotFound {
282
+		// this is a new registration, need to update account-to-channels
283
+		accountChannelsKey := fmt.Sprintf(keyAccountChannels, channelInfo.Founder)
284
+		alreadyChannels, _ := tx.Get(accountChannelsKey)
285
+		newChannels := channelKey // this is the casefolded channel name
286
+		if alreadyChannels != "" {
287
+			newChannels = fmt.Sprintf("%s,%s", alreadyChannels, newChannels)
288
+		}
289
+		tx.Set(accountChannelsKey, newChannels, nil)
290
+	}
291
+
263 292
 	if includeFlags&IncludeInitial != 0 {
264
-		tx.Set(fmt.Sprintf(keyChannelExists, channelKey), "1", nil)
293
+		tx.Set(chanExistsKey, "1", nil)
265 294
 		tx.Set(fmt.Sprintf(keyChannelName, channelKey), channelInfo.Name, nil)
266 295
 		tx.Set(fmt.Sprintf(keyChannelRegTime, channelKey), strconv.FormatInt(channelInfo.RegisteredAt.Unix(), 10), nil)
267 296
 		tx.Set(fmt.Sprintf(keyChannelFounder, channelKey), channelInfo.Founder, nil)

+ 16
- 7
irc/chanserv.go Просмотреть файл

@@ -224,8 +224,15 @@ func csRegisterHandler(server *Server, client *Client, command string, params []
224 224
 		return
225 225
 	}
226 226
 
227
+	account := client.Account()
228
+	channelsAlreadyRegistered := server.accounts.ChannelsForAccount(account)
229
+	if server.Config().Channels.Registration.MaxChannelsPerAccount <= len(channelsAlreadyRegistered) {
230
+		csNotice(rb, client.t("You have already registered the maximum number of channels; try dropping some with /CS UNREGISTER"))
231
+		return
232
+	}
233
+
227 234
 	// this provides the synchronization that allows exactly one registration of the channel:
228
-	err = channelInfo.SetRegistered(client.Account())
235
+	err = channelInfo.SetRegistered(account)
229 236
 	if err != nil {
230 237
 		csNotice(rb, err.Error())
231 238
 		return
@@ -270,11 +277,13 @@ func csUnregisterHandler(server *Server, client *Client, command string, params
270 277
 		return
271 278
 	}
272 279
 
273
-	hasPrivs := client.HasRoleCapabs("chanreg")
274
-	if !hasPrivs {
275
-		founder := channel.Founder()
276
-		hasPrivs = founder != "" && founder == client.Account()
280
+	founder := channel.Founder()
281
+	if founder == "" {
282
+		csNotice(rb, client.t("That channel is not registered"))
283
+		return
277 284
 	}
285
+
286
+	hasPrivs := client.HasRoleCapabs("chanreg") || founder == client.Account()
278 287
 	if !hasPrivs {
279 288
 		csNotice(rb, client.t("Insufficient privileges"))
280 289
 		return
@@ -288,8 +297,8 @@ func csUnregisterHandler(server *Server, client *Client, command string, params
288 297
 		return
289 298
 	}
290 299
 
291
-	channel.SetUnregistered()
292
-	go server.channelRegistry.Delete(channelKey, info)
300
+	channel.SetUnregistered(founder)
301
+	server.channelRegistry.Delete(channelKey, info)
293 302
 	csNotice(rb, fmt.Sprintf(client.t("Channel %s is now unregistered"), channelKey))
294 303
 }
295 304
 

+ 13
- 4
irc/config.go Просмотреть файл

@@ -181,7 +181,8 @@ type NickReservationConfig struct {
181 181
 
182 182
 // ChannelRegistrationConfig controls channel registration.
183 183
 type ChannelRegistrationConfig struct {
184
-	Enabled bool
184
+	Enabled               bool
185
+	MaxChannelsPerAccount int `yaml:"max-channels-per-account"`
185 186
 }
186 187
 
187 188
 // OperClassConfig defines a specific operator class.
@@ -293,9 +294,10 @@ type Config struct {
293 294
 	Accounts AccountConfig
294 295
 
295 296
 	Channels struct {
296
-		DefaultModes *string `yaml:"default-modes"`
297
-		defaultModes modes.Modes
298
-		Registration ChannelRegistrationConfig
297
+		DefaultModes         *string `yaml:"default-modes"`
298
+		defaultModes         modes.Modes
299
+		MaxChannelsPerClient int `yaml:"max-channels-per-client"`
300
+		Registration         ChannelRegistrationConfig
299 301
 	}
300 302
 
301 303
 	OperClasses map[string]*OperClassConfig `yaml:"oper-classes"`
@@ -789,6 +791,13 @@ func LoadConfig(filename string) (config *Config, err error) {
789 791
 		config.Accounts.Registration.BcryptCost = passwd.DefaultCost
790 792
 	}
791 793
 
794
+	if config.Channels.MaxChannelsPerClient == 0 {
795
+		config.Channels.MaxChannelsPerClient = 100
796
+	}
797
+	if config.Channels.Registration.MaxChannelsPerAccount == 0 {
798
+		config.Channels.Registration.MaxChannelsPerAccount = 15
799
+	}
800
+
792 801
 	// in the current implementation, we disable history by creating a history buffer
793 802
 	// with zero capacity. but the `enabled` config option MUST be respected regardless
794 803
 	// of this detail

+ 25
- 1
irc/database.go Просмотреть файл

@@ -22,7 +22,7 @@ const (
22 22
 	// 'version' of the database schema
23 23
 	keySchemaVersion = "db.version"
24 24
 	// latest schema of the db
25
-	latestDbSchema = "4"
25
+	latestDbSchema = "5"
26 26
 )
27 27
 
28 28
 type SchemaChanger func(*Config, *buntdb.Tx) error
@@ -390,6 +390,25 @@ func schemaChangeV3ToV4(config *Config, tx *buntdb.Tx) error {
390 390
 	return nil
391 391
 }
392 392
 
393
+// create new key tracking channels that belong to an account
394
+func schemaChangeV4ToV5(config *Config, tx *buntdb.Tx) error {
395
+	founderToChannels := make(map[string][]string)
396
+	prefix := "channel.founder "
397
+	tx.AscendGreaterOrEqual("", prefix, func(key, value string) bool {
398
+		if !strings.HasPrefix(key, prefix) {
399
+			return false
400
+		}
401
+		channel := strings.TrimPrefix(key, prefix)
402
+		founderToChannels[value] = append(founderToChannels[value], channel)
403
+		return true
404
+	})
405
+
406
+	for founder, channels := range founderToChannels {
407
+		tx.Set(fmt.Sprintf("account.channels %s", founder), strings.Join(channels, ","), nil)
408
+	}
409
+	return nil
410
+}
411
+
393 412
 func init() {
394 413
 	allChanges := []SchemaChange{
395 414
 		{
@@ -407,6 +426,11 @@ func init() {
407 426
 			TargetVersion:  "4",
408 427
 			Changer:        schemaChangeV3ToV4,
409 428
 		},
429
+		{
430
+			InitialVersion: "4",
431
+			TargetVersion:  "5",
432
+			Changer:        schemaChangeV4ToV5,
433
+		},
410 434
 	}
411 435
 
412 436
 	// build the index

+ 6
- 0
irc/getters.go Просмотреть файл

@@ -200,6 +200,12 @@ func (client *Client) Channels() (result []*Channel) {
200 200
 	return
201 201
 }
202 202
 
203
+func (client *Client) NumChannels() int {
204
+	client.stateMutex.RLock()
205
+	defer client.stateMutex.RUnlock()
206
+	return len(client.channels)
207
+}
208
+
203 209
 func (client *Client) WhoWas() (result WhoWas) {
204 210
 	return client.Details().WhoWas
205 211
 }

+ 6
- 0
irc/handlers.go Просмотреть файл

@@ -1159,7 +1159,13 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
1159 1159
 		keys = strings.Split(msg.Params[1], ",")
1160 1160
 	}
1161 1161
 
1162
+	config := server.Config()
1163
+	oper := client.Oper()
1162 1164
 	for i, name := range channels {
1165
+		if config.Channels.MaxChannelsPerClient <= client.NumChannels() && oper == nil {
1166
+			rb.Add(nil, server.name, ERR_TOOMANYCHANNELS, client.Nick(), name, client.t("You have joined too many channels"))
1167
+			return false
1168
+		}
1163 1169
 		var key string
1164 1170
 		if len(keys) > i {
1165 1171
 			key = keys[i]

+ 3
- 0
irc/nickserv.go Просмотреть файл

@@ -327,6 +327,9 @@ func nsInfoHandler(server *Server, client *Client, command string, params []stri
327 327
 	for _, nick := range account.AdditionalNicks {
328 328
 		nsNotice(rb, fmt.Sprintf(client.t("Additional grouped nick: %s"), nick))
329 329
 	}
330
+	for _, channel := range server.accounts.ChannelsForAccount(accountName) {
331
+		nsNotice(rb, fmt.Sprintf(client.t("Registered channel: %s"), channel))
332
+	}
330 333
 }
331 334
 
332 335
 func nsRegisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {

+ 6
- 0
oragono.yaml Просмотреть файл

@@ -275,11 +275,17 @@ channels:
275 275
     # see  /QUOTE HELP cmodes  for more channel modes
276 276
     default-modes: +nt
277 277
 
278
+    # how many channels can a client be in at once?
279
+    max-channels-per-client: 100
280
+
278 281
     # channel registration - requires an account
279 282
     registration:
280 283
         # can users register new channels?
281 284
         enabled: true
282 285
 
286
+        # how many channels can each account register?
287
+        max-channels-per-account: 15
288
+
283 289
 # operator classes
284 290
 oper-classes:
285 291
     # local operator

Загрузка…
Отмена
Сохранить