diff --git a/irc/accountreg.go b/irc/accountreg.go index fdc75329..0ad64ec3 100644 --- a/irc/accountreg.go +++ b/irc/accountreg.go @@ -25,9 +25,10 @@ var ( // AccountRegistration manages the registration of accounts. type AccountRegistration struct { - Enabled bool - EnabledCallbacks []string - EnabledCredentialTypes []string + Enabled bool + EnabledCallbacks []string + EnabledCredentialTypes []string + AllowMultiplePerConnection bool } // AccountCredentials stores the various methods for verifying accounts. @@ -41,6 +42,7 @@ type AccountCredentials struct { func NewAccountRegistration(config AccountRegistrationConfig) (accountReg AccountRegistration) { if config.Enabled { accountReg.Enabled = true + accountReg.AllowMultiplePerConnection = config.AllowMultiplePerConnection for _, name := range config.EnabledCallbacks { // we store "none" as "*" internally if name == "none" { @@ -94,8 +96,12 @@ func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage) b // clients can't reg new accounts if they're already logged in if client.account != nil { - client.Send(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, client.nick, "*", "You're already logged into an account") - return false + if server.accountRegistration.AllowMultiplePerConnection { + client.LogoutOfAccount() + } else { + client.Send(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, client.nick, "*", "You're already logged into an account") + return false + } } // get and sanitise account name diff --git a/irc/accounts.go b/irc/accounts.go index f7f42c65..58d80f3c 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -262,6 +262,33 @@ func (client *Client) LoginToAccount(account *ClientAccount) { account.Clients = append(account.Clients, client) client.account = account client.server.snomasks.Send(sno.LocalAccounts, fmt.Sprintf(ircfmt.Unescape("Client $c[grey][$r%s$c[grey]] logged into account $c[grey][$r%s$c[grey]]"), client.nickMaskString, account.Name)) + + //TODO(dan): This should output the AccountNotify message instead of the sasl accepted function below. +} + +// LogoutOfAccount logs the client out of their current account. +func (client *Client) LogoutOfAccount() { + account := client.account + if account == nil { + // already logged out + return + } + + // logout of existing acct + var newClientAccounts []*Client + for _, c := range account.Clients { + if c != client { + newClientAccounts = append(newClientAccounts, c) + } + } + account.Clients = newClientAccounts + + client.account = nil + + // dispatch account-notify + for friend := range client.Friends(AccountNotify) { + friend.Send(nil, client.nickMaskString, "ACCOUNT", "*") + } } // authExternalHandler parses the SASL EXTERNAL mechanism. diff --git a/irc/config.go b/irc/config.go index 9712324d..92973199 100644 --- a/irc/config.go +++ b/irc/config.go @@ -74,6 +74,7 @@ type AccountRegistrationConfig struct { VerifyMessage string `yaml:"verify-message"` } } + AllowMultiplePerConnection bool `yaml:"allow-multiple-per-connection"` } // ChannelRegistrationConfig controls channel registration. diff --git a/oragono.yaml b/oragono.yaml index 427f7098..a215095a 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -131,6 +131,10 @@ accounts: # callbacks to allow enabled-callbacks: - none # no verification needed, will instantly register successfully + + # allow multiple account registrations per connection + # this is for testing purposes and shouldn't be allowed on real networks + allow-multiple-per-connection: false # is account authentication enabled? authentication-enabled: true