Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8769308dfd | |||
| f5848907f5 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "dashboard/unifi",
|
||||
"description": "UniFi network management, WiFi stats, and captive portal authentication for the Dashboard platform",
|
||||
"version": "1.7.0",
|
||||
"version": "1.8.0",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
|
||||
@@ -40,6 +40,15 @@ class UnifiPagesAccessController extends Controller
|
||||
$grantedUserIds = $grants->flatten(1)->where('grantee_type', 'user')->pluck('grantee_id')->unique();
|
||||
$users = User::whereIn('id', $grantedUserIds)->orderBy('name')->get(['id', 'name', 'email']);
|
||||
|
||||
// Groups: always include super-admin groups (locked-on across all
|
||||
// pages) plus any group with at least one grant. Other groups are
|
||||
// added via searchGroups.
|
||||
$grantedGroupIds = $grants->flatten(1)->where('grantee_type', 'group')->pluck('grantee_id')->unique();
|
||||
$groups = Group::where(function ($q) use ($grantedGroupIds) {
|
||||
$q->where('is_super', true)
|
||||
->orWhereIn('id', $grantedGroupIds);
|
||||
})->orderBy('name')->get(['id', 'name', 'is_super']);
|
||||
|
||||
return response()->json([
|
||||
'pages' => $pages->map(fn ($p) => [
|
||||
'id' => $p->id,
|
||||
@@ -49,7 +58,7 @@ class UnifiPagesAccessController extends Controller
|
||||
'group_ids' => $grants->get($p->id, collect())->where('grantee_type', 'group')->pluck('grantee_id')->all(),
|
||||
])->values(),
|
||||
'users' => $users,
|
||||
'groups' => Group::orderBy('name')->get(['id', 'name', 'is_super']),
|
||||
'groups' => $groups,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -76,6 +85,27 @@ class UnifiPagesAccessController extends Controller
|
||||
return response()->json(['users' => $users]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Typeahead-style search for groups to add to the access matrix.
|
||||
* Excludes super-admin groups (they're already in the matrix and
|
||||
* locked-on across every page).
|
||||
*/
|
||||
public function searchGroups(Request $request)
|
||||
{
|
||||
$q = trim((string) $request->query('q', ''));
|
||||
if (strlen($q) < 2) {
|
||||
return response()->json(['groups' => []]);
|
||||
}
|
||||
|
||||
$groups = Group::where('name', 'like', '%' . $q . '%')
|
||||
->where(function ($w) { $w->where('is_super', false)->orWhereNull('is_super'); })
|
||||
->orderBy('name')
|
||||
->limit(20)
|
||||
->get(['id', 'name', 'is_super']);
|
||||
|
||||
return response()->json(['groups' => $groups]);
|
||||
}
|
||||
|
||||
public function update(Request $request, NavItem $navItem)
|
||||
{
|
||||
$app = DashboardApp::where('slug', 'unifi')->first();
|
||||
|
||||
@@ -29,18 +29,20 @@ class UnifiPageGrant extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* True iff $user is allowed to access $navItem under this grant model.
|
||||
* Super-admins always pass.
|
||||
* If there are NO grants for the page, falls back to "open" (anyone
|
||||
* who can reach the route can access — same as before grants existed).
|
||||
* True iff $user is allowed to access $navItem under strict allowlist
|
||||
* semantics:
|
||||
* * super-admins (the model-level flag) always pass
|
||||
* * otherwise the user must be a direct grantee, OR be in a group
|
||||
* that is a grantee
|
||||
*
|
||||
* A page with NO grants saved is only visible to super-admins —
|
||||
* the admin must explicitly authorize everyone else via the
|
||||
* Access tab.
|
||||
*/
|
||||
public static function userCanAccess(User $user, NavItem $navItem): bool
|
||||
{
|
||||
if ($user->is_super_admin) return true;
|
||||
|
||||
$hasGrants = static::where('nav_item_id', $navItem->id)->exists();
|
||||
if (! $hasGrants) return true;
|
||||
|
||||
$groupIds = $user->groups()->pluck('groups.id');
|
||||
|
||||
return static::where('nav_item_id', $navItem->id)
|
||||
|
||||
@@ -44,7 +44,9 @@ class UnifiServiceProvider extends ServiceProvider
|
||||
if (! $item) return;
|
||||
|
||||
if (! UnifiPageGrant::userCanAccess($user, $item)) {
|
||||
abort(403, 'You do not have access to this page.');
|
||||
// 404 instead of 403 — don't leak that the page
|
||||
// exists. The Access tab is the only way in.
|
||||
abort(404);
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// unifi_page_grants table may not exist yet on a fresh
|
||||
|
||||
@@ -78,6 +78,7 @@ Route::middleware(['web', 'auth', 'app.access:unifi'])
|
||||
Route::middleware('super.admin')->group(function () {
|
||||
Route::get('/settings/pages-access', [UnifiPagesAccessController::class, 'index']) ->name('settings.pages-access.index');
|
||||
Route::get('/settings/pages-access/users/search', [UnifiPagesAccessController::class, 'searchUsers'])->name('settings.pages-access.users.search');
|
||||
Route::get('/settings/pages-access/groups/search', [UnifiPagesAccessController::class, 'searchGroups'])->name('settings.pages-access.groups.search');
|
||||
Route::put('/settings/pages-access/{navItem}', [UnifiPagesAccessController::class, 'update']) ->name('settings.pages-access.update');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user