mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-03 04:02:10 +02:00
Third coverage batch — the pure/near-pure cores of the auth layer: - AuthorizationTest: hasResellerPermissions() flag lookup; check() short-circuit when identity globals are absent; the 'user'/'line' report-tree scoping via a real SQLite query (owner/member within self + all_reports); and the 'adv' permission logic (admin required, super-admin group 1 bypasses the advanced list, other groups gated by it). - BruteforceGuardTest: truncateAttempts() drops entries older than the window in both indexed (reindexed) and associative (keys preserved) shapes; all-recent and empty inputs. The IO-bound check* methods are left for integration tests. +12 tests. Suite: 646 tests, 0 errors.
95 lines
3.8 KiB
PHP
95 lines
3.8 KiB
PHP
<?php
|
|
|
|
use XcVm\Core\Auth\Authorization;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Authorization — per-entity access checks for the current user/reseller.
|
|
*
|
|
* Reads the current identity from the $rUserInfo / $rPermissions / $db globals,
|
|
* so each test seeds those and tearDown clears them. The 'user' and 'line'
|
|
* checks scope by the report tree via a real (SQLite) query; the 'adv' check is
|
|
* pure permission logic; and everything short-circuits to false when the
|
|
* identity globals are missing.
|
|
*/
|
|
final class AuthorizationTest extends TestCase {
|
|
|
|
private TestDb $db;
|
|
|
|
protected function setUp(): void {
|
|
$this->db = new TestDb();
|
|
$this->db->exec(
|
|
'CREATE TABLE users (id INTEGER PRIMARY KEY, owner_id INTEGER);
|
|
CREATE TABLE `lines` (id INTEGER PRIMARY KEY, member_id INTEGER);
|
|
INSERT INTO users (id, owner_id) VALUES (100, 10), (200, 20), (300, 99);
|
|
INSERT INTO `lines` (id, member_id) VALUES (5, 10), (6, 99);'
|
|
);
|
|
$GLOBALS['db'] = $this->db;
|
|
$GLOBALS['rUserInfo'] = ['id' => 10, 'member_group_id' => 2];
|
|
$GLOBALS['rPermissions'] = [
|
|
'all_reports' => [20],
|
|
'is_admin' => 1,
|
|
'advanced' => ['export', 'mass_edit'],
|
|
];
|
|
}
|
|
|
|
protected function tearDown(): void {
|
|
unset($GLOBALS['db'], $GLOBALS['rUserInfo'], $GLOBALS['rPermissions']);
|
|
}
|
|
|
|
// ── hasResellerPermissions ───────────────────────────────────────
|
|
|
|
public function testHasResellerPermissionsReadsTheFlagMap(): void {
|
|
$GLOBALS['rPermissions'] = ['manage_streams' => 1, 'delete' => 0];
|
|
$this->assertTrue(Authorization::hasResellerPermissions('manage_streams'));
|
|
$this->assertFalse(Authorization::hasResellerPermissions('delete'), 'falsy flag');
|
|
$this->assertFalse(Authorization::hasResellerPermissions('missing'));
|
|
}
|
|
|
|
public function testHasResellerPermissionsFalseWhenMapMissing(): void {
|
|
unset($GLOBALS['rPermissions']);
|
|
$this->assertFalse(Authorization::hasResellerPermissions('anything'));
|
|
}
|
|
|
|
// ── check(): guards ──────────────────────────────────────────────
|
|
|
|
public function testCheckFalseWhenIdentityGlobalsMissing(): void {
|
|
unset($GLOBALS['rUserInfo']);
|
|
$this->assertFalse(Authorization::check('adv', 1));
|
|
}
|
|
|
|
// ── check(): 'user' / 'line' scope by report tree ────────────────
|
|
|
|
public function testCheckUserMatchesWithinOwnerReportTree(): void {
|
|
// user 100 is owned by 10 (self); reports = [self=10, 20].
|
|
$this->assertTrue(Authorization::check('user', 100));
|
|
// user 200 owned by 20, which is in the report tree.
|
|
$this->assertTrue(Authorization::check('user', 200));
|
|
// user 300 owned by 99 (outside the tree) and not self.
|
|
$this->assertFalse(Authorization::check('user', 300));
|
|
}
|
|
|
|
public function testCheckLineMatchesWithinReportTree(): void {
|
|
$this->assertTrue(Authorization::check('line', 5), 'line owned by self (10)');
|
|
$this->assertFalse(Authorization::check('line', 6), 'line owned by 99, outside tree');
|
|
}
|
|
|
|
// ── check(): 'adv' permission logic ──────────────────────────────
|
|
|
|
public function testCheckAdvRequiresAdmin(): void {
|
|
$GLOBALS['rPermissions']['is_admin'] = 0;
|
|
$this->assertFalse(Authorization::check('adv', 'export'));
|
|
}
|
|
|
|
public function testCheckAdvSuperAdminBypassesAdvancedList(): void {
|
|
$GLOBALS['rUserInfo']['member_group_id'] = 1; // super admin group
|
|
$this->assertTrue(Authorization::check('adv', 'anything_not_in_list'));
|
|
}
|
|
|
|
public function testCheckAdvNonSuperAdminIsGatedByAdvancedList(): void {
|
|
// member_group_id 2, advanced = ['export', 'mass_edit']
|
|
$this->assertTrue(Authorization::check('adv', 'export'));
|
|
$this->assertFalse(Authorization::check('adv', 'delete_all'));
|
|
}
|
|
}
|