3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-25 21:39:25 +01:00

Allow configuring relay

This commit is contained in:
Daniel Oaks 2020-06-08 15:17:45 +10:00
parent 4ee49f8450
commit 4ecd7fdf43
7 changed files with 95 additions and 28 deletions

View File

@ -134,6 +134,19 @@ server:
# if this is true, the motd is escaped using formatting codes like $c, $b, and $i # if this is true, the motd is escaped using formatting codes like $c, $b, and $i
motd-formatting: true motd-formatting: true
# relaying using the RELAYMSG command
relaying:
# is relaying enabled at all?
enabled: true
# which character(s) are reserved for relayed nicks?
separators: "/"
# can channel operators use RELAYMSG in their channels?
# our implementation of RELAYMSG makes it safe for chanops to use without the
# possibility of real users being silently spoofed
available-to-chanops: true
# addresses/CIDRs the PROXY command can be used from # addresses/CIDRs the PROXY command can be used from
# this should be restricted to localhost (127.0.0.1/8, ::1/128, and unix sockets), # this should be restricted to localhost (127.0.0.1/8, ::1/128, and unix sockets),
# unless you have a good reason. you should also add these addresses to the # unless you have a good reason. you should also add these addresses to the

View File

@ -173,8 +173,13 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick
return "", errNicknameInvalid, false return "", errNicknameInvalid, false
} }
if strings.Contains(newCfNick, "/") { config := client.server.Config()
return "", errNicknameInvalid, false if config.Server.Relaying.Enabled {
for _, char := range config.Server.Relaying.Separators {
if strings.ContainsRune(newCfNick, char) {
return "", errNicknameInvalid, false
}
}
} }
if restrictedCasefoldedNicks[newCfNick] || restrictedSkeletons[newSkeleton] { if restrictedCasefoldedNicks[newCfNick] || restrictedSkeletons[newSkeleton] {

View File

@ -499,14 +499,19 @@ type Config struct {
CheckIdent bool `yaml:"check-ident"` CheckIdent bool `yaml:"check-ident"`
MOTD string MOTD string
motdLines []string motdLines []string
MOTDFormatting bool `yaml:"motd-formatting"` MOTDFormatting bool `yaml:"motd-formatting"`
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"` Relaying struct {
proxyAllowedFromNets []net.IPNet Enabled bool
WebIRC []webircConfig `yaml:"webirc"` Separators string
MaxSendQString string `yaml:"max-sendq"` AvailableToChanops bool `yaml:"available-to-chanops"`
MaxSendQBytes int }
AllowPlaintextResume bool `yaml:"allow-plaintext-resume"` ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
Compatibility struct { proxyAllowedFromNets []net.IPNet
WebIRC []webircConfig `yaml:"webirc"`
MaxSendQString string `yaml:"max-sendq"`
MaxSendQBytes int
AllowPlaintextResume bool `yaml:"allow-plaintext-resume"`
Compatibility struct {
ForceTrailing *bool `yaml:"force-trailing"` ForceTrailing *bool `yaml:"force-trailing"`
forceTrailing bool forceTrailing bool
SendUnprefixedSasl bool `yaml:"send-unprefixed-sasl"` SendUnprefixedSasl bool `yaml:"send-unprefixed-sasl"`
@ -1068,8 +1073,16 @@ func LoadConfig(filename string) (config *Config, err error) {
} }
config.Server.capValues[caps.Languages] = config.languageManager.CapValue() config.Server.capValues[caps.Languages] = config.languageManager.CapValue()
// intentionally not configurable if config.Server.Relaying.Enabled {
config.Server.capValues[caps.Relaymsg] = "/" for _, char := range protocolBreakingNameCharacters {
if strings.ContainsRune(config.Server.Relaying.Separators, char) {
return nil, fmt.Errorf("Relaying separators cannot include the characters %s", protocolBreakingNameCharacters)
}
}
config.Server.capValues[caps.Relaymsg] = config.Server.Relaying.Separators
} else {
config.Server.supportedCaps.Disable(caps.Relaymsg)
}
config.Debug.recoverFromErrors = utils.BoolDefaultTrue(config.Debug.RecoverFromErrors) config.Debug.recoverFromErrors = utils.BoolDefaultTrue(config.Debug.RecoverFromErrors)

View File

@ -1888,12 +1888,22 @@ func messageHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
break break
} }
if strings.Contains(targetString, "/") { config := server.Config()
if histType == history.Privmsg { if config.Server.Relaying.Enabled {
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.Nick(), targetString, client.t("Relayed users cannot be sent private messages")) var isForRelayClient bool
for _, char := range config.Server.Relaying.Separators {
if strings.ContainsRune(targetString, char) {
isForRelayClient = true
break
}
}
if isForRelayClient {
if histType == history.Privmsg {
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.Nick(), targetString, client.t("Relayed users cannot be sent private messages"))
}
// TAGMSG/NOTICEs are intentionally silently dropped
continue
} }
// TAGMSG/NOTICEs are intentionally silently dropped
continue
} }
// each target gets distinct msgids // each target gets distinct msgids
@ -2281,14 +2291,21 @@ func rehashHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
// RELAYMSG <channel> <spoofed nick> :<message> // RELAYMSG <channel> <spoofed nick> :<message>
func relaymsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) (result bool) { func relaymsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) (result bool) {
config := server.Config()
if !config.Server.Relaying.Enabled {
rb.Add(nil, server.name, "FAIL", "RELAYMSG", "NOT_ENABLED", client.t("Relaying has been disabled"))
return false
}
channel := server.channels.Get(msg.Params[0]) channel := server.channels.Get(msg.Params[0])
if channel == nil { if channel == nil {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(msg.Params[0]), client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
return false return false
} }
if !(channel.ClientIsAtLeast(client, modes.ChannelOperator) || client.HasRoleCapabs("relaymsg-anywhere")) { allowedToRelay := client.HasRoleCapabs("relaymsg-anywhere") || (config.Server.Relaying.AvailableToChanops && channel.ClientIsAtLeast(client, modes.ChannelOperator))
rb.Add(nil, server.name, "FAIL", "RELAYMSG", "NOT_PRIVED", client.t("Only channel operators or ircops with the 'relaymsg-anywhere' role can relay messages")) if !allowedToRelay {
rb.Add(nil, server.name, "FAIL", "RELAYMSG", "NOT_PRIVED", client.t("You cannot relay messages to this channel"))
return false return false
} }

View File

@ -497,6 +497,10 @@ func (server *Server) applyConfig(config *Config) (err error) {
return fmt.Errorf("Casemapping cannot be changed after launching the server, rehash aborted") return fmt.Errorf("Casemapping cannot be changed after launching the server, rehash aborted")
} else if oldConfig.Accounts.Multiclient.AlwaysOn != config.Accounts.Multiclient.AlwaysOn { } else if oldConfig.Accounts.Multiclient.AlwaysOn != config.Accounts.Multiclient.AlwaysOn {
return fmt.Errorf("Default always-on setting cannot be changed after launching the server, rehash aborted") return fmt.Errorf("Default always-on setting cannot be changed after launching the server, rehash aborted")
} else if oldConfig.Server.Relaying.Enabled != config.Server.Relaying.Enabled {
return fmt.Errorf("Cannot enable or disable relaying after launching the server, rehash aborted")
} else if oldConfig.Server.Relaying.Separators != config.Server.Relaying.Separators {
return fmt.Errorf("Cannot change relaying separators after launching the server, rehash aborted")
} }
} }

