feat(permissions): filter guild channels by VIEW_CHANNEL in view()
Hide channels denied via role or channel overwrite from view().channels, guard selectChannel with memberCanViewChannel, and reassign activeChannelId to the first visible text channel when the current selection becomes hidden after loadGuild or permission gossip. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -117,6 +117,7 @@ const {
|
|||||||
PERMISSION,
|
PERMISSION,
|
||||||
roleHasPermission,
|
roleHasPermission,
|
||||||
memberCanParticipate,
|
memberCanParticipate,
|
||||||
|
memberCanViewChannel,
|
||||||
memberCanConnectVoice,
|
memberCanConnectVoice,
|
||||||
memberCanSpeakInVoice,
|
memberCanSpeakInVoice,
|
||||||
memberCanJoinVoiceListenOnly,
|
memberCanJoinVoiceListenOnly,
|
||||||
@@ -2168,6 +2169,34 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
return effectivePermissionMask(member, customRoles, overwrites)
|
return effectivePermissionMask(member, customRoles, overwrites)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _canViewChannel (channelId) {
|
||||||
|
if (this.mode !== 'guild' || !this.guild?.guild) return true
|
||||||
|
const member = await this._resolveMemberRecord()
|
||||||
|
if (!member) return false
|
||||||
|
const customRoles = this.guildRoles
|
||||||
|
? await this.guildRoles.listRoles(this.guild.guild.id)
|
||||||
|
: []
|
||||||
|
const overwrites = await this._channelOverwrites(channelId)
|
||||||
|
const mask = effectivePermissionMask(member, customRoles, overwrites)
|
||||||
|
return memberCanViewChannel(member, customRoles, mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
async _filterVisibleChannels (channels = []) {
|
||||||
|
if (this.mode !== 'guild' || !this.guild?.guild) return channels
|
||||||
|
const member = await this._resolveMemberRecord()
|
||||||
|
if (!member) return []
|
||||||
|
const customRoles = this.guildRoles
|
||||||
|
? await this.guildRoles.listRoles(this.guild.guild.id)
|
||||||
|
: []
|
||||||
|
const visible = []
|
||||||
|
for (const ch of channels) {
|
||||||
|
const overwrites = await this._channelOverwrites(ch.id)
|
||||||
|
const mask = effectivePermissionMask(member, customRoles, overwrites)
|
||||||
|
if (memberCanViewChannel(member, customRoles, mask)) visible.push(ch)
|
||||||
|
}
|
||||||
|
return visible
|
||||||
|
}
|
||||||
|
|
||||||
async _initBotEvents (guildId) {
|
async _initBotEvents (guildId) {
|
||||||
this.botEvents = new BotEventFanout({
|
this.botEvents = new BotEventFanout({
|
||||||
guildId,
|
guildId,
|
||||||
@@ -2404,6 +2433,9 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
|
|
||||||
async selectChannel (channelId) {
|
async selectChannel (channelId) {
|
||||||
if (this.mode === 'guild' && this.guild?.guild) {
|
if (this.mode === 'guild' && this.guild?.guild) {
|
||||||
|
if (!(await this._canViewChannel(channelId))) {
|
||||||
|
throw new Error('no permission to view channel')
|
||||||
|
}
|
||||||
const ch = await this.db.get(COLLECTIONS.CHANNELS, {
|
const ch = await this.db.get(COLLECTIONS.CHANNELS, {
|
||||||
guildId: this.guild.guild.id,
|
guildId: this.guild.guild.id,
|
||||||
id: channelId
|
id: channelId
|
||||||
@@ -4750,12 +4782,29 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
let messages = []
|
let messages = []
|
||||||
let dmConversations = []
|
let dmConversations = []
|
||||||
if (guild && this.guild) {
|
if (guild && this.guild) {
|
||||||
channels = await this.guild.listChannels()
|
const allChannels = await this.guild.listChannels()
|
||||||
members = await this.guild.listMembers()
|
members = await this.guild.listMembers()
|
||||||
await this._initGuildRoles(guild.id).catch(() => {})
|
await this._initGuildRoles(guild.id).catch(() => {})
|
||||||
if (this.guildRoles) {
|
if (this.guildRoles) {
|
||||||
members = await this.guildRoles.attachCustomRolesToMembers(guild.id, members)
|
members = await this.guildRoles.attachCustomRolesToMembers(guild.id, members)
|
||||||
}
|
}
|
||||||
|
channels = await this._filterVisibleChannels(allChannels)
|
||||||
|
if (
|
||||||
|
this.activeChannelId &&
|
||||||
|
!channels.some((c) => c.id === this.activeChannelId)
|
||||||
|
) {
|
||||||
|
const fallback =
|
||||||
|
channels.find((c) => c.type === 'text') ||
|
||||||
|
channels.find((c) => c.type === 'announcement') ||
|
||||||
|
channels[0]
|
||||||
|
this.activeChannelId = fallback?.id || null
|
||||||
|
if (this.messages && guild && this.activeChannelId) {
|
||||||
|
this.messages.setChannel({
|
||||||
|
channelId: this.activeChannelId,
|
||||||
|
guildId: guild.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.mode === 'dm' && this.dm?.channel) {
|
if (this.mode === 'dm' && this.dm?.channel) {
|
||||||
channels = [this.dm.channel]
|
channels = [this.dm.channel]
|
||||||
|
|||||||
Reference in New Issue
Block a user