Skip to content

Commit dd257dc

Browse files
"Added page encryption and decryption functionality, tests, and updates to page display"
1 parent 724a62f commit dd257dc

21 files changed

+356
-118
lines changed

app/Activity/ActivityType.php

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class ActivityType
99
const PAGE_DELETE = 'page_delete';
1010
const PAGE_RESTORE = 'page_restore';
1111
const PAGE_MOVE = 'page_move';
12+
const PAGE_ENCRYPTED = 'page_encrypted';
13+
const PAGE_DECRYPTED = 'page_decrypted';
1214

1315
const CHAPTER_CREATE = 'chapter_create';
1416
const CHAPTER_UPDATE = 'chapter_update';

app/Entities/Controllers/PageController.php

+23-15
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ public function edit(Request $request, string $bookSlug, string $pageSlug)
199199
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
200200
$this->checkOwnablePermission('page-update', $page);
201201

202+
if(session()->get('is_decrypt') == 'FOR_EDIT')
203+
{
204+
$page->html = decrypt($page->html);
205+
session()->remove('is_decrypt');
206+
}
207+
202208
$editorData = new PageEditorData($page, $this->entityQueries, $request->query('editor', ''));
203209
if ($editorData->getWarnings()) {
204210
$this->showWarningNotification(implode("\n", $editorData->getWarnings()));
@@ -223,10 +229,10 @@ public function update(Request $request, string $bookSlug, string $pageSlug)
223229
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
224230
$this->checkOwnablePermission('page-update', $page);
225231

226-
if($page->is_decrypt == 1)
232+
if($page->is_decrypt == 'FOR_EDIT')
227233
{
228234
$request['html'] = encrypt($request['html']);
229-
$request['is_decrypt'] = false;
235+
$request['is_decrypt'] = 'NONE';
230236
}
231237

232238
$this->pageRepo->update($page, $request->all());
@@ -485,17 +491,6 @@ public function decrypt(Request $request,string $bookSlug, string $pageSlug)
485491
{
486492
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug,$pageSlug);
487493
return $this->pageRepo->decryptPageContent($request->all(),$page);
488-
// if($page->is_encrypted)
489-
// {
490-
// if(Hash::check($request->get('decrypt_password'),$page->decrypt_password))
491-
// {
492-
// return $this->pageRepo->decryptPageContent($request->all(),$page);
493-
// }
494-
// else
495-
// {
496-
// return response()->json(['contents' => [],'message' => 'Decrypt Password is Wrong','success' => false]);
497-
// }
498-
// }
499494
}
500495

501496
public function updateEncryption(Request $request,string $bookSlug, string $pageSlug)
@@ -515,14 +510,27 @@ public function updateEncryption(Request $request,string $bookSlug, string $page
515510
public function updateDecryption(Request $request,string $bookSlug, string $pageSlug)
516511
{
517512
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug,$pageSlug);
518-
if(Hash::check($request->get('decrypt_password'),$page->decrypt_password))
513+
if($this->validateDecryptPassword($request, $bookSlug, $pageSlug))
519514
{
515+
if($request->has('is_decrypt'))
516+
{
517+
session()->put('is_decrypt',$request->get('is_decrypt'));
518+
\Log::info('Update : ' .session()->get('is_decrypt'));
519+
}
520520
$this->pageRepo->update($page, $request->all());
521-
return response()->json(['contents' => [],'message' => 'Decryption Update SuccessFully','success' => true]);
521+
return response()->json(['contents' => [],'message' => 'Decrypted SuccessFully','success' => true]);
522522
}
523523
else
524524
{
525525
return response()->json(['contents' => [],'message' => 'Decrypt Password is Wrong','success' => false]);
526526
}
527527
}
528+
529+
public function validateDecryptPassword(Request $request,string $bookSlug, string $pageSlug)
530+
{
531+
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug,$pageSlug);
532+
return Hash::check($request->get('decrypt_password'),$page->decrypt_password) ?
533+
response()->json(['success'=>true]) :
534+
response()->json(['success'=>false]);
535+
}
528536
}

app/Entities/Controllers/PageExportController.php

+25-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace BookStack\Entities\Controllers;
44

