mirror of
				https://github.com/ergochat/ergo.git
				synced 2025-10-31 22:07:23 +01:00 
			
		
		
		
	fix #1176
Transition most "is an operator" checks to require a specific operator capability
This commit is contained in:
		
							parent
							
								
									4c08bc9c49
								
							
						
					
					
						commit
						42316bc04f
					
				| @ -593,6 +593,7 @@ oper-classes: | ||||
|             - "vhosts" | ||||
|             - "sajoin" | ||||
|             - "samode" | ||||
|             - "snomasks" | ||||
| 
 | ||||
|     # server admin: has full control of the ircd, including nickname and | ||||
|     # channel registrations | ||||
|  | ||||
| @ -439,7 +439,7 @@ func (channel *Channel) Names(client *Client, rb *ResponseBuffer) { | ||||
| 	channel.stateMutex.RLock() | ||||
| 	clientData, isJoined := channel.members[client] | ||||
| 	channel.stateMutex.RUnlock() | ||||
| 	isOper := client.HasMode(modes.Operator) | ||||
| 	isOper := client.HasRoleCapabs("sajoin") | ||||
| 	respectAuditorium := channel.flags.HasMode(modes.Auditorium) && !isOper && | ||||
| 		(!isJoined || clientData.modes.HighestChannelUserMode() == modes.Mode(0)) | ||||
| 	isMultiPrefix := rb.session.capabilities.Has(caps.MultiPrefix) | ||||
| @ -607,7 +607,7 @@ func (channel *Channel) hasClient(client *Client) bool { | ||||
| 
 | ||||
| // <mode> <mode params> | ||||
| func (channel *Channel) modeStrings(client *Client) (result []string) { | ||||
| 	hasPrivs := client.HasMode(modes.Operator) | ||||
| 	hasPrivs := client.HasRoleCapabs("sajoin") | ||||
| 
 | ||||
| 	channel.stateMutex.RLock() | ||||
| 	defer channel.stateMutex.RUnlock() | ||||
| @ -1245,12 +1245,12 @@ func (channel *Channel) SendTopic(client *Client, rb *ResponseBuffer, sendNoTopi | ||||
| 
 | ||||
| // SetTopic sets the topic of this channel, if the client is allowed to do so. | ||||
| func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffer) { | ||||
| 	if !(client.HasMode(modes.Operator) || channel.hasClient(client)) { | ||||
| 	if !channel.hasClient(client) { | ||||
| 		rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), channel.Name(), client.t("You're not on that channel")) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if channel.flags.HasMode(modes.OpOnlyTopic) && !channel.ClientIsAtLeast(client, modes.Halfop) { | ||||
| 	if channel.flags.HasMode(modes.OpOnlyTopic) && !(channel.ClientIsAtLeast(client, modes.Halfop) || client.HasRoleCapabs("samode")) { | ||||
| 		rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.Name(), client.t("You're not a channel operator")) | ||||
| 		return | ||||
| 	} | ||||
| @ -1487,10 +1487,6 @@ func (channel *Channel) Quit(client *Client) { | ||||
| 
 | ||||
| func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer, hasPrivs bool) { | ||||
| 	if !hasPrivs { | ||||
| 		if !(client.HasMode(modes.Operator) || channel.hasClient(client)) { | ||||
| 			rb.Add(nil, client.server.name, ERR_NOTONCHANNEL, client.Nick(), channel.Name(), client.t("You're not on that channel")) | ||||
| 			return | ||||
| 		} | ||||
| 		if !channel.ClientHasPrivsOver(client, target) { | ||||
| 			rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, client.Nick(), channel.Name(), client.t("You don't have enough channel privileges")) | ||||
| 			return | ||||
|  | ||||
| @ -860,7 +860,7 @@ func csHowToBanHandler(service *ircService, server *Server, client *Client, comm | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if !(channel.ClientIsAtLeast(client, modes.Operator) || client.HasRoleCapabs("samode")) { | ||||
| 	if !(channel.ClientIsAtLeast(client, modes.ChannelOperator) || client.HasRoleCapabs("samode")) { | ||||
| 		service.Notice(rb, client.t("Insufficient privileges")) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @ -1512,7 +1512,7 @@ func (client *Client) destroy(session *Session) { | ||||
| 	// decrement stats if we have no more sessions, even if the client will not be destroyed | ||||
| 	if shouldDecrement { | ||||
| 		invisible := client.HasMode(modes.Invisible) | ||||
| 		operator := client.HasMode(modes.LocalOperator) || client.HasMode(modes.Operator) | ||||
| 		operator := client.HasMode(modes.Operator) | ||||
| 		client.server.stats.Remove(registered, invisible, operator) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -222,7 +222,7 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick | ||||
| 		} | ||||
| 		if numSessions == 1 { | ||||
| 			invisible := currentClient.HasMode(modes.Invisible) | ||||
| 			operator := currentClient.HasMode(modes.Operator) || currentClient.HasMode(modes.LocalOperator) | ||||
| 			operator := currentClient.HasMode(modes.Operator) | ||||
| 			client.server.stats.AddRegistered(invisible, operator) | ||||
| 		} | ||||
| 		session.autoreplayMissedSince = lastSeen | ||||
|  | ||||
| @ -7,13 +7,11 @@ package irc | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/goshuirc/irc-go/ircmsg" | ||||
| 	"github.com/oragono/oragono/irc/modes" | ||||
| ) | ||||
| 
 | ||||
| // Command represents a command accepted from a client. | ||||
| type Command struct { | ||||
| 	handler        func(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool | ||||
| 	oper           bool | ||||
| 	usablePreReg   bool | ||||
| 	allowedInBatch bool // allowed in client-to-server batches | ||||
| 	minParams      int | ||||
| @ -32,10 +30,6 @@ func (cmd *Command) Run(server *Server, client *Client, session *Session, msg ir | ||||
| 			rb.Add(nil, server.name, ERR_NOTREGISTERED, "*", client.t("You need to register before you can use that command")) | ||||
| 			return false | ||||
| 		} | ||||
| 		if cmd.oper && !client.HasMode(modes.Operator) { | ||||
| 			rb.Add(nil, server.name, ERR_NOPRIVILEGES, client.Nick(), client.t("Permission Denied - You're not an IRC operator")) | ||||
| 			return false | ||||
| 		} | ||||
| 		if len(cmd.capabs) > 0 && !client.HasRoleCapabs(cmd.capabs...) { | ||||
| 			rb.Add(nil, server.name, ERR_NOPRIVILEGES, client.Nick(), client.t("Permission Denied")) | ||||
| 			return false | ||||
| @ -115,7 +109,7 @@ func init() { | ||||
| 		"DEBUG": { | ||||
| 			handler:   debugHandler, | ||||
| 			minParams: 1, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"rehash"}, | ||||
| 		}, | ||||
| 		"DEFCON": { | ||||
| 			handler: defconHandler, | ||||
| @ -124,12 +118,11 @@ func init() { | ||||
| 		"DEOPER": { | ||||
| 			handler:   deoperHandler, | ||||
| 			minParams: 0, | ||||
| 			oper:      true, | ||||
| 		}, | ||||
| 		"DLINE": { | ||||
| 			handler:   dlineHandler, | ||||
| 			minParams: 1, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"ban"}, | ||||
| 		}, | ||||
| 		"EXTJWT": { | ||||
| 			handler:   extjwtHandler, | ||||
| @ -169,13 +162,12 @@ func init() { | ||||
| 		"KILL": { | ||||
| 			handler:   killHandler, | ||||
| 			minParams: 1, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"kill"}, | ||||
| 		}, | ||||
| 		"KLINE": { | ||||
| 			handler:   klineHandler, | ||||
| 			minParams: 1, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"ban"}, | ||||
| 		}, | ||||
| 		"LANGUAGE": { | ||||
| 			handler:      languageHandler, | ||||
| @ -278,7 +270,7 @@ func init() { | ||||
| 		"SANICK": { | ||||
| 			handler:   sanickHandler, | ||||
| 			minParams: 2, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"samode"}, | ||||
| 		}, | ||||
| 		"SAMODE": { | ||||
| 			handler:   modeHandler, | ||||
| @ -308,7 +300,6 @@ func init() { | ||||
| 		"REHASH": { | ||||
| 			handler:   rehashHandler, | ||||
| 			minParams: 0, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"rehash"}, | ||||
| 		}, | ||||
| 		"TIME": { | ||||
| @ -327,7 +318,7 @@ func init() { | ||||
| 		"UNDLINE": { | ||||
| 			handler:   unDLineHandler, | ||||
| 			minParams: 1, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"ban"}, | ||||
| 		}, | ||||
| 		"UNINVITE": { | ||||
| 			handler:   inviteHandler, | ||||
| @ -336,7 +327,7 @@ func init() { | ||||
| 		"UNKLINE": { | ||||
| 			handler:   unKLineHandler, | ||||
| 			minParams: 1, | ||||
| 			oper:      true, | ||||
| 			capabs:    []string{"ban"}, | ||||
| 		}, | ||||
| 		"USER": { | ||||
| 			handler:      userHandler, | ||||
|  | ||||
| @ -757,10 +757,6 @@ func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res | ||||
| 		rb.Notice(fmt.Sprintf("CPU profiling stopped")) | ||||
| 
 | ||||
| 	case "CRASHSERVER": | ||||
| 		if !client.HasRoleCapabs("rehash") { | ||||
| 			rb.Notice(client.t("You must have rehash permissions in order to execute DEBUG CRASHSERVER")) | ||||
| 			return false | ||||
| 		} | ||||
| 		code := utils.ConfirmationCode(server.name, server.ctime) | ||||
| 		if len(msg.Params) == 1 || msg.Params[1] != code { | ||||
| 			rb.Notice(fmt.Sprintf(client.t("To confirm, run this command: %s"), fmt.Sprintf("/DEBUG CRASHSERVER %s", code))) | ||||
| @ -1293,6 +1289,7 @@ func sajoinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re | ||||
| 
 | ||||
| // KICK <channel>{,<channel>} <user>{,<user>} [<comment>] | ||||
| func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { | ||||
| 	hasPrivs := client.HasRoleCapabs("samode") | ||||
| 	channels := strings.Split(msg.Params[0], ",") | ||||
| 	users := strings.Split(msg.Params[1], ",") | ||||
| 	if (len(channels) != len(users)) && (len(users) != 1) { | ||||
| @ -1336,7 +1333,7 @@ func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp | ||||
| 		if comment == "" { | ||||
| 			comment = kick.nick | ||||
| 		} | ||||
| 		channel.Kick(client, target, comment, rb, false) | ||||
| 		channel.Kick(client, target, comment, rb, hasPrivs) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| @ -1618,7 +1615,7 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp | ||||
| 		rb.Add(nil, client.server.name, RPL_LIST, nick, name, strconv.Itoa(members), topic) | ||||
| 	} | ||||
| 
 | ||||
| 	clientIsOp := client.HasMode(modes.Operator) | ||||
| 	clientIsOp := client.HasRoleCapabs("sajoin") | ||||
| 	if len(channels) == 0 { | ||||
| 		for _, channel := range server.channels.Channels() { | ||||
| 			if !clientIsOp && channel.flags.HasMode(modes.Secret) { | ||||
| @ -1775,7 +1772,7 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res | ||||
| 		rb.Add(nil, cDetails.nickMask, "MODE", args...) | ||||
| 	} else if hasPrivs { | ||||
| 		rb.Add(nil, server.name, RPL_UMODEIS, targetNick, target.ModeString()) | ||||
| 		if target.HasMode(modes.LocalOperator) || target.HasMode(modes.Operator) { | ||||
| 		if target.HasMode(modes.Operator) { | ||||
| 			masks := server.snomasks.String(target) | ||||
| 			if 0 < len(masks) { | ||||
| 				rb.Add(nil, server.name, RPL_SNOMASKIS, targetNick, masks, client.t("Server notice masks")) | ||||
| @ -1959,7 +1956,7 @@ func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res | ||||
| 	success := false | ||||
| 	channel := server.channels.Get(chname) | ||||
| 	if channel != nil { | ||||
| 		if !channel.flags.HasMode(modes.Secret) || channel.hasClient(client) || client.HasMode(modes.Operator) { | ||||
| 		if !channel.flags.HasMode(modes.Secret) || channel.hasClient(client) || client.HasRoleCapabs("sajoin") { | ||||
| 			channel.Names(client, rb) | ||||
| 			success = true | ||||
| 		} | ||||
| @ -2338,6 +2335,10 @@ func applyOper(client *Client, oper *Oper, rb *ResponseBuffer) { | ||||
| 
 | ||||
| // DEOPER | ||||
| func deoperHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { | ||||
| 	if client.Oper() == nil { | ||||
| 		rb.Notice(client.t("Insufficient oper privs")) | ||||
| 		return false | ||||
| 	} | ||||
| 	// pretend they sent /MODE $nick -o | ||||
| 	fakeModeMsg := ircmsg.MakeMessage(nil, "", "MODE", client.Nick(), "-o") | ||||
| 	return umodeHandler(server, client, fakeModeMsg, rb) | ||||
| @ -2944,7 +2945,7 @@ func operStatusVisible(client, target *Client, hasPrivs bool) bool { | ||||
| 
 | ||||
| // USERHOST <nickname>{ <nickname>} | ||||
| func userhostHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { | ||||
| 	hasPrivs := client.HasMode(modes.Operator) // TODO(#1176) figure out the right capab for this | ||||
| 	hasPrivs := client.HasMode(modes.Operator) | ||||
| 	returnedClients := make(ClientSet) | ||||
| 
 | ||||
| 	var tl utils.TokenLineBuilder | ||||
| @ -3083,7 +3084,7 @@ func (fields whoxFields) Has(field rune) bool { | ||||
| // <channel> <user> <host> <server> <nick> <H|G>[*][~|&|@|%|+][B] :<hopcount> <real name> | ||||
| // whox format: | ||||
| // <type> <channel> <user> <ip> <host> <server> <nick> <H|G>[*][~|&|@|%|+][B] <hops> <idle> <account> <rank> :<real name> | ||||
| func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer, hasPrivs, includeRFlag, isWhox bool, fields whoxFields, whoType string) { | ||||
| func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer, canSeeIPs, canSeeOpers, includeRFlag, isWhox bool, fields whoxFields, whoType string) { | ||||
| 	params := []string{client.Nick()} | ||||
| 
 | ||||
| 	details := target.Details() | ||||
| @ -3103,7 +3104,7 @@ func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *Response | ||||
| 	} | ||||
| 	if fields.Has('i') { | ||||
| 		fIP := "255.255.255.255" | ||||
| 		if hasPrivs || client == target { | ||||
| 		if canSeeIPs || client == target { | ||||
| 			// you can only see a target's IP if they're you or you're an oper | ||||
| 			fIP = target.IPString() | ||||
| 		} | ||||
| @ -3126,7 +3127,7 @@ func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *Response | ||||
| 			flags.WriteRune('H') // Here | ||||
| 		} | ||||
| 
 | ||||
| 		if target.HasMode(modes.Operator) && operStatusVisible(client, target, hasPrivs) { | ||||
| 		if target.HasMode(modes.Operator) && operStatusVisible(client, target, canSeeOpers) { | ||||
| 			flags.WriteRune('*') | ||||
| 		} | ||||
| 
 | ||||
| @ -3229,23 +3230,23 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo | ||||
| 	//	operatorOnly = true | ||||
| 	//} | ||||
| 
 | ||||
| 	isOper := client.HasMode(modes.Operator) | ||||
| 	oper := client.Oper() | ||||
| 	hasPrivs := oper.HasRoleCapab("sajoin") | ||||
| 	canSeeIPs := oper.HasRoleCapab("ban") | ||||
| 	if mask[0] == '#' { | ||||
| 		// TODO implement wildcard matching | ||||
| 		//TODO(dan): ^ only for opers | ||||
| 		channel := server.channels.Get(mask) | ||||
| 		if channel != nil { | ||||
| 			isJoined := channel.hasClient(client) | ||||
| 			if !channel.flags.HasMode(modes.Secret) || isJoined || isOper { | ||||
| 			if !channel.flags.HasMode(modes.Secret) || isJoined || hasPrivs { | ||||
| 				var members []*Client | ||||
| 				if isOper { | ||||
| 				if hasPrivs { | ||||
| 					members = channel.Members() | ||||
| 				} else { | ||||
| 					members = channel.auditoriumFriends(client) | ||||
| 				} | ||||
| 				for _, member := range members { | ||||
| 					if !member.HasMode(modes.Invisible) || isJoined || isOper { | ||||
| 						client.rplWhoReply(channel, member, rb, isOper, includeRFlag, isWhox, fields, whoType) | ||||
| 					if !member.HasMode(modes.Invisible) || isJoined || hasPrivs { | ||||
| 						client.rplWhoReply(channel, member, rb, canSeeIPs, oper != nil, includeRFlag, isWhox, fields, whoType) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| @ -3275,8 +3276,8 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo | ||||
| 		} | ||||
| 
 | ||||
| 		for mclient := range server.clients.FindAll(mask) { | ||||
| 			if isOper || !mclient.HasMode(modes.Invisible) || isFriend(mclient) { | ||||
| 				client.rplWhoReply(nil, mclient, rb, isOper, includeRFlag, isWhox, fields, whoType) | ||||
| 			if hasPrivs || !mclient.HasMode(modes.Invisible) || isFriend(mclient) { | ||||
| 				client.rplWhoReply(nil, mclient, rb, canSeeIPs, oper != nil, includeRFlag, isWhox, fields, whoType) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -3319,7 +3320,7 @@ func whoisHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	hasPrivs := client.HasMode(modes.Operator) // TODO(#1176) figure out the right capab for this | ||||
| 	hasPrivs := client.HasRoleCapabs("samode") | ||||
| 	if hasPrivs { | ||||
| 		for _, mask := range strings.Split(masksString, ",") { | ||||
| 			matches := server.clients.FindAll(mask) | ||||
|  | ||||
							
								
								
									
										14
									
								
								irc/modes.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								irc/modes.go
									
									
									
									
									
								
							| @ -37,14 +37,14 @@ func ApplyUserModeChanges(client *Client, changes modes.ModeChanges, force bool, | ||||
| 		if change.Mode != modes.ServerNotice { | ||||
| 			switch change.Op { | ||||
| 			case modes.Add: | ||||
| 				if (change.Mode == modes.Operator || change.Mode == modes.LocalOperator) && !(force && oper != nil) { | ||||
| 				if (change.Mode == modes.Operator) && !(force && oper != nil) { | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				if client.SetMode(change.Mode, true) { | ||||
| 					if change.Mode == modes.Invisible { | ||||
| 						client.server.stats.ChangeInvisible(1) | ||||
| 					} else if change.Mode == modes.Operator || change.Mode == modes.LocalOperator { | ||||
| 					} else if change.Mode == modes.Operator { | ||||
| 						client.server.stats.ChangeOperators(1) | ||||
| 					} | ||||
| 					applied = append(applied, change) | ||||
| @ -55,7 +55,7 @@ func ApplyUserModeChanges(client *Client, changes modes.ModeChanges, force bool, | ||||
| 				if client.SetMode(change.Mode, false) { | ||||
| 					if change.Mode == modes.Invisible { | ||||
| 						client.server.stats.ChangeInvisible(-1) | ||||
| 					} else if change.Mode == modes.Operator || change.Mode == modes.LocalOperator { | ||||
| 					} else if change.Mode == modes.Operator { | ||||
| 						removedSnomasks = client.server.snomasks.String(client) | ||||
| 						client.server.stats.ChangeOperators(-1) | ||||
| 						applyOper(client, nil, nil) | ||||
| @ -91,8 +91,12 @@ func ApplyUserModeChanges(client *Client, changes modes.ModeChanges, force bool, | ||||
| 				change.Arg = newArg | ||||
| 			} | ||||
| 			if change.Op == modes.Add { | ||||
| 				client.server.snomasks.AddMasks(client, masks...) | ||||
| 				applied = append(applied, change) | ||||
| 				oper := client.Oper() | ||||
| 				// #1176: require special operator privileges to subscribe to snomasks | ||||
| 				if oper.HasRoleCapab("snomasks") || oper.HasRoleCapab("ban") { | ||||
| 					client.server.snomasks.AddMasks(client, masks...) | ||||
| 					applied = append(applied, change) | ||||
| 				} | ||||
| 			} else if change.Op == modes.Remove { | ||||
| 				client.server.snomasks.RemoveMasks(client, masks...) | ||||
| 				applied = append(applied, change) | ||||
|  | ||||
| @ -101,7 +101,6 @@ func (modes Modes) String() string { | ||||
| const ( | ||||
| 	Bot             Mode = 'B' | ||||
| 	Invisible       Mode = 'i' | ||||
| 	LocalOperator   Mode = 'O' | ||||
| 	Operator        Mode = 'o' | ||||
| 	Restricted      Mode = 'r' | ||||
| 	RegisteredOnly  Mode = 'R' | ||||
|  | ||||
| @ -459,15 +459,13 @@ func (server *Server) MOTD(client *Client, rb *ResponseBuffer) { | ||||
| 	rb.Add(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command")) | ||||
| } | ||||
| 
 | ||||
| // WhoisChannelsNames returns the common channel names between two users. | ||||
| func (client *Client) WhoisChannelsNames(target *Client, multiPrefix bool) []string { | ||||
| func (client *Client) whoisChannelsNames(target *Client, multiPrefix bool, hasPrivs bool) []string { | ||||
| 	var chstrs []string | ||||
| 	targetInvis := target.HasMode(modes.Invisible) | ||||
| 	for _, channel := range target.Channels() { | ||||
| 		// channel is secret and the target can't see it | ||||
| 		if !client.HasMode(modes.Operator) { | ||||
| 			if (target.HasMode(modes.Invisible) || channel.flags.HasMode(modes.Secret)) && !channel.hasClient(client) { | ||||
| 				continue | ||||
| 			} | ||||
| 		if !hasPrivs && (targetInvis || channel.flags.HasMode(modes.Secret)) && !channel.hasClient(client) { | ||||
| 			// client can't see *this* channel membership | ||||
| 			continue | ||||
| 		} | ||||
| 		chstrs = append(chstrs, channel.ClientPrefixes(target, multiPrefix)+channel.name) | ||||
| 	} | ||||
| @ -475,23 +473,26 @@ func (client *Client) WhoisChannelsNames(target *Client, multiPrefix bool) []str | ||||
| } | ||||
| 
 | ||||
| func (client *Client) getWhoisOf(target *Client, hasPrivs bool, rb *ResponseBuffer) { | ||||
| 	oper := client.Oper() | ||||
| 	cnick := client.Nick() | ||||
| 	targetInfo := target.Details() | ||||
| 	rb.Add(nil, client.server.name, RPL_WHOISUSER, cnick, targetInfo.nick, targetInfo.username, targetInfo.hostname, "*", targetInfo.realname) | ||||
| 	tnick := targetInfo.nick | ||||
| 
 | ||||
| 	whoischannels := client.WhoisChannelsNames(target, rb.session.capabilities.Has(caps.MultiPrefix)) | ||||
| 	whoischannels := client.whoisChannelsNames(target, rb.session.capabilities.Has(caps.MultiPrefix), oper.HasRoleCapab("sajoin")) | ||||
| 	if whoischannels != nil { | ||||
| 		rb.Add(nil, client.server.name, RPL_WHOISCHANNELS, cnick, tnick, strings.Join(whoischannels, " ")) | ||||
| 	} | ||||
| 	if target.HasMode(modes.Operator) && operStatusVisible(client, target, hasPrivs) { | ||||
| 	if target.HasMode(modes.Operator) && operStatusVisible(client, target, oper != nil) { | ||||
| 		tOper := target.Oper() | ||||
| 		if tOper != nil { | ||||
| 			rb.Add(nil, client.server.name, RPL_WHOISOPERATOR, cnick, tnick, tOper.WhoisLine) | ||||
| 		} | ||||
| 	} | ||||
| 	if client == target || hasPrivs { | ||||
| 	if client == target || oper.HasRoleCapab("ban") { | ||||
| 		rb.Add(nil, client.server.name, RPL_WHOISACTUALLY, cnick, tnick, fmt.Sprintf("%s@%s", targetInfo.username, target.RawHostname()), target.IPString(), client.t("Actual user@host, Actual IP")) | ||||
| 	} | ||||
| 	if client == target || oper.HasRoleCapab("samode") { | ||||
| 		rb.Add(nil, client.server.name, RPL_WHOISMODES, cnick, tnick, fmt.Sprintf(client.t("is using modes +%s"), target.modes.String())) | ||||
| 	} | ||||
| 	if target.HasMode(modes.TLS) { | ||||
| @ -504,7 +505,7 @@ func (client *Client) getWhoisOf(target *Client, hasPrivs bool, rb *ResponseBuff | ||||
| 		rb.Add(nil, client.server.name, RPL_WHOISBOT, cnick, tnick, fmt.Sprintf(ircfmt.Unescape(client.t("is a $bBot$b on %s")), client.server.Config().Network.Name)) | ||||
| 	} | ||||
| 
 | ||||
| 	if client == target || hasPrivs { | ||||
| 	if client == target || oper.HasRoleCapab("ban") { | ||||
| 		for _, session := range target.Sessions() { | ||||
| 			if session.certfp != "" { | ||||
| 				rb.Add(nil, client.server.name, RPL_WHOISCERTFP, cnick, tnick, fmt.Sprintf(client.t("has client certificate fingerprint %s"), session.certfp)) | ||||
|  | ||||
| @ -565,6 +565,7 @@ oper-classes: | ||||
|             - "vhosts" | ||||
|             - "sajoin" | ||||
|             - "samode" | ||||
|             - "snomasks" | ||||
| 
 | ||||
|     # server admin: has full control of the ircd, including nickname and | ||||
|     # channel registrations | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Shivaram Lingamneni
						Shivaram Lingamneni