CluPilotCloud/app/Policies/VpnPeerPolicy.php

84 lines
2.7 KiB
PHP

<?php
namespace App\Policies;
use App\Models\User;
use App\Models\VpnPeer;
/**
* Who may see and do what with a VPN access.
*
* Ownership is record-level and lives here; permissions describe elevated
* capabilities (vpn.view.all, vpn.manage.all) and are checked through Gate.
* The two are kept apart on purpose: seeing an access is not managing it, and
* neither of them is holding its private key.
*
* There is no Gate::before super-admin shortcut in this application, so these
* rules are the whole story — in particular downloadConfig() cannot be
* out-voted by a role.
*/
class VpnPeerPolicy
{
public function viewAny(User $user): bool
{
// Every operator may at least reach the page to find their own access.
return $user->isOperator();
}
public function view(User $user, VpnPeer $peer): bool
{
return $this->owns($user, $peer) || $user->can('vpn.view.all');
}
public function create(User $user): bool
{
// Not self-service: an access reaches the management network, so issuing
// one is an administrative act even for oneself.
return $user->can('vpn.manage.all');
}
/** Rename, reassign, change stored-config settings. */
public function update(User $user, VpnPeer $peer): bool
{
return $user->can('vpn.manage.all');
}
/** Block / unblock. Owners may switch their own access off and on again. */
public function block(User $user, VpnPeer $peer): bool
{
return $user->can('vpn.manage.all') || $this->owns($user, $peer);
}
public function delete(User $user, VpnPeer $peer): bool
{
return $user->can('vpn.manage.all') || $this->owns($user, $peer);
}
/**
* The private half of someone's credential. Owner only — explicitly NOT
* vpn.view.all and NOT vpn.manage.all: an administrator who needs access
* revokes this one and issues themselves their own, which keeps the record
* of who holds what intact.
*/
public function downloadConfig(User $user, VpnPeer $peer): bool
{
return $this->owns($user, $peer)
&& $peer->config_secret !== null
&& ! $peer->trashed();
}
/**
* isOperator() is part of ownership on purpose: roles can be taken away by
* other paths than revokeStaff() — a direct role edit, for instance. Losing
* the console must close these doors by itself, not rely on whoever removed
* the role also remembering the tunnel.
*/
private function owns(User $user, VpnPeer $peer): bool
{
return $user->isOperator()
&& $peer->kind === VpnPeer::KIND_STAFF
&& $peer->user_id !== null
&& $peer->user_id === $user->id;
}
}