mirror of
https://github.com/snipe/snipe-it.git
synced 2026-08-23 21:59:00 +00:00
92 lines
3.0 KiB
PHP
92 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Assets\Ui;
|
|
|
|
use App\Models\Asset;
|
|
use App\Models\User;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Regression tests for a broken-access-control bug where
|
|
* BulkAssetsController::restore() (POST /hardware/bulkrestore) used
|
|
* $this->authorize('update', Asset::class), letting any user with
|
|
* assets.edit undo an admin's soft-delete by sending the ID directly.
|
|
* Every other restore code path in the codebase gated on
|
|
* authorize('delete', ...):
|
|
*
|
|
* - AssetsController::getRestore (single-asset web)
|
|
* - Api\AssetsController::restore (single-asset API)
|
|
* - BulkAssetsController::edit() 'restore' preview branch
|
|
*
|
|
* The fix aligns the bulk POST handler with the rest by gating on the
|
|
* `delete` ability at both the class level and per-instance level.
|
|
*/
|
|
class BulkRestoreAuthorizationTest extends TestCase
|
|
{
|
|
public function test_user_with_edit_but_no_delete_cannot_bulk_restore()
|
|
{
|
|
$asset = Asset::factory()->deleted()->create();
|
|
|
|
$user = User::factory()->viewAssets()->editAssets()->create();
|
|
|
|
$this->actingAs($user)
|
|
->post(route('hardware/bulkrestore'), [
|
|
'ids' => [$asset->id],
|
|
])
|
|
->assertForbidden();
|
|
|
|
$asset->refresh();
|
|
$this->assertNotNull($asset->deleted_at, 'Asset must remain soft-deleted after a forbidden restore attempt.');
|
|
}
|
|
|
|
public function test_user_with_only_view_cannot_bulk_restore()
|
|
{
|
|
$asset = Asset::factory()->deleted()->create();
|
|
|
|
$user = User::factory()->viewAssets()->create();
|
|
|
|
$this->actingAs($user)
|
|
->post(route('hardware/bulkrestore'), [
|
|
'ids' => [$asset->id],
|
|
])
|
|
->assertForbidden();
|
|
|
|
$asset->refresh();
|
|
$this->assertNotNull($asset->deleted_at);
|
|
}
|
|
|
|
public function test_user_with_delete_permission_can_bulk_restore()
|
|
{
|
|
$asset = Asset::factory()->deleted()->create();
|
|
|
|
$user = User::factory()->viewAssets()->deleteAssets()->create();
|
|
|
|
$this->actingAs($user)
|
|
->post(route('hardware/bulkrestore'), [
|
|
'ids' => [$asset->id],
|
|
])
|
|
->assertRedirect(route('hardware.index'));
|
|
|
|
$asset->refresh();
|
|
$this->assertNull($asset->deleted_at, 'Asset should be restored (deleted_at cleared) after an authorized bulk restore.');
|
|
}
|
|
|
|
public function test_bulk_restore_skips_nonexistent_ids_instead_of_500()
|
|
{
|
|
// Prior code did Asset::withTrashed()->find($id)->restore() with no
|
|
// null guard, so any invalid or forged ID crashed the whole request.
|
|
$realAsset = Asset::factory()->deleted()->create();
|
|
|
|
$user = User::factory()->viewAssets()->deleteAssets()->create();
|
|
|
|
$this->actingAs($user)
|
|
->post(route('hardware/bulkrestore'), [
|
|
'ids' => [$realAsset->id, 99999999],
|
|
])
|
|
->assertRedirect(route('hardware.index'));
|
|
|
|
$realAsset->refresh();
|
|
$this->assertNull($realAsset->deleted_at);
|
|
}
|
|
}
|