diff --git a/irc/config.go b/irc/config.go index c0d94656..12e47ce0 100644 --- a/irc/config.go +++ b/irc/config.go @@ -537,8 +537,7 @@ type Config struct { } Roleplay struct { - Enabled *bool - enabled bool + Enabled bool RequireChanops bool `yaml:"require-chanops"` RequireOper bool `yaml:"require-oper"` AddSuffix *bool `yaml:"add-suffix"` @@ -1192,7 +1191,6 @@ func LoadConfig(filename string) (config *Config, err error) { config.History.ZNCMax = config.History.ChathistoryMax } - config.Roleplay.enabled = utils.BoolDefaultTrue(config.Roleplay.Enabled) config.Roleplay.addSuffix = utils.BoolDefaultTrue(config.Roleplay.AddSuffix) config.Datastore.MySQL.ExpireTime = time.Duration(config.History.Restrictions.ExpireTime) @@ -1272,7 +1270,7 @@ func (config *Config) generateISupport() (err error) { isupport.Add("NETWORK", config.Network.Name) isupport.Add("NICKLEN", strconv.Itoa(config.Limits.NickLen)) isupport.Add("PREFIX", "(qaohv)~&@%+") - if config.Roleplay.enabled { + if config.Roleplay.Enabled { isupport.Add("RPCHAN", "E") isupport.Add("RPUSER", "E") } diff --git a/irc/handlers.go b/irc/handlers.go index 3db6ee5a..585c2387 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -2194,15 +2194,7 @@ func npcHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo fakeSource := msg.Params[1] message := msg.Params[2:] - _, err := CasefoldName(fakeSource) - if err != nil { - client.Send(nil, client.server.name, ERR_CANNOTSENDRP, target, client.t("Fake source must be a valid nickname")) - return false - } - - sourceString := fmt.Sprintf(npcNickMask, fakeSource, client.nick) - - sendRoleplayMessage(server, client, sourceString, target, false, message, rb) + sendRoleplayMessage(server, client, fakeSource, target, false, false, message, rb) return false } @@ -2212,15 +2204,8 @@ func npcaHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp target := msg.Params[0] fakeSource := msg.Params[1] message := msg.Params[2:] - sourceString := fmt.Sprintf(npcNickMask, fakeSource, client.nick) - _, err := CasefoldName(fakeSource) - if err != nil { - client.Send(nil, client.server.name, ERR_CANNOTSENDRP, target, client.t("Fake source must be a valid nickname")) - return false - } - - sendRoleplayMessage(server, client, sourceString, target, true, message, rb) + sendRoleplayMessage(server, client, fakeSource, target, false, true, message, rb) return false } @@ -2623,9 +2608,8 @@ func sanickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re func sceneHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { target := msg.Params[0] message := msg.Params[1:] - sourceString := fmt.Sprintf(sceneNickMask, client.nick) - sendRoleplayMessage(server, client, sourceString, target, false, message, rb) + sendRoleplayMessage(server, client, "", target, true, false, message, rb) return false } diff --git a/irc/roleplay.go b/irc/roleplay.go index fdd59584..14f9dfe4 100644 --- a/irc/roleplay.go +++ b/irc/roleplay.go @@ -4,7 +4,8 @@ package irc import ( - "bytes" + "fmt" + "strings" "github.com/oragono/oragono/irc/history" "github.com/oragono/oragono/irc/modes" @@ -16,9 +17,9 @@ const ( sceneNickMask = "=Scene=!%s@npc.fakeuser.invalid" ) -func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isAction bool, messageParts []string, rb *ResponseBuffer) { +func sendRoleplayMessage(server *Server, client *Client, source string, targetString string, isScene, isAction bool, messageParts []string, rb *ResponseBuffer) { config := server.Config() - if !config.Roleplay.enabled { + if !config.Roleplay.Enabled { rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Roleplaying has been disabled by the server administrators")) return } @@ -27,12 +28,26 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt return } + var sourceMask string + if isScene { + sourceMask = fmt.Sprintf(sceneNickMask, client.Nick()) + } else { + cfSource, cfSourceErr := CasefoldName(source) + skelSource, skelErr := Skeleton(source) + if cfSourceErr != nil || skelErr != nil || + restrictedCasefoldedNicks.Has(cfSource) || restrictedSkeletons.Has(skelSource) { + rb.Add(nil, client.server.name, ERR_CANNOTSENDRP, targetString, client.t("Invalid roleplay name")) + return + } + sourceMask = fmt.Sprintf(npcNickMask, source, client.Nick()) + } + // block attempts to send CTCP messages to Tor clients if len(messageParts) > 0 && len(messageParts[0]) > 0 && messageParts[0][0] == '\x01' { return } - var buf bytes.Buffer + var buf strings.Builder if isAction { buf.WriteString("\x01ACTION ") } @@ -80,9 +95,9 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt // of roleplay commands, so send them a copy whether they have echo-message // or not if rb.session == session { - rb.AddSplitMessageFromClient(source, "", nil, "PRIVMSG", targetString, splitMessage) + rb.AddSplitMessageFromClient(sourceMask, "", nil, "PRIVMSG", targetString, splitMessage) } else { - session.sendSplitMsgFromClientInternal(false, source, "*", nil, "PRIVMSG", targetString, splitMessage) + session.sendSplitMsgFromClientInternal(false, sourceMask, "*", nil, "PRIVMSG", targetString, splitMessage) } } } @@ -90,7 +105,7 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt channel.AddHistoryItem(history.Item{ Type: history.Privmsg, Message: splitMessage, - Nick: source, + Nick: sourceMask, }, client.Account()) } else { target, err := CasefoldName(targetString) @@ -108,7 +123,7 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt cnick := client.Nick() tnick := user.Nick() for _, session := range user.Sessions() { - session.sendSplitMsgFromClientInternal(false, source, "*", nil, "PRIVMSG", tnick, splitMessage) + session.sendSplitMsgFromClientInternal(false, sourceMask, "*", nil, "PRIVMSG", tnick, splitMessage) } if away, awayMessage := user.Away(); away { //TODO(dan): possibly implement cooldown of away notifications to users