38443-vm/includes/permissions.php
2026-02-19 14:42:55 +00:00

126 lines
4.5 KiB
PHP

<?php
class Permissions {
const VIEW_CHANNEL = 1;
const SEND_MESSAGES = 2;
const MANAGE_MESSAGES = 4;
const MANAGE_CHANNELS = 8;
const MANAGE_SERVER = 16;
const ADMINISTRATOR = 32;
const CREATE_THREAD = 64;
const MANAGE_TAGS = 128;
const PIN_THREADS = 256;
const LOCK_THREADS = 512;
const SEND_MESSAGES_IN_THREADS = 1024;
const SPEAK = 2048;
public static function hasPermission($user_id, $server_id, $permission) {
$stmt = db()->prepare("SELECT is_admin FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch();
if ($user && $user['is_admin']) return true;
$stmt = db()->prepare("SELECT owner_id FROM servers WHERE id = ?");
$stmt->execute([$server_id]);
$server = $stmt->fetch();
if ($server && $server['owner_id'] == $user_id) return true;
// Aggregate permissions from user's roles AND the @everyone role
$stmt = db()->prepare("
SELECT BIT_OR(r.permissions) as total_perms
FROM roles r
LEFT JOIN user_roles ur ON r.id = ur.role_id AND ur.user_id = ?
WHERE r.server_id = ? AND (ur.user_id IS NOT NULL OR r.name = '@everyone' OR r.name = 'Everyone')
");
$stmt->execute([$user_id, $server_id]);
$row = $stmt->fetch();
$perms = (int)($row['total_perms'] ?? 0);
if ($perms & self::ADMINISTRATOR) return true;
return ($perms & $permission) === $permission;
}
public static function canViewChannel($user_id, $channel_id) {
return self::canDoInChannel($user_id, $channel_id, self::VIEW_CHANNEL);
}
public static function canSendInChannel($user_id, $channel_id) {
return self::canDoInChannel($user_id, $channel_id, self::SEND_MESSAGES);
}
public static function canDoInChannel($user_id, $channel_id, $permission) {
$stmt = db()->prepare("SELECT server_id FROM channels WHERE id = ?");
$stmt->execute([$channel_id]);
$c = $stmt->fetch();
if (!$c) return false;
$server_id = $c['server_id'];
// Check if owner or admin
if (self::hasPermission($user_id, $server_id, self::ADMINISTRATOR)) return true;
// Fetch all relevant overrides
// 1. @everyone role
// 2. User's roles
// 3. User specifically
// Use a single query to get all relevant overrides
$stmt = db()->prepare("
SELECT cp.user_id, cp.role_id, cp.allow_permissions, cp.deny_permissions, r.name as role_name
FROM channel_permissions cp
LEFT JOIN roles r ON cp.role_id = r.id
LEFT JOIN user_roles ur ON cp.role_id = ur.role_id AND ur.user_id = ?
WHERE cp.channel_id = ? AND (
cp.user_id = ? OR
ur.user_id IS NOT NULL OR
r.name = '@everyone' OR
r.name = 'Everyone'
)
");
$stmt->execute([$user_id, $channel_id, $user_id]);
$overrides = $stmt->fetchAll();
if (empty($overrides)) {
// No overrides, fallback to global permissions
return self::hasPermission($user_id, $server_id, $permission);
}
// Resolution order (simplified but effective):
// User overrides > Role overrides > @everyone
$user_override = null;
$role_allow = 0;
$role_deny = 0;
$everyone_override = null;
foreach($overrides as $o) {
if ($o['user_id'] == $user_id) {
$user_override = $o;
} elseif ($o['role_name'] === '@everyone' || $o['role_name'] === 'Everyone') {
$everyone_override = $o;
} else {
$role_allow |= (int)$o['allow_permissions'];
$role_deny |= (int)$o['deny_permissions'];
}
}
// 1. User specifically
if ($user_override) {
if ($user_override['allow_permissions'] & $permission) return true;
if ($user_override['deny_permissions'] & $permission) return false;
}
// 2. Roles
if ($role_allow & $permission) return true;
if ($role_deny & $permission) return false;
// 3. @everyone
if ($everyone_override) {
if ($everyone_override['allow_permissions'] & $permission) return true;
if ($everyone_override['deny_permissions'] & $permission) return false;
}
// Fallback to base permissions
return self::hasPermission($user_id, $server_id, $permission);
}
}