View File

@ -19,6 +19,16 @@ import (
const ( const (
precisUTF8MappingToken = "rfc8265" precisUTF8MappingToken = "rfc8265"
// space can't be used
// , is used as a separator
// * is used in mask matching
// ? is used in mask matching
// . denotes a server name
// ! separates nickname from username
// @ separates username from hostname
// : means trailing
protocolBreakingNameCharacters = " ,*?.!@:"
) )
var ( var (
@ -132,18 +142,10 @@ func CasefoldName(name string) (string, error) {
return "", errStringIsEmpty return "", errStringIsEmpty
} }
// space can't be used
// , is used as a separator
// * is used in mask matching
// ? is used in mask matching
// . denotes a server name
// ! separates nickname from username
// @ separates username from hostname
// : means trailing
// # is a channel prefix // # is a channel prefix
// ~&@%+ are channel membership prefixes // ~&@%+ are channel membership prefixes
// - I feel like disallowing // - I feel like disallowing
if strings.ContainsAny(lowered, " ,*?.!@:") || strings.ContainsAny(string(lowered[0]), "#~&@%+-") { if strings.ContainsAny(lowered, protocolBreakingNameCharacters) || strings.ContainsAny(string(lowered[0]), "#~&@%+-") {
return "", errInvalidCharacter return "", errInvalidCharacter
} }

View File

@ -160,6 +160,19 @@ server:
# if this is true, the motd is escaped using formatting codes like $c, $b, and $i # if this is true, the motd is escaped using formatting codes like $c, $b, and $i
motd-formatting: true motd-formatting: true
# relaying using the RELAYMSG command
relaying:
# is relaying enabled at all?
enabled: true
# which character(s) are reserved for relayed nicks?
separators: "/"
# can channel operators use RELAYMSG in their channels?
# our implementation of RELAYMSG makes it safe for chanops to use without the
# possibility of real users being silently spoofed
available-to-chanops: true
# addresses/CIDRs the PROXY command can be used from # addresses/CIDRs the PROXY command can be used from
# this should be restricted to localhost (127.0.0.1/8, ::1/128, and unix sockets), # this should be restricted to localhost (127.0.0.1/8, ::1/128, and unix sockets),
# unless you have a good reason. you should also add these addresses to the # unless you have a good reason. you should also add these addresses to the