Skip to content

Commit a889c18

Browse files
committed
Attachment API: Fixed missing check on attachment page change
On the change of an attachment uploaded_to (page) this ensures that a PageUpdate permission check is made against the original attachment page, in addition to the new page. Thanks to Wade Sparks / ByteMe.Red for reporting.
1 parent c813c1b commit a889c18

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

app/Uploads/Controllers/AttachmentApiController.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function __construct(
2424

2525
/**
2626
* Get a listing of attachments visible to the user.
27-
* The external property indicates whether the attachment is simple a link.
27+
* The external property indicates whether the attachment is simply a link.
2828
* A false value for the external property would indicate a file upload.
2929
*/
3030
public function list()
@@ -39,7 +39,7 @@ public function list()
3939
* An uploaded_to value must be provided containing an ID of the page
4040
* that this upload will be related to.
4141
*
42-
* If you're uploading a file the POST data should be provided via
42+
* If you're uploading a file, the POST data should be provided via
4343
* a multipart/form-data type request instead of JSON.
4444
*
4545
* @throws ValidationException
@@ -71,7 +71,7 @@ public function create(Request $request)
7171
}
7272

7373
/**
74-
* Get the details & content of a single attachment of the given ID.
74+
* Get the details and content of a single attachment of the given ID.
7575
* The attachment link or file content is provided via a 'content' property.
7676
* For files the content will be base64 encoded.
7777
*
@@ -120,7 +120,7 @@ public function read(string $id)
120120

121121
/**
122122
* Update the details of a single attachment.
123-
* As per the create endpoint, if a file is being provided as the attachment content
123+
* As per the create endpoint, if a file is being provided as the attachment content,
124124
* the request should be formatted as a multipart/form-data request instead of JSON.
125125
*
126126
* @throws ValidationException
@@ -134,9 +134,12 @@ public function update(Request $request, string $id)
134134

135135
$page = $attachment->page;
136136
if ($requestData['uploaded_to'] ?? false) {
137-
$pageId = $request->input('uploaded_to');
138-
$page = $this->pageQueries->findVisibleByIdOrFail($pageId);
139-
$attachment->uploaded_to = $requestData['uploaded_to'];
137+
$pageId = intval($requestData['uploaded_to']);
138+
if ($pageId !== $page->id) {
139+
$this->checkOwnablePermission(Permission::PageUpdate, $page);
140+
$page = $this->pageQueries->findVisibleByIdOrFail($pageId);
141+
$attachment->uploaded_to = $pageId;
142+
}
140143
}
141144

142145
$this->checkOwnablePermission(Permission::PageView, $page);

tests/Api/AttachmentsApiTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Tests\Api;
44

55
use BookStack\Entities\Models\Page;
6+
use BookStack\Permissions\Permission;
67
use BookStack\Uploads\Attachment;
78
use Illuminate\Http\UploadedFile;
89
use Illuminate\Testing\AssertableJsonString;
@@ -345,6 +346,31 @@ public function test_update_does_not_require_name()
345346
$this->assertEquals('', $attachment->extension);
346347
}
347348

349+
public function test_update_uploaded_to_change_requires_edit_permission_to_old_page()
350+
{
351+
$editor = $this->users->editor();
352+
$this->actingAsForApi($editor);
353+
354+
$originalPage = $this->entities->page();
355+
$attachment = $this->createAttachmentForPage($originalPage);
356+
$newPage = $this->entities->page();
357+
358+
$details = [
359+
'name' => 'My updated API attachment',
360+
'uploaded_to' => $newPage->id,
361+
];
362+
363+
$this->permissions->setEntityPermissions($originalPage, ['view'], [$editor->roles->first()]);
364+
$this->permissions->grantUserRolePermissions($editor, [Permission::AttachmentUpdateAll]);
365+
366+
$resp = $this->putJson("{$this->baseEndpoint}/{$attachment->id}", $details);
367+
$attachment->refresh();
368+
369+
$this->assertPermissionError($resp);
370+
$this->assertNotEquals($newPage->id, $attachment->uploaded_to);
371+
$this->assertEquals($originalPage->id, $attachment->uploaded_to);
372+
}
373+
348374
public function test_delete_endpoint()
349375
{
350376
$this->actingAsApiAdmin();

0 commit comments

Comments
 (0)