Skip to content

Commit c803961

Browse files
committed
Increased attachment link limit from 192 to 2k
Added test to cover. Did attempt a 64k limit, but values over 2k significantly increase chance of other issues since this URL may be used in redirect headers. Would rather catch issues in-app. For #4044
1 parent 8da3e64 commit c803961

File tree

6 files changed

+71
-26
lines changed

6 files changed

+71
-26
lines changed

app/Http/Controllers/Api/AttachmentApiController.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313

1414
class AttachmentApiController extends ApiController
1515
{
16-
protected $attachmentService;
17-
18-
public function __construct(AttachmentService $attachmentService)
19-
{
20-
$this->attachmentService = $attachmentService;
16+
public function __construct(
17+
protected AttachmentService $attachmentService
18+
) {
2119
}
2220

2321
/**
@@ -174,13 +172,13 @@ protected function rules(): array
174172
'name' => ['required', 'min:1', 'max:255', 'string'],
175173
'uploaded_to' => ['required', 'integer', 'exists:pages,id'],
176174
'file' => array_merge(['required_without:link'], $this->attachmentService->getFileValidationRules()),
177-
'link' => ['required_without:file', 'min:1', 'max:255', 'safe_url'],
175+
'link' => ['required_without:file', 'min:1', 'max:2000', 'safe_url'],
178176
],
179177
'update' => [
180178
'name' => ['min:1', 'max:255', 'string'],
181179
'uploaded_to' => ['integer', 'exists:pages,id'],
182180
'file' => $this->attachmentService->getFileValidationRules(),
183-
'link' => ['min:1', 'max:255', 'safe_url'],
181+
'link' => ['min:1', 'max:2000', 'safe_url'],
184182
],
185183
];
186184
}

app/Http/Controllers/AttachmentController.php

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,10 @@
1515

1616
class AttachmentController extends Controller
1717
{
18-
protected AttachmentService $attachmentService;
19-
protected PageRepo $pageRepo;
20-
21-
/**
22-
* AttachmentController constructor.
23-
*/
24-
public function __construct(AttachmentService $attachmentService, PageRepo $pageRepo)
25-
{
26-
$this->attachmentService = $attachmentService;
27-
$this->pageRepo = $pageRepo;
18+
public function __construct(
19+
protected AttachmentService $attachmentService,
20+
protected PageRepo $pageRepo
21+
) {
2822
}
2923

3024
/**
@@ -112,7 +106,7 @@ public function update(Request $request, string $attachmentId)
112106
try {
113107
$this->validate($request, [
114108
'attachment_edit_name' => ['required', 'string', 'min:1', 'max:255'],
115-
'attachment_edit_url' => ['string', 'min:1', 'max:255', 'safe_url'],
109+
'attachment_edit_url' => ['string', 'min:1', 'max:2000', 'safe_url'],
116110
]);
117111
} catch (ValidationException $exception) {
118112
return response()->view('attachments.manager-edit-form', array_merge($request->only(['attachment_edit_name', 'attachment_edit_url']), [
@@ -148,7 +142,7 @@ public function attachLink(Request $request)
148142
$this->validate($request, [
149143
'attachment_link_uploaded_to' => ['required', 'integer', 'exists:pages,id'],
150144
'attachment_link_name' => ['required', 'string', 'min:1', 'max:255'],
151-
'attachment_link_url' => ['required', 'string', 'min:1', 'max:255', 'safe_url'],
145+
'attachment_link_url' => ['required', 'string', 'min:1', 'max:2000', 'safe_url'],
152146
]);
153147
} catch (ValidationException $exception) {
154148
return response()->view('attachments.manager-link-form', array_merge($request->only(['attachment_link_name', 'attachment_link_url']), [

app/Providers/ValidationRuleServiceProvider.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ public function boot(): void
2121

2222
Validator::extend('safe_url', function ($attribute, $value, $parameters, $validator) {
2323
$cleanLinkName = strtolower(trim($value));
24-
$isJs = strpos($cleanLinkName, 'javascript:') === 0;
25-
$isData = strpos($cleanLinkName, 'data:') === 0;
24+
$isJs = str_starts_with($cleanLinkName, 'javascript:');
25+
$isData = str_starts_with($cleanLinkName, 'data:');
2626

2727
return !$isJs && !$isData;
2828
});

app/Uploads/Attachment.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,10 @@ class Attachment extends Model
4040

4141
/**
4242
* Get the downloadable file name for this upload.
43-
*
44-
* @return mixed|string
4543
*/
46-
public function getFileName()
44+
public function getFileName(): string
4745
{
48-
if (strpos($this->name, '.') !== false) {
46+
if (str_contains($this->name, '.')) {
4947
return $this->name;
5048
}
5149

@@ -71,7 +69,7 @@ public function jointPermissions(): HasMany
7169
*/
7270
public function getUrl($openInline = false): string
7371
{
74-
if ($this->external && strpos($this->path, 'http') !== 0) {
72+
if ($this->external && !str_starts_with($this->path, 'http')) {
7573
return $this->path;
7674
}
7775

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::table('attachments', function (Blueprint $table) {
17+
$table->text('path')->change();
18+
});
19+
}
20+
21+
/**
22+
* Reverse the migrations.
23+
*
24+
* @return void
25+
*/
26+
public function down()
27+
{
28+
Schema::table('attachments', function (Blueprint $table) {
29+
$table->string('path')->change();
30+
});
31+
}
32+
};

tests/Uploads/AttachmentTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,29 @@ public function test_attaching_link_to_page()
111111
$this->files->deleteAllAttachmentFiles();
112112
}
113113

114+
public function test_attaching_long_links_to_a_page()
115+
{
116+
$page = $this->entities->page();
117+
118+
$link = 'https://example.com?query=' . str_repeat('catsIScool', 195);
119+
$linkReq = $this->asAdmin()->post('attachments/link', [
120+
'attachment_link_url' => $link,
121+
'attachment_link_name' => 'Example Attachment Link',
122+
'attachment_link_uploaded_to' => $page->id,
123+
]);
124+
125+
$linkReq->assertStatus(200);
126+
$this->assertDatabaseHas('attachments', [
127+
'uploaded_to' => $page->id,
128+
'path' => $link,
129+
'external' => true,
130+
]);
131+
132+
$attachment = $page->attachments()->where('external', '=', true)->first();
133+
$resp = $this->get($attachment->getUrl());
134+
$resp->assertRedirect($link);
135+
}
136+
114137
public function test_attachment_updating()
115138
{
116139
$page = $this->entities->page();

0 commit comments

Comments
 (0)