forked from External/ergo
per-user settings for nickname enforcement
This commit is contained in:
parent
d0ded906d4
commit
2ee89b15b3
7 changed files with 216 additions and 39 deletions
111
irc/accounts.go
111
irc/accounts.go
|
|
@ -30,6 +30,7 @@ const (
|
|||
keyAccountRegTime = "account.registered.time %s"
|
||||
keyAccountCredentials = "account.credentials %s"
|
||||
keyAccountAdditionalNicks = "account.additionalnicks %s"
|
||||
keyAccountEnforcement = "account.customenforcement %s"
|
||||
keyAccountVHost = "account.vhost %s"
|
||||
keyCertToAccount = "account.creds.certfp %s"
|
||||
|
||||
|
|
@ -53,12 +54,14 @@ type AccountManager struct {
|
|||
// track clients logged in to accounts
|
||||
accountToClients map[string][]*Client
|
||||
nickToAccount map[string]string
|
||||
accountToMethod map[string]NickReservationMethod
|
||||
}
|
||||
|
||||
func NewAccountManager(server *Server) *AccountManager {
|
||||
am := AccountManager{
|
||||
accountToClients: make(map[string][]*Client),
|
||||
nickToAccount: make(map[string]string),
|
||||
accountToMethod: make(map[string]NickReservationMethod),
|
||||
server: server,
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +75,8 @@ func (am *AccountManager) buildNickToAccountIndex() {
|
|||
return
|
||||
}
|
||||
|
||||
result := make(map[string]string)
|
||||
nickToAccount := make(map[string]string)
|
||||
accountToMethod := make(map[string]NickReservationMethod)
|
||||
existsPrefix := fmt.Sprintf(keyAccountExists, "")
|
||||
|
||||
am.serialCacheUpdateMutex.Lock()
|
||||
|
|
@ -83,14 +87,22 @@ func (am *AccountManager) buildNickToAccountIndex() {
|
|||
if !strings.HasPrefix(key, existsPrefix) {
|
||||
return false
|
||||
}
|
||||
accountName := strings.TrimPrefix(key, existsPrefix)
|
||||
if _, err := tx.Get(fmt.Sprintf(keyAccountVerified, accountName)); err == nil {
|
||||
result[accountName] = accountName
|
||||
|
||||
account := strings.TrimPrefix(key, existsPrefix)
|
||||
if _, err := tx.Get(fmt.Sprintf(keyAccountVerified, account)); err == nil {
|
||||
nickToAccount[account] = account
|
||||
}
|
||||
if rawNicks, err := tx.Get(fmt.Sprintf(keyAccountAdditionalNicks, accountName)); err == nil {
|
||||
if rawNicks, err := tx.Get(fmt.Sprintf(keyAccountAdditionalNicks, account)); err == nil {
|
||||
additionalNicks := unmarshalReservedNicks(rawNicks)
|
||||
for _, nick := range additionalNicks {
|
||||
result[nick] = accountName
|
||||
nickToAccount[nick] = account
|
||||
}
|
||||
}
|
||||
|
||||
if methodStr, err := tx.Get(fmt.Sprintf(keyAccountEnforcement, account)); err == nil {
|
||||
method, err := nickReservationFromString(methodStr)
|
||||
if err == nil {
|
||||
accountToMethod[account] = method
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
@ -102,7 +114,8 @@ func (am *AccountManager) buildNickToAccountIndex() {
|
|||
am.server.logger.Error("internal", "couldn't read reserved nicks", err.Error())
|
||||
} else {
|
||||
am.Lock()
|
||||
am.nickToAccount = result
|
||||
am.nickToAccount = nickToAccount
|
||||
am.accountToMethod = accountToMethod
|
||||
am.Unlock()
|
||||
}
|
||||
}
|
||||
|
|
@ -156,6 +169,84 @@ func (am *AccountManager) NickToAccount(nick string) string {
|
|||
return am.nickToAccount[cfnick]
|
||||
}
|
||||
|
||||
// Given a nick, looks up the account that owns it and the method (none/timeout/strict)
|
||||
// used to enforce ownership.
|
||||
func (am *AccountManager) EnforcementStatus(nick string) (account string, method NickReservationMethod) {
|
||||
cfnick, err := CasefoldName(nick)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config := am.server.Config()
|
||||
if !config.Accounts.NickReservation.Enabled {
|
||||
method = NickReservationNone
|
||||
return
|
||||
}
|
||||
|
||||
am.RLock()
|
||||
defer am.RUnlock()
|
||||
|
||||
account = am.nickToAccount[cfnick]
|
||||
method = am.accountToMethod[account]
|
||||
// if they don't have a custom setting, or customization is disabled, use the default
|
||||
if method == NickReservationOptional || !config.Accounts.NickReservation.AllowCustomEnforcement {
|
||||
method = config.Accounts.NickReservation.Method
|
||||
}
|
||||
if method == NickReservationOptional {
|
||||
// enforcement was explicitly enabled neither in the config or by the user
|
||||
method = NickReservationNone
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Looks up the enforcement method stored in the database for an account
|
||||
// (typically you want EnforcementStatus instead, which respects the config)
|
||||
func (am *AccountManager) getStoredEnforcementStatus(account string) string {
|
||||
am.RLock()
|
||||
defer am.RUnlock()
|
||||
return nickReservationToString(am.accountToMethod[account])
|
||||
}
|
||||
|
||||
// Sets a custom enforcement method for an account and stores it in the database.
|
||||
func (am *AccountManager) SetEnforcementStatus(account string, method NickReservationMethod) (err error) {
|
||||
config := am.server.Config()
|
||||
if !(config.Accounts.NickReservation.Enabled && config.Accounts.NickReservation.AllowCustomEnforcement) {
|
||||
return errFeatureDisabled
|
||||
}
|
||||
|
||||
var serialized string
|
||||
if method == NickReservationOptional {
|
||||
serialized = "" // normally this is "default", but we're going to delete the key
|
||||
} else {
|
||||
serialized = nickReservationToString(method)
|
||||
}
|
||||
|
||||
key := fmt.Sprintf(keyAccountEnforcement, account)
|
||||
|
||||
am.Lock()
|
||||
defer am.Unlock()
|
||||
|
||||
currentMethod := am.accountToMethod[account]
|
||||
if method != currentMethod {
|
||||
if method == NickReservationOptional {
|
||||
delete(am.accountToMethod, account)
|
||||
} else {
|
||||
am.accountToMethod[account] = method
|
||||
}
|
||||
|
||||
return am.server.store.Update(func(tx *buntdb.Tx) (err error) {
|
||||
if serialized != "" {
|
||||
_, _, err = tx.Set(key, nickReservationToString(method), nil)
|
||||
} else {
|
||||
_, err = tx.Delete(key)
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *AccountManager) AccountToClients(account string) (result []*Client) {
|
||||
cfaccount, err := CasefoldName(account)
|
||||
if err != nil {
|
||||
|
|
@ -992,10 +1083,12 @@ func (am *AccountManager) applyVhostToClients(account string, result VHostInfo)
|
|||
|
||||
func (am *AccountManager) Login(client *Client, account ClientAccount) {
|
||||
changed := client.SetAccountName(account.Name)
|
||||
if changed {
|
||||
go client.nickTimer.Touch()
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
|
||||
client.nickTimer.Touch()
|
||||
|
||||
am.applyVHostInfo(client, account.VHost)
|
||||
|
||||
casefoldedAccount := client.Account()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue