From b84dbb1a069c0ec91c1ad14eeebfffbbdb3f4489 Mon Sep 17 00:00:00 2001 From: Daniel Oaks Date: Sat, 22 Oct 2016 22:18:41 +1000 Subject: [PATCH] Support cap-notify and enabling/disabling SASL --- CHANGELOG.md | 2 ++ irc/accounts.go | 2 +- irc/capability.go | 18 ++++++------ irc/client_lookup_set.go | 18 ++++++++++++ irc/config.go | 2 ++ irc/server.go | 60 ++++++++++++++++++++++++++++++++++------ oragono.yaml | 3 ++ 7 files changed, 88 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a419e48..90e37ba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ New release of Oragono! ### Added * Added `REHASH` command. +* Added ability to enable and disable SASL. +* Added support for IRCv3 capability [`cap-notify`](http://ircv3.net/specs/extensions/cap-notify-3.2.html). ### Changed diff --git a/irc/accounts.go b/irc/accounts.go index 4b42f197..36b81e8d 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -78,7 +78,7 @@ func loadAccount(server *Server, tx *buntdb.Tx, accountKey string) *ClientAccoun // authenticateHandler parses the AUTHENTICATE command (for SASL authentication). func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { // sasl abort - if len(msg.Params) == 1 && msg.Params[0] == "*" { + if !server.authenticationEnabled || len(msg.Params) == 1 && msg.Params[0] == "*" { if client.saslInProgress { client.Send(nil, server.name, ERR_SASLABORTED, client.nick, "SASL authentication aborted") } else { diff --git a/irc/capability.go b/irc/capability.go index cd3bd203..9671f921 100644 --- a/irc/capability.go +++ b/irc/capability.go @@ -17,6 +17,7 @@ const ( AccountTag Capability = "account-tag" AccountNotify Capability = "account-notify" AwayNotify Capability = "away-notify" + CapNotify Capability = "cap-notify" ExtendedJoin Capability = "extended-join" InviteNotify Capability = "invite-notify" MessageTags Capability = "draft/message-tags" @@ -28,14 +29,15 @@ const ( var ( SupportedCapabilities = CapabilitySet{ - AccountTag: true, - AccountNotify: true, - AwayNotify: true, - ExtendedJoin: true, - InviteNotify: true, - MessageTags: true, - MultiPrefix: true, - SASL: true, + AccountTag: true, + AccountNotify: true, + AwayNotify: true, + CapNotify: true, + ExtendedJoin: true, + InviteNotify: true, + MessageTags: true, + MultiPrefix: true, + // SASL is set during server startup ServerTime: true, UserhostInNames: true, } diff --git a/irc/client_lookup_set.go b/irc/client_lookup_set.go index f9322d92..26907b7b 100644 --- a/irc/client_lookup_set.go +++ b/irc/client_lookup_set.go @@ -82,6 +82,24 @@ func (clients *ClientLookupSet) Remove(client *Client) error { return nil } +func (clients *ClientLookupSet) AllWithCaps(caps ...Capability) (set ClientSet) { + set = make(ClientSet) + + var client *Client + for _, client = range clients.ByNick { + // make sure they have all the required caps + for _, Cap := range caps { + if !client.capabilities[Cap] { + continue + } + } + + set.Add(client) + } + + return set +} + func (clients *ClientLookupSet) FindAll(userhost string) (set ClientSet) { set = make(ClientSet) diff --git a/irc/config.go b/irc/config.go index 5f894067..accb5f84 100644 --- a/irc/config.go +++ b/irc/config.go @@ -86,6 +86,8 @@ type Config struct { Path string } + AuthenticationEnabled bool `yaml:"authentication-enabled"` + Registration struct { Accounts AccountRegistrationConfig } diff --git a/irc/server.go b/irc/server.go index 4831a40f..ff48ab4b 100644 --- a/irc/server.go +++ b/irc/server.go @@ -60,6 +60,7 @@ type ListenerEvent struct { // Server is the main Oragono server. type Server struct { accounts map[string]*ClientAccount + authenticationEnabled bool channels ChannelNameMap clients *ClientLookupSet commands chan Command @@ -110,14 +111,19 @@ func NewServer(configFilename string, config *Config) *Server { return nil } + if config.AuthenticationEnabled { + SupportedCapabilities[SASL] = true + } + server := &Server{ - accounts: make(map[string]*ClientAccount), - channels: make(ChannelNameMap), - clients: NewClientLookupSet(), - commands: make(chan Command), - configFilename: configFilename, - ctime: time.Now(), - idle: make(chan *Client), + accounts: make(map[string]*ClientAccount), + authenticationEnabled: config.AuthenticationEnabled, + channels: make(ChannelNameMap), + clients: NewClientLookupSet(), + commands: make(chan Command), + configFilename: configFilename, + ctime: time.Now(), + idle: make(chan *Client), limits: Limits{ AwayLen: int(config.Limits.AwayLen), ChannelLen: int(config.Limits.ChannelLen), @@ -894,7 +900,45 @@ func (server *Server) rehash() error { return fmt.Errorf("Error rehashing config file: %s", err.Error()) } - //TODO(dan): burst CAP DEL for sasl + // setup new and removed caps + addedCaps := make(CapabilitySet) + removedCaps := make(CapabilitySet) + + // SASL + if config.AuthenticationEnabled && !server.authenticationEnabled { + // enabling SASL + SupportedCapabilities[SASL] = true + addedCaps[SASL] = true + } + if !config.AuthenticationEnabled && server.authenticationEnabled { + // disabling SASL + SupportedCapabilities[SASL] = false + removedCaps[SASL] = true + } + server.authenticationEnabled = config.AuthenticationEnabled + + // burst new and removed caps + var capBurstClients ClientSet + added := make(map[CapVersion]string) + var removed string + + if len(addedCaps) > 0 || len(removedCaps) > 0 { + capBurstClients = server.clients.AllWithCaps(CapNotify) + + added[Cap301] = addedCaps.String(Cap301) + added[Cap302] = addedCaps.String(Cap302) + // removed never has values + removed = removedCaps.String(Cap301) + } + + for sClient := range capBurstClients { + if len(addedCaps) > 0 { + sClient.Send(nil, server.name, "CAP", sClient.nick, "NEW", added[sClient.capVersion]) + } + if len(removedCaps) > 0 { + sClient.Send(nil, server.name, "CAP", sClient.nick, "DEL", removed) + } + } // set server options server.limits = Limits{ diff --git a/oragono.yaml b/oragono.yaml index dcf93425..02efb3ab 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -41,6 +41,9 @@ server: # if you change the motd, you should move it to ircd.motd motd: oragono.motd +# whether account authentication is enabled +authentication-enabled: true + # account/channel registration registration: # account registration