mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
commit
9a6e3025c2
@ -541,10 +541,16 @@ func (channel *Channel) ClientPrefixes(client *Client, isMultiPrefix bool) strin
|
||||
|
||||
func (channel *Channel) ClientHasPrivsOver(client *Client, target *Client) bool {
|
||||
channel.stateMutex.RLock()
|
||||
founder := channel.registeredFounder
|
||||
clientModes := channel.members[client]
|
||||
targetModes := channel.members[target]
|
||||
channel.stateMutex.RUnlock()
|
||||
|
||||
if founder != "" && founder == client.Account() {
|
||||
// #950: founder can kick or whatever without actually having the +q mode
|
||||
return true
|
||||
}
|
||||
|
||||
return channelUserModeHasPrivsOver(clientModes.HighestChannelUserMode(), targetModes.HighestChannelUserMode())
|
||||
}
|
||||
|
||||
@ -1064,6 +1070,25 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
|
||||
message := fmt.Sprintf(client.t("%[1]s changed nick to %[2]s"), nick, item.Params[0])
|
||||
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), histServMask, "*", nil, "PRIVMSG", chname, message)
|
||||
}
|
||||
case history.Topic:
|
||||
if eventPlayback {
|
||||
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "TOPIC", chname, item.Message.Message)
|
||||
} else {
|
||||
message := fmt.Sprintf(client.t("%[1]s set the channel topic to: %[2]s"), nick, item.Message.Message)
|
||||
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), histServMask, "*", nil, "PRIVMSG", chname, message)
|
||||
}
|
||||
case history.Mode:
|
||||
params := make([]string, len(item.Message.Split)+1)
|
||||
params[0] = chname
|
||||
for i, pair := range item.Message.Split {
|
||||
params[i+1] = pair.Message
|
||||
}
|
||||
if eventPlayback {
|
||||
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "MODE", params...)
|
||||
} else {
|
||||
message := fmt.Sprintf(client.t("%[1]s set channel modes: %[2]s"), nick, strings.Join(params[1:], " "))
|
||||
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), histServMask, "*", nil, "PRIVMSG", chname, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1113,22 +1138,30 @@ func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffe
|
||||
}
|
||||
|
||||
channel.stateMutex.Lock()
|
||||
chname := channel.name
|
||||
channel.topic = topic
|
||||
channel.topicSetBy = client.nickMaskString
|
||||
channel.topicSetTime = time.Now().UTC()
|
||||
channel.stateMutex.Unlock()
|
||||
|
||||
prefix := client.NickMaskString()
|
||||
details := client.Details()
|
||||
message := utils.MakeMessage(topic)
|
||||
rb.AddFromClient(message.Time, message.Msgid, details.nickMask, details.accountName, nil, "TOPIC", chname, topic)
|
||||
for _, member := range channel.Members() {
|
||||
for _, session := range member.Sessions() {
|
||||
if session == rb.session {
|
||||
rb.Add(nil, prefix, "TOPIC", channel.name, topic)
|
||||
} else {
|
||||
session.Send(nil, prefix, "TOPIC", channel.name, topic)
|
||||
if session != rb.session {
|
||||
session.sendFromClientInternal(false, message.Time, message.Msgid, details.nickMask, details.accountName, nil, "TOPIC", chname, topic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
channel.AddHistoryItem(history.Item{
|
||||
Type: history.Topic,
|
||||
Nick: details.nickMask,
|
||||
AccountName: details.accountName,
|
||||
Message: message,
|
||||
})
|
||||
|
||||
channel.MarkDirty(IncludeTopic)
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ func csAmodeHandler(server *Server, client *Client, command string, params []str
|
||||
if member.Account() == change.Arg {
|
||||
applied, change := channel.applyModeToMember(client, change, rb)
|
||||
if applied {
|
||||
announceCmodeChanges(channel, modes.ModeChanges{change}, chanservMask, rb)
|
||||
announceCmodeChanges(channel, modes.ModeChanges{change}, chanservMask, "*", rb)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -291,7 +291,7 @@ func csOpHandler(server *Server, client *Client, command string, params []string
|
||||
},
|
||||
rb)
|
||||
if applied {
|
||||
announceCmodeChanges(channelInfo, modes.ModeChanges{change}, chanservMask, rb)
|
||||
announceCmodeChanges(channelInfo, modes.ModeChanges{change}, chanservMask, "*", rb)
|
||||
}
|
||||
|
||||
csNotice(rb, fmt.Sprintf(client.t("Successfully op'd in channel %s"), channelName))
|
||||
@ -343,7 +343,7 @@ func csRegisterHandler(server *Server, client *Client, command string, params []
|
||||
},
|
||||
rb)
|
||||
if applied {
|
||||
announceCmodeChanges(channelInfo, modes.ModeChanges{change}, chanservMask, rb)
|
||||
announceCmodeChanges(channelInfo, modes.ModeChanges{change}, chanservMask, "*", rb)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,9 +205,18 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick
|
||||
// the client may just be changing case
|
||||
if currentClient != nil && currentClient != client && session != nil {
|
||||
// these conditions forbid reattaching to an existing session:
|
||||
if registered || !bouncerAllowed || account == "" || account != currentClient.Account() || client.HasMode(modes.TLS) != currentClient.HasMode(modes.TLS) {
|
||||
if registered || !bouncerAllowed || account == "" || account != currentClient.Account() {
|
||||
return "", errNicknameInUse
|
||||
}
|
||||
// check TLS modes
|
||||
if client.HasMode(modes.TLS) != currentClient.HasMode(modes.TLS) {
|
||||
if useAccountName {
|
||||
// #955: this is fatal because they can't fix it by trying a different nick
|
||||
return "", errInsecureReattach
|
||||
} else {
|
||||
return "", errNicknameInUse
|
||||
}
|
||||
}
|
||||
reattachSuccessful, numSessions, lastSeen := currentClient.AddSession(session)
|
||||
if !reattachSuccessful {
|
||||
return "", errNicknameInUse
|
||||
|
@ -42,6 +42,7 @@ var (
|
||||
errNickMissing = errors.New("nick missing")
|
||||
errNicknameInvalid = errors.New("invalid nickname")
|
||||
errNicknameInUse = errors.New("nickname in use")
|
||||
errInsecureReattach = errors.New("insecure reattach")
|
||||
errNicknameReserved = errors.New("nickname is reserved")
|
||||
errNickAccountMismatch = errors.New(`Your nickname must match your account name; try logging out and logging back in with SASL`)
|
||||
errNoExistingBan = errors.New("Ban does not exist")
|
||||
|
@ -1520,24 +1520,35 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
|
||||
}
|
||||
// process mode changes, include list operations (an empty set of changes does a list)
|
||||
applied := channel.ApplyChannelModeChanges(client, msg.Command == "SAMODE", changes, rb)
|
||||
announceCmodeChanges(channel, applied, client.NickMaskString(), rb)
|
||||
details := client.Details()
|
||||
announceCmodeChanges(channel, applied, details.nickMask, details.accountName, rb)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func announceCmodeChanges(channel *Channel, applied modes.ModeChanges, source string, rb *ResponseBuffer) {
|
||||
func announceCmodeChanges(channel *Channel, applied modes.ModeChanges, source, accountName string, rb *ResponseBuffer) {
|
||||
// send out changes
|
||||
if len(applied) > 0 {
|
||||
//TODO(dan): we should change the name of String and make it return a slice here
|
||||
args := append([]string{channel.name}, applied.Strings()...)
|
||||
rb.Add(nil, source, "MODE", args...)
|
||||
message := utils.MakeMessage("")
|
||||
changeStrings := applied.Strings()
|
||||
for _, changeString := range changeStrings {
|
||||
message.Split = append(message.Split, utils.MessagePair{Message: changeString})
|
||||
}
|
||||
args := append([]string{channel.name}, changeStrings...)
|
||||
rb.AddFromClient(message.Time, message.Msgid, source, accountName, nil, "MODE", args...)
|
||||
for _, member := range channel.Members() {
|
||||
for _, session := range member.Sessions() {
|
||||
if session != rb.session {
|
||||
session.Send(nil, source, "MODE", args...)
|
||||
session.sendFromClientInternal(false, message.Time, message.Msgid, source, accountName, nil, "MODE", args...)
|
||||
}
|
||||
}
|
||||
}
|
||||
channel.AddHistoryItem(history.Item{
|
||||
Type: history.Mode,
|
||||
Nick: source,
|
||||
AccountName: accountName,
|
||||
Message: message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -2054,7 +2065,7 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
}
|
||||
|
||||
// must pass at least one check, and all enabled checks
|
||||
var checkPassed, checkFailed bool
|
||||
var checkPassed, checkFailed, passwordFailed bool
|
||||
oper := server.GetOperator(msg.Params[0])
|
||||
if oper != nil {
|
||||
if oper.Fingerprint != "" {
|
||||
@ -2065,8 +2076,11 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
}
|
||||
}
|
||||
if !checkFailed && oper.Pass != nil {
|
||||
if len(msg.Params) == 1 || bcrypt.CompareHashAndPassword(oper.Pass, []byte(msg.Params[1])) != nil {
|
||||
if len(msg.Params) == 1 {
|
||||
checkFailed = true
|
||||
} else if bcrypt.CompareHashAndPassword(oper.Pass, []byte(msg.Params[1])) != nil {
|
||||
checkFailed = true
|
||||
passwordFailed = true
|
||||
} else {
|
||||
checkPassed = true
|
||||
}
|
||||
@ -2075,11 +2089,18 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
||||
|
||||
if !checkPassed || checkFailed {
|
||||
rb.Add(nil, server.name, ERR_PASSWDMISMATCH, client.Nick(), client.t("Password incorrect"))
|
||||
client.Quit(client.t("Password incorrect"), rb.session)
|
||||
return true
|
||||
// #951: only disconnect them if we actually tried to check a password for them
|
||||
if passwordFailed {
|
||||
client.Quit(client.t("Password incorrect"), rb.session)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
applyOper(client, oper, rb)
|
||||
if oper != nil {
|
||||
applyOper(client, oper, rb)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ const (
|
||||
Mode
|
||||
Tagmsg
|
||||
Nick
|
||||
Topic
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -25,12 +25,11 @@ var (
|
||||
restrictedSkeletons = make(map[string]bool)
|
||||
)
|
||||
|
||||
// returns whether the change succeeded or failed
|
||||
func performNickChange(server *Server, client *Client, target *Client, session *Session, nickname string, rb *ResponseBuffer) bool {
|
||||
func performNickChange(server *Server, client *Client, target *Client, session *Session, nickname string, rb *ResponseBuffer) error {
|
||||
currentNick := client.Nick()
|
||||
details := target.Details()
|
||||
if details.nick == nickname {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
hadNick := details.nick != "*"
|
||||
origNickMask := details.nickMask
|
||||
@ -52,7 +51,7 @@ func performNickChange(server *Server, client *Client, target *Client, session *
|
||||
rb.Add(nil, server.name, ERR_UNKNOWNERROR, currentNick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
|
||||
}
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
|
||||
message := utils.MakeMessage("")
|
||||
@ -88,7 +87,7 @@ func performNickChange(server *Server, client *Client, target *Client, session *
|
||||
client.server.monitorManager.AlertAbout(target, true)
|
||||
target.nickTimer.Touch(rb)
|
||||
} // else: these will be deferred to the end of registration (see #572)
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (server *Server) RandomlyRename(client *Client) {
|
||||
@ -124,7 +123,7 @@ func fixupNickEqualsAccount(client *Client, rb *ResponseBuffer, config *Config)
|
||||
if !client.registered {
|
||||
return true
|
||||
}
|
||||
if !performNickChange(client.server, client, client, rb.session, client.AccountName(), rb) {
|
||||
if performNickChange(client.server, client, client, rb.session, client.AccountName(), rb) != nil {
|
||||
client.server.accounts.Logout(client)
|
||||
nsNotice(rb, client.t("A client is already using that account; try logging out and logging back in with SASL"))
|
||||
return false
|
||||
|
@ -343,11 +343,14 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
|
||||
}
|
||||
|
||||
rb := NewResponseBuffer(session)
|
||||
nickAssigned := performNickChange(server, c, c, session, c.preregNick, rb)
|
||||
nickError := performNickChange(server, c, c, session, c.preregNick, rb)
|
||||
rb.Send(true)
|
||||
if !nickAssigned {
|
||||
if nickError == errInsecureReattach {
|
||||
c.Quit(c.t("You can't mix secure and insecure connections to this account"), nil)
|
||||
return true
|
||||
} else if nickError != nil {
|
||||
c.preregNick = ""
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
if session.client != c {
|
||||
@ -355,7 +358,7 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
|
||||
// we'll play the reg burst later, on the new goroutine associated with
|
||||
// (thisSession, otherClient). This is to avoid having to transfer state
|
||||
// like nickname, hostname, etc. to show the correct values in the reg burst.
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
// check KLINEs
|
||||
|
Loading…
Reference in New Issue
Block a user