( channelId: string, slackUserId: string )
| 745 | * so we use local working group membership for access control (fast, no API calls). |
| 746 | */ |
| 747 | export async function checkChannelAccess( |
| 748 | channelId: string, |
| 749 | slackUserId: string |
| 750 | ): Promise<{ hasAccess: boolean; isPrivate: boolean; reason?: string }> { |
| 751 | try { |
| 752 | const channelInfo = await getChannelInfo(channelId); |
| 753 | if (!channelInfo) { |
| 754 | return { hasAccess: false, isPrivate: false, reason: 'Channel not found' }; |
| 755 | } |
| 756 | |
| 757 | // Public channels are accessible to all workspace members |
| 758 | if (!channelInfo.is_private) { |
| 759 | return { hasAccess: true, isPrivate: false }; |
| 760 | } |
| 761 | |
| 762 | // Private channel - check local working group membership |
| 763 | const wgDb = getWorkingGroupDb(); |
| 764 | const workingGroup = await wgDb.getWorkingGroupBySlackChannelId(channelId); |
| 765 | |
| 766 | if (!workingGroup) { |
| 767 | // Private channel without a working group is not indexed |
| 768 | return { |
| 769 | hasAccess: false, |
| 770 | isPrivate: true, |
| 771 | reason: 'This private channel is not indexed (no linked working group)', |
| 772 | }; |
| 773 | } |
| 774 | |
| 775 | // Check local membership |
| 776 | const slackDb = getSlackDb(); |
| 777 | const mapping = await slackDb.getBySlackUserId(slackUserId); |
| 778 | |
| 779 | if (mapping?.workos_user_id) { |
| 780 | const isMember = await wgDb.isMember(workingGroup.id, mapping.workos_user_id); |
| 781 | if (isMember) { |
| 782 | return { hasAccess: true, isPrivate: true }; |
| 783 | } |
| 784 | } |
| 785 | |
| 786 | return { |
| 787 | hasAccess: false, |
| 788 | isPrivate: true, |
| 789 | reason: 'You are not a member of this private channel', |
| 790 | }; |
| 791 | } catch (error) { |
| 792 | logger.warn({ error, channelId, slackUserId }, 'Failed to check channel access'); |
| 793 | // Fail closed - deny access on error |
| 794 | return { hasAccess: false, isPrivate: false, reason: 'Failed to verify access' }; |
| 795 | } |
| 796 | } |
| 797 | |
| 798 | /** |
| 799 | * Find a channel by name (partial match) and check user access |
no test coverage detected