5+
use BookStack\Entities\Models\Page;
56
use BookStack\Entities\Queries\PageQueries;
67
use BookStack\Entities\Tools\ExportFormatter;
78
use BookStack\Entities\Tools\PageContent;
@@ -28,6 +29,7 @@ public function __construct(
2829
public function pdf(string $bookSlug, string $pageSlug)
2930
{
3031
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
32+
$this->validatePageEncrypted($page);
3133
$page->html = (new PageContent($page))->render();
3234
$pdfContent = $this->exportFormatter->pageToPdf($page);
3335

@@ -43,6 +45,7 @@ public function pdf(string $bookSlug, string $pageSlug)
4345
public function html(string $bookSlug, string $pageSlug)
4446
{
4547
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
48+
$this->validatePageEncrypted($page);
4649
$page->html = (new PageContent($page))->render();
4750
$containedHtml = $this->exportFormatter->pageToContainedHtml($page);
4851

@@ -57,7 +60,8 @@ public function html(string $bookSlug, string $pageSlug)
5760
public function plainText(string $bookSlug, string $pageSlug)
5861
{
5962
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
60-
$pageText = $this->exportFormatter->pageToPlainText($page);
63+
$this->validatePageEncrypted($page);
64+
$pageText = $this->exportFormatter->pageToPlainText($page,$page->is_encrypted);
6165

6266
return $this->download()->directly($pageText, $pageSlug . '.txt');
6367
}
@@ -70,8 +74,28 @@ public function plainText(string $bookSlug, string $pageSlug)
7074
public function markdown(string $bookSlug, string $pageSlug)
7175
{
7276
$page = $this->queries->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
77+
$this->validatePageEncrypted($page);
7378
$pageText = $this->exportFormatter->pageToMarkdown($page);
7479

7580
return $this->download()->directly($pageText, $pageSlug . '.md');
7681
}
82+
83+
public function validatePageEncrypted(Page $page)
84+
{
85+
86+
if($page->is_encrypted)
87+
{
88+
if(session()->get('is_decrypt') == 'FOR_EXPORT')
89+
{
90+
$page->html = decrypt($page->html);
91+
session()->put('is_decrypt','NONE');
92+
return true;
93+
}
94+
else
95+
{
96+
return redirect($page->getUrl());
97+
}
98+
}
99+
return true;
100+
}
77101
}

app/Entities/Queries/PageQueries.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class PageQueries implements ProvidesEntityQueries
1111
protected static array $contentAttributes = [
1212
'name', 'id', 'slug', 'book_id', 'chapter_id', 'draft',
1313
'template', 'html', 'text', 'created_at', 'updated_at', 'priority',
14-
'created_by', 'updated_by', 'owned_by',
14+
'created_by', 'updated_by', 'owned_by', 'is_encrypted',
1515
];
1616
protected static array $listAttributes = [
1717
'name', 'id', 'slug', 'book_id', 'chapter_id', 'draft',

app/Entities/Repos/PageRepo.php

+17-3
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,21 @@ public function update(Page $page, array $input): Page
124124
$this->revisionRepo->storeNewForPage($page, $summary);
125125
}
126126

127-
Activity::add(ActivityType::PAGE_UPDATE, $page);
127+
if(array_key_exists('is_encrypted',$input))
128+
{
129+
if($input['is_encrypted'] == true)
130+
{
131+
Activity::add(ActivityType::PAGE_ENCRYPTED, $page);
132+
}
133+
else if($input['is_encrypted'] == false)
134+
{
135+
Activity::add(ActivityType::PAGE_DECRYPTED, $page);
136+
}
137+
}
138+
else if(!array_key_exists('is_decrypt',$input))
139+
{
140+
Activity::add(ActivityType::PAGE_UPDATE, $page);
141+
}
128142

129143
return $page;
130144
}
@@ -293,7 +307,7 @@ public function encryptPageContent(array $data, Page $page)
293307
if(!$page->is_encrypted)
294308
{
295309
$content = encrypt($data['content']);
296-
return response()->json(['content' => $content,'message' => 'Encrypt Content SuccessFully','success' => true]);
310+
return response()->json(['content' => $content,'message' => 'Encrypted SuccessFully','success' => true]);
297311
}
298312
else
299313
{
@@ -308,7 +322,7 @@ public function decryptPageContent(array $data, Page $page)
308322
if(Hash::check($data['decrypt_password'],$page->decrypt_password))
309323
{
310324
$content = decrypt($data['content']);
311-
return response()->json(['content' => $content,'message' => 'Decrypt Content SuccessFully','success' => true]);
325+
return response()->json(['content' => $content,'message' => 'Decrypted SuccessFully','success' => true]);
312326
}
313327
else
314328
{

app/Entities/Tools/BookContents.php

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public function getLastPriority(): int
4242
public function getTree(bool $showDrafts = false, bool $renderPages = false): Collection
4343
{
4444
$pages = $this->getPages($showDrafts, $renderPages);
45+
46+
// Check For Encrypted Pages
47+
$pages->each(function($page){
48+
$page->html = $page->is_encrypted ? '<p>This page is encrypted</p>' : $page->html;
49+
});
50+
4551
$chapters = $this->book->chapters()->scopes('visible')->get();
4652
$all = collect()->concat($pages)->concat($chapters);
4753
$chapterMap = $chapters->keyBy('id');

app/Entities/Tools/ExportFormatter.php

+20-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function pageToContainedHtml(Page $page): string
3636
'format' => 'html',
3737
'cspContent' => $this->cspService->getCspMetaTagValue(),
3838
'locale' => user()->getLocale(),
39+
'export' => true,
3940
])->render();
4041

4142
return $this->containHtml($pageHtml);
@@ -50,7 +51,7 @@ public function chapterToContainedHtml(Chapter $chapter): string
5051
{
5152
$pages = $chapter->getVisiblePages();
5253
$pages->each(function ($page) {
53-
$page->html = (new PageContent($page))->render();
54+
$page->html = $page->is_encrypted ? "<p>This page is Encrypted</p>" : (new PageContent($page))->render();
5455
});
5556
$html = view('exports.chapter', [
5657
'chapter' => $chapter,
@@ -95,6 +96,7 @@ public function pageToPdf(Page $page): string
9596
'format' => 'pdf',
9697
'engine' => $this->pdfGenerator->getActiveEngine(),
9798
'locale' => user()->getLocale(),
99+
'export' => true,
98100
])->render();
99101

100102
return $this->htmlToPdf($html);
@@ -109,7 +111,7 @@ public function chapterToPdf(Chapter $chapter): string
109111
{
110112
$pages = $chapter->getVisiblePages();
111113
$pages->each(function ($page) {
112-
$page->html = (new PageContent($page))->render();
114+
$page->html = $page->is_encrypted ? "<p>This page is Encrypted</p>" : (new PageContent($page))->render();
113115
});
114116

115117
$html = view('exports.chapter', [
@@ -270,6 +272,10 @@ public function chapterToPlainText(Chapter $chapter): string
270272

271273
$parts = [];
272274
foreach ($chapter->getVisiblePages() as $page) {
275+
if($page->is_encrypted)
276+
{
277+
$page->html = "<p>This page is Encrypted</p>";
278+
}
273279
$parts[] = $this->pageToPlainText($page, false, true);
274280
}
275281

@@ -290,6 +296,10 @@ public function bookToPlainText(Book $book): string
290296
if ($bookChild->isA('chapter')) {
291297
$parts[] = $this->chapterToPlainText($bookChild);
292298
} else {
299+
if($bookChild->is_encrypted)
300+
{
301+
$bookChild->html = "<p>This page is Encrypted</p>";
302+
}
293303
$parts[] = $this->pageToPlainText($bookChild, true, true);
294304
}
295305
}
@@ -317,6 +327,10 @@ public function chapterToMarkdown(Chapter $chapter): string
317327
$text = '# ' . $chapter->name . "\n\n";
318328
$text .= $chapter->description . "\n\n";
319329
foreach ($chapter->pages as $page) {
330+
if($page->is_encrypted)
331+
{
332+
$page->html = "<p>This page is Encrypted</p>";
333+
}
320334
$text .= $this->pageToMarkdown($page) . "\n\n";
321335
}
322336

@@ -334,6 +348,10 @@ public function bookToMarkdown(Book $book): string
334348
if ($bookChild instanceof Chapter) {
335349
$text .= $this->chapterToMarkdown($bookChild) . "\n\n";
336350
} else {
351+
if($bookChild->is_encrypted)
352+
{
353+
$bookChild->html = "<p>This page is Encrypted</p>";
354+
}
337355
$text .= $this->pageToMarkdown($bookChild) . "\n\n";
338356
}
339357
}

app/Uploads/ImageService.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public function saveNew(string $imageName, string $imageData, string $type, int
9898
'type' => $type,
9999
'uploaded_to' => $uploadedTo,
100100
];
101-
101+
dump($this->storage->getPublicUrl($fullPath));
102102
if (user()->id !== 0) {
103103
$userId = user()->id;
104104
$imageDetails['created_by'] = $userId;

database/.gitignore

100644100755
File mode changed.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
public function up(): void
13+
{
14+
Schema::table('entity_permissions', function (Blueprint $table) {
15+
$table->boolean('encrypt');
16+
});
17+
}
18+
19+
/**
20+
* Reverse the migrations.
21+
*/
22+
public function down(): void
23+
{
24+
Schema::table('entity_permissions', function (Blueprint $table) {
25+
$table->removeColumn('encrypt');
26+
});
27+
}
28+
};

lang/en/activities.php

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
'page_restore_notification' => 'Page successfully restored',
1717
'page_move' => 'moved page',
1818
'page_move_notification' => 'Page successfully moved',
19+
'page_encrypted' => 'page encrypted',
20+
'page_encrypted_notification' => 'Page successfully encrypted',
21+
'page_decrypted' => 'page decrypted',
22+
'page_decrypted_notification' => 'Page successfully decrypted',
1923

2024
// Chapters
2125
'chapter_create' => 'created chapter',

resources/js/components/collapsible.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class Collapsible extends Component {
1313
this.content = this.$refs.content;
1414

1515
if (this.trigger) {
16-
this.trigger.addEventListener('click', this.toggle.bind(this));
16+
this.trigger.addEventListener('click',this.toggle.bind(this));
1717
this.openIfContainsError();
1818
}
1919
}

0 commit comments

Comments
 (0)