Skip to content

Commit ef4b7ec

Browse files
committed
Add CSRF protection to storage endpoint
1 parent 82bcf0a commit ef4b7ec

File tree

7 files changed

+63
-5
lines changed

7 files changed

+63
-5
lines changed

dist/js/field.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,18 @@ __webpack_require__.r(__webpack_exports__);
512512
created: function created() {
513513
this.setEditorTheme();
514514
},
515+
computed: {
516+
/**
517+
* Query parameters to send to the upload endpoint.
518+
*
519+
* @returns {string}
520+
*/
521+
endpointParams: function endpointParams() {
522+
return '?' + new URLSearchParams({
523+
_token: this.field.token
524+
}).toString();
525+
}
526+
},
515527
methods: {
516528
/*
517529
* Set the initial, internal value for the field.
@@ -653,7 +665,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
653665
automatic_uploads: true,
654666
image_uploadtab: true,
655667
images_upload_credentials: true,
656-
images_upload_url: $props.field.options.storage_endpoint
668+
images_upload_url: $props.field.options.storage_endpoint + $options.endpointParams
657669
}),
658670
modelValue: _ctx.value,
659671
"onUpdate:modelValue": _cache[0] || (_cache[0] = function ($event) {

resources/js/components/FormField.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
automatic_uploads: true,
2020
image_uploadtab: true,
2121
images_upload_credentials: true,
22-
images_upload_url: field.options.storage_endpoint
22+
images_upload_url: field.options.storage_endpoint + endpointParams
2323
}"
2424
v-model="value"
2525
/>
@@ -42,6 +42,19 @@ export default {
4242
this.setEditorTheme()
4343
},
4444
45+
computed: {
46+
/**
47+
* Query parameters to send to the upload endpoint.
48+
*
49+
* @returns {string}
50+
*/
51+
endpointParams() {
52+
return '?' + new URLSearchParams({
53+
_token: this.field.token
54+
}).toString()
55+
}
56+
},
57+
4558
methods: {
4659
/*
4760
* Set the initial, internal value for the field.

routes/api.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
<?php
22

33
use Illuminate\Support\Facades\Route;
4-
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
54
use Jacobfitzp\NovaTinymce\Http\Controllers\ImageAttachmentController;
65

76
Route::post('/upload', [ImageAttachmentController::class, 'store'])
8-
->withoutMiddleware(VerifyCsrfToken::class)
97
->name('nova-tinymce.upload');

src/Events/ImageWasAttached.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Jacobfitzp\NovaTinymce\Events;
4+
5+
use Illuminate\Foundation\Events\Dispatchable;
6+
7+
/**
8+
* Image attachment event.
9+
* Dispatched when an image is uploaded to the TinyMCE field.
10+
*
11+
* @author Jacob Fitzpatrick
12+
*/
13+
class ImageWasAttached
14+
{
15+
use Dispatchable;
16+
17+
public function __construct(
18+
public string $location,
19+
public string $disk
20+
) {}
21+
}

src/Http/Controllers/ImageAttachmentController.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\JsonResponse;
66
use Illuminate\Support\Facades\Storage;
7+
use Jacobfitzp\NovaTinymce\Events\ImageWasAttached;
78
use Jacobfitzp\NovaTinymce\Http\Requests\AttachImageRequest;
89

910
/**
@@ -32,6 +33,10 @@ public function store(AttachImageRequest $request): JsonResponse
3233

3334
// Return the location of the uploaded file.
3435
if (filled($location)) {
36+
// Dispatch attachment event.
37+
ImageWasAttached::dispatch($location, $storageDisk);
38+
39+
// Respond with the location.
3540
return response()->json([
3641
'location' => Storage::disk($storageDisk)->url($location),
3742
]);

src/Http/Requests/AttachImageRequest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Jacobfitzp\NovaTinymce\Http\Requests;
44

55
use Illuminate\Foundation\Http\FormRequest;
6+
use Illuminate\Validation\Rule;
67

78
/**
89
* Attach image form request.
@@ -17,6 +18,9 @@ class AttachImageRequest extends FormRequest
1718
public function rules(): array
1819
{
1920
return [
21+
'disk' => [
22+
Rule::in(array_keys(config('filesystems.disks'))),
23+
],
2024
'file' => [
2125
'required',
2226
'image',

src/Tinymce.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ public function __construct($name, $attribute = null, callable $resolveCallback
2929
{
3030
parent::__construct($name, $attribute, $resolveCallback);
3131

32-
$this->withMeta(['options' => config('nova-tinymce')]);
32+
$this->withMeta([
33+
'options' => config('nova-tinymce'),
34+
// Need to make the CSRF token available to the component.
35+
// This will allow us to use CSRF protection for the storage endpoint.
36+
'token' => csrf_token(),
37+
]);
3338
}
3439

3540
/**

0 commit comments

Comments
 (0)