fix: wire permission checks into message/channel handlers
- Add CheckChannelPermission to permissions.Checker (layers channel overrides on top of role permissions) - Refactor requireChannelAccess to accept required permission bitmap - Message Create checks SEND_MESSAGES; List/Search check VIEW_CHANNEL - BulkDelete uses Checker.CheckPermission for MANAGE_MESSAGES - Channel handler List filters out channels user cannot view - Remove dead checkPermission method from message handler - Fix frontend avatar upload: parse response URL, call updateProfile
This commit is contained in:
@@ -80,3 +80,63 @@ func (c *Checker) CheckPermission(ctx context.Context, serverID string, userID s
|
||||
|
||||
return Has(perms, required), nil
|
||||
}
|
||||
|
||||
// CheckChannelPermission reports whether the user has the required permission bits
|
||||
// for a specific channel. It layers channel-level overrides on top of server role
|
||||
// permissions. ADMINISTRATOR bypasses all checks.
|
||||
func (c *Checker) CheckChannelPermission(ctx context.Context, serverID, userID, channelID string, required int64) (bool, error) {
|
||||
perms, err := c.GetUserPermissions(ctx, serverID, userID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Administrator bypasses everything.
|
||||
if Has(perms, ADMINISTRATOR) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Layer channel overrides: apply deny first (subtract), then allow (add).
|
||||
// Role-based overrides from all user roles, then user-specific override.
|
||||
rows, err := c.db.QueryContext(ctx, `
|
||||
SELECT co.allow_bitflags, co.deny_bitflags
|
||||
FROM channel_overrides co
|
||||
WHERE co.channel_id = $1 AND co.target_type = 'role'
|
||||
AND co.target_id IN (
|
||||
SELECT mr.role_id FROM member_roles mr WHERE mr.user_id = $2 AND mr.server_id = $3
|
||||
)
|
||||
`, channelID, userID, serverID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var allow, deny int64
|
||||
if rows != nil {
|
||||
for rows.Next() {
|
||||
var a, d int64
|
||||
if err := rows.Scan(&a, &d); err != nil {
|
||||
rows.Close()
|
||||
return false, err
|
||||
}
|
||||
allow |= a
|
||||
deny |= d
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
// User-specific override.
|
||||
var ua, ud int64
|
||||
err = c.db.QueryRowContext(ctx, `
|
||||
SELECT allow_bitflags, deny_bitflags FROM channel_overrides
|
||||
WHERE channel_id = $1 AND target_type = 'user' AND target_id = $2
|
||||
`, channelID, userID).Scan(&ua, &ud)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
allow |= ua
|
||||
deny |= ud
|
||||
|
||||
// Apply deny first, then allow.
|
||||
perms = (perms &^ deny) | allow
|
||||
|
||||
return Has(perms, required), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user