1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-03-14 19:59:38 +01:00

Adjust api model authorization

This commit is contained in:
Kovah 2023-09-28 21:17:16 +02:00
parent f0421b7222
commit 0f0e266101
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
14 changed files with 121 additions and 81 deletions

View File

@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\ChecksOrdering;
use App\Http\Requests\Models\ListStoreRequest;
use App\Http\Requests\Models\ListUpdateRequest;
use App\Models\Api\ApiLinkList;
use App\Models\LinkList;
use App\Repositories\ListRepository;
use Illuminate\Http\JsonResponse;
@ -17,8 +18,8 @@ class ListController extends Controller
public function __construct()
{
$this->allowedOrderBy = LinkList::$allowOrderBy;
$this->authorizeResource(LinkList::class . 'Api', 'list');
$this->allowedOrderBy = ApiLinkList::$allowOrderBy;
$this->authorizeResource(ApiLinkList::class, 'list');
}
public function index(Request $request): JsonResponse

View File

@ -5,6 +5,7 @@ namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Http\Requests\Models\NoteStoreRequest;
use App\Http\Requests\Models\NoteUpdateRequest;
use App\Models\Api\ApiNote;
use App\Models\Note;
use App\Repositories\NoteRepository;
use Illuminate\Http\JsonResponse;
@ -14,7 +15,7 @@ class NoteController extends Controller
{
public function __construct()
{
$this->authorizeResource(Note::class . 'Api', 'note');
$this->authorizeResource(ApiNote::class, 'note');
}
public function store(NoteStoreRequest $request): JsonResponse

View File

@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\ChecksOrdering;
use App\Http\Requests\Models\TagStoreRequest;
use App\Http\Requests\Models\TagUpdateRequest;
use App\Models\Api\ApiTag;
use App\Models\Tag;
use App\Repositories\TagRepository;
use Illuminate\Http\JsonResponse;
@ -17,8 +18,8 @@ class TagController extends Controller
public function __construct()
{
$this->allowedOrderBy = Tag::$allowOrderBy;
$this->authorizeResource(Tag::class . 'Api', 'tag');
$this->allowedOrderBy = ApiTag::$allowOrderBy;
$this->authorizeResource(ApiTag::class, 'tag');
}
public function index(Request $request): JsonResponse

View File

@ -6,5 +6,5 @@ use App\Models\Link;
class ApiLink extends Link
{
protected $table = 'links';
public $table = 'links';
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Models\Api;
use App\Models\LinkList;
class ApiLinkList extends LinkList
{
public $table = 'lists';
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Models\Api;
use App\Models\Note;
class ApiNote extends Note
{
public $table = 'notes';
}

10
app/Models/Api/ApiTag.php Normal file
View File

@ -0,0 +1,10 @@
<?php
namespace App\Models\Api;
use App\Models\Tag;
class ApiTag extends Tag
{
public $table = 'tags';
}

View File

@ -3,7 +3,6 @@
namespace App\Policies\Api;
use App\Enums\ApiToken;
use App\Enums\ModelAttribute;
use App\Models\Api\ApiLink;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
@ -11,6 +10,11 @@ use Illuminate\Auth\Access\HandlesAuthorization;
class ApiLinkPolicy
{
use HandlesAuthorization;
use AuthorizesUserApiActions;
protected string $readAbility = ApiToken::ABILITY_LINKS_READ;
protected string $updateAbility = ApiToken::ABILITY_LINKS_UPDATE;
protected string $deleteAbility = ApiToken::ABILITY_LINKS_DELETE;
public function viewAny(User $user): bool
{
@ -22,7 +26,7 @@ class ApiLinkPolicy
public function view(User $user, ApiLink $link): bool
{
return $this->userCanAccessLink($user, $link);
return $this->userCanAccessModel($user, $link);
}
public function create(User $user): bool
@ -32,7 +36,7 @@ class ApiLinkPolicy
public function update(User $user, ApiLink $link): bool
{
return $this->userCanUpdateLink($user, $link);
return $this->userCanUpdateModel($user, $link);
}
public function delete(User $user, ApiLink $link): bool
@ -49,33 +53,4 @@ class ApiLinkPolicy
{
return $link->user->is($user);
}
// Link must be either owned by user, or be not private
protected function userCanAccessLink(User $user, ApiLink $link): bool
{
if ($link->user_id === $user->id) {
return true;
}
if ($user->isSystemUser()) {
if ($link->visibility === ModelAttribute::VISIBILITY_PRIVATE) {
return $user->tokenCan(ApiToken::ABILITY_LINKS_READ) && $user->tokenCan(ApiToken::ABILITY_SYSTEM_ACCESS_PRIVATE);
}
return $user->tokenCan(ApiToken::ABILITY_LINKS_READ);
}
return $link->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
protected function userCanUpdateLink(User $user, ApiLink $link): bool
{
if ($link->user_id === $user->id) {
return true;
}
if ($user->isSystemUser()) {
if ($link->visibility === ModelAttribute::VISIBILITY_PRIVATE) {
return $user->tokenCan(ApiToken::ABILITY_LINKS_UPDATE) && $user->tokenCan(ApiToken::ABILITY_SYSTEM_ACCESS_PRIVATE);
}
return $user->tokenCan(ApiToken::ABILITY_LINKS_UPDATE);
}
return $link->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Policies\Api;
use App\Enums\ApiToken;
use App\Enums\ModelAttribute;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
trait AuthorizesUserApiActions
{
protected function userCanAccessModel(User $user, Model $model): bool
{
if ($model->user_id === $user->id) {
return true;
}
if ($user->isSystemUser()) {
if ($model->visibility === ModelAttribute::VISIBILITY_PRIVATE) {
return $user->tokenCan($this->readAbility) && $user->tokenCan(ApiToken::ABILITY_SYSTEM_ACCESS_PRIVATE);
}
return $user->tokenCan($this->readAbility);
}
return $model->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
protected function userCanUpdateModel(User $user, Model $model): bool
{
if ($model->user_id === $user->id) {
return true;
}
if ($user->isSystemUser()) {
if ($model->visibility === ModelAttribute::VISIBILITY_PRIVATE) {
return $user->tokenCan($this->updateAbility) && $user->tokenCan(ApiToken::ABILITY_SYSTEM_ACCESS_PRIVATE);
}
return $user->tokenCan($this->updateAbility);
}
return $model->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
}

View File

@ -2,23 +2,28 @@
namespace App\Policies\Api;
use App\Enums\ModelAttribute;
use App\Models\LinkList;
use App\Enums\ApiToken;
use App\Models\Api\ApiLinkList;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class LinkListApiPolicy
{
use HandlesAuthorization;
use AuthorizesUserApiActions;
protected string $readAbility = ApiToken::ABILITY_LISTS_READ;
protected string $updateAbility = ApiToken::ABILITY_LISTS_UPDATE;
protected string $deleteAbility = ApiToken::ABILITY_LISTS_DELETE;
public function viewAny(User $user): bool
{
return true;
}
public function view(User $user, LinkList $list): bool
public function view(User $user, ApiLinkList $list): bool
{
return $this->userCanAccessList($user, $list);
return $this->userCanAccessModel($user, $list);
}
public function create(User $user): bool
@ -26,32 +31,23 @@ class LinkListApiPolicy
return true;
}
public function update(User $user, LinkList $list): bool
public function update(User $user, ApiLinkList $list): bool
{
return $this->userCanAccessList($user, $list);
return $this->userCanUpdateModel($user, $list);
}
public function delete(User $user, LinkList $list): bool
public function delete(User $user, ApiLinkList $list): bool
{
return $list->user->is($user);
}
public function restore(User $user, LinkList $list): bool
public function restore(User $user, ApiLinkList $list): bool
{
return $list->user->is($user);
}
public function forceDelete(User $user, LinkList $list): bool
public function forceDelete(User $user, ApiLinkList $list): bool
{
return $list->user->is($user);
}
// Link must be either owned by user, or be not private
protected function userCanAccessList(User $user, LinkList $list): bool
{
if ($list->user_id === $user->id) {
return true;
}
return $list->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies\Api;
use App\Enums\ModelAttribute;
use App\Enums\ApiToken;
use App\Models\Note;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
@ -10,6 +10,11 @@ use Illuminate\Auth\Access\HandlesAuthorization;
class NoteApiPolicy
{
use HandlesAuthorization;
use AuthorizesUserApiActions;
protected string $readAbility = ApiToken::ABILITY_NOTES_READ;
protected string $updateAbility = ApiToken::ABILITY_NOTES_UPDATE;
protected string $deleteAbility = ApiToken::ABILITY_NOTES_DELETE;
public function viewAny(User $user): bool
{
@ -45,13 +50,4 @@ class NoteApiPolicy
{
return $note->user->is($user);
}
// Link must be either owned by user, or be not private
protected function userCanAccessNote(User $user, Note $note): bool
{
if ($note->user_id === $user->id) {
return true;
}
return $note->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
}

View File

@ -2,7 +2,7 @@
namespace App\Policies\Api;
use App\Enums\ModelAttribute;
use App\Enums\ApiToken;
use App\Models\Tag;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
@ -10,6 +10,11 @@ use Illuminate\Auth\Access\HandlesAuthorization;
class TagApiPolicy
{
use HandlesAuthorization;
use AuthorizesUserApiActions;
protected string $readAbility = ApiToken::ABILITY_TAGS_READ;
protected string $updateAbility = ApiToken::ABILITY_TAGS_UPDATE;
protected string $deleteAbility = ApiToken::ABILITY_TAGS_DELETE;
public function viewAny(User $user): bool
{
@ -18,7 +23,7 @@ class TagApiPolicy
public function view(User $user, Tag $tag): bool
{
return $this->userCanAccessTag($user, $tag);
return $this->userCanAccessModel($user, $tag);
}
public function create(User $user): bool
@ -28,7 +33,7 @@ class TagApiPolicy
public function update(User $user, Tag $tag): bool
{
return $this->userCanAccessTag($user, $tag);
return $this->userCanUpdateModel($user, $tag);
}
public function delete(User $user, Tag $tag): bool
@ -45,13 +50,4 @@ class TagApiPolicy
{
return $tag->user->is($user);
}
// Link must be either owned by user, or be not private
protected function userCanAccessTag(User $user, Tag $tag): bool
{
if ($tag->user_id === $user->id) {
return true;
}
return $tag->visibility !== ModelAttribute::VISIBILITY_PRIVATE;
}
}

View File

@ -3,6 +3,9 @@
namespace App\Providers;
use App\Models\Api\ApiLink;
use App\Models\Api\ApiLinkList;
use App\Models\Api\ApiNote;
use App\Models\Api\ApiTag;
use App\Models\Link;
use App\Models\LinkList;
use App\Models\Note;
@ -33,9 +36,9 @@ class AuthServiceProvider extends ServiceProvider
Tag::class => TagPolicy::class,
PersonalAccessToken::class => ApiTokenPolicy::class,
ApiLink::class => ApiLinkPolicy::class,
LinkList::class . 'Api' => LinkListApiPolicy::class,
Note::class . 'Api' => NoteApiPolicy::class,
Tag::class . 'Api' => TagApiPolicy::class,
ApiLinkList::class => LinkListApiPolicy::class,
ApiNote::class => NoteApiPolicy::class,
ApiTag::class => TagApiPolicy::class,
];
/**

View File

@ -4,6 +4,7 @@ namespace Tests;
use App\Settings\SystemSettings;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Schema;
abstract class TestCase extends BaseTestCase
@ -13,6 +14,7 @@ abstract class TestCase extends BaseTestCase
protected function setUp(): void
{
parent::setUp();
Http::preventStrayRequests();
if (Schema::hasTable('settings')) {
SystemSettings::fake([