Skip to content

Commit 10bab70

Browse files
committed
Merge branch 'development' into release
2 parents 350e0b2 + 8e01345 commit 10bab70

File tree

505 files changed

+6202
-3020
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

505 files changed

+6202
-3020
lines changed

.github/translators.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ balmag :: Hungarian
374374
Antti-Jussi Nygård (ajnyga) :: Finnish
375375
Eduard Ereza Martínez (Ereza) :: Catalan
376376
Jabir Lang (amar.almrad) :: Arabic
377-
Jaroslav Koblizek (foretix) :: Czech; French
377+
Jaroslav Kobližek (foretix) :: Czech; French
378378
Wiktor Adamczyk (adamczyk.wiktor) :: Polish
379379
Abdulmajeed Alshuaibi (4Majeed) :: Arabic
380380
NotSmartZakk :: Czech
@@ -393,3 +393,16 @@ TheGatesDev (thegatesdev) :: Dutch
393393
Irdi (irdiOL) :: Albanian
394394
KateBarber :: Welsh
395395
Twister (theuncles75) :: Hebrew
396+
algernon19 :: Hungarian
397+
Ivan Krstic (ikrstic) :: Serbian (Cyrillic)
398+
Show :: Russian
399+
xBahamut :: Portuguese, Brazilian
400+
Pavle Knežević (pavleknezzevic) :: Serbian (Cyrillic)
401+
Vanja Cvelbar (b100w11) :: Slovenian
402+
simonpct :: French
403+
Honza Nagy (honza.nagy) :: Czech
404+
asd20752 :: Norwegian Bokmal
405+
Jan Picka (polipones) :: Czech
406+
diogoalex991 :: Portuguese
407+
Ehsan Sadeghi (ehsansadeghi) :: Persian
408+
ka_picit :: Danish

app/Access/Oidc/OidcOAuthProvider.php

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,9 @@ protected function getScopeSeparator(): string
8383

8484
/**
8585
* Checks a provider response for errors.
86-
*
87-
* @param ResponseInterface $response
88-
* @param array|string $data Parsed response data
89-
*
9086
* @throws IdentityProviderException
91-
*
92-
* @return void
9387
*/
94-
protected function checkResponse(ResponseInterface $response, $data)
88+
protected function checkResponse(ResponseInterface $response, $data): void
9589
{
9690
if ($response->getStatusCode() >= 400 || isset($data['error'])) {
9791
throw new IdentityProviderException(
@@ -105,13 +99,8 @@ protected function checkResponse(ResponseInterface $response, $data)
10599
/**
106100
* Generates a resource owner object from a successful resource owner
107101
* details request.
108-
*
109-
* @param array $response
110-
* @param AccessToken $token
111-
*
112-
* @return ResourceOwnerInterface
113102
*/
114-
protected function createResourceOwner(array $response, AccessToken $token)
103+
protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface
115104
{
116105
return new GenericResourceOwner($response, '');
117106
}
@@ -121,14 +110,18 @@ protected function createResourceOwner(array $response, AccessToken $token)
121110
*
122111
* The grant that was used to fetch the response can be used to provide
123112
* additional context.
124-
*
125-
* @param array $response
126-
* @param AbstractGrant $grant
127-
*
128-
* @return OidcAccessToken
129113
*/
130-
protected function createAccessToken(array $response, AbstractGrant $grant)
114+
protected function createAccessToken(array $response, AbstractGrant $grant): OidcAccessToken
131115
{
132116
return new OidcAccessToken($response);
133117
}
118+
119+
/**
120+
* Get the method used for PKCE code verifier hashing, which is passed
121+
* in the "code_challenge_method" parameter in the authorization request.
122+
*/
123+
protected function getPkceMethod(): string
124+
{
125+
return static::PKCE_METHOD_S256;
126+
}
134127
}

app/Access/Oidc/OidcService.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public function __construct(
3333

3434
/**
3535
* Initiate an authorization flow.
36+
* Provides back an authorize redirect URL, in addition to other
37+
* details which may be required for the auth flow.
3638
*
3739
* @throws OidcException
3840
*
@@ -42,8 +44,12 @@ public function login(): array
4244
{
4345
$settings = $this->getProviderSettings();
4446
$provider = $this->getProvider($settings);
47+
48+
$url = $provider->getAuthorizationUrl();
49+
session()->put('oidc_pkce_code', $provider->getPkceCode() ?? '');
50+
4551
return [
46-
'url' => $provider->getAuthorizationUrl(),
52+
'url' => $url,
4753
'state' => $provider->getState(),
4854
];
4955
}
@@ -63,6 +69,10 @@ public function processAuthorizeResponse(?string $authorizationCode): User
6369
$settings = $this->getProviderSettings();
6470
$provider = $this->getProvider($settings);
6571

72+
// Set PKCE code flashed at login
73+
$pkceCode = session()->pull('oidc_pkce_code', '');
74+
$provider->setPkceCode($pkceCode);
75+
6676
// Try to exchange authorization code for access token
6777
$accessToken = $provider->getAccessToken('authorization_code', [
6878
'code' => $authorizationCode,

app/Access/RegistrationService.php

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,14 @@
1414

1515
class RegistrationService
1616
{
17-
protected $userRepo;
18-
protected $emailConfirmationService;
19-
20-
/**
21-
* RegistrationService constructor.
22-
*/
23-
public function __construct(UserRepo $userRepo, EmailConfirmationService $emailConfirmationService)
24-
{
25-
$this->userRepo = $userRepo;
26-
$this->emailConfirmationService = $emailConfirmationService;
17+
public function __construct(
18+
protected UserRepo $userRepo,
19+
protected EmailConfirmationService $emailConfirmationService,
20+
) {
2721
}
2822

2923
/**
30-
* Check whether or not registrations are allowed in the app settings.
24+
* Check if registrations are allowed in the app settings.
3125
*
3226
* @throws UserRegistrationException
3327
*/
@@ -84,6 +78,7 @@ public function findOrRegister(string $name, string $email, string $externalId):
8478
public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailConfirmed = false): User
8579
{
8680
$userEmail = $userData['email'];
81+
$authSystem = $socialAccount ? $socialAccount->driver : auth()->getDefaultDriver();
8782

8883
// Email restriction
8984
$this->ensureEmailDomainAllowed($userEmail);
@@ -94,6 +89,12 @@ public function registerUser(array $userData, ?SocialAccount $socialAccount = nu
9489
throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $userEmail]), '/login');
9590
}
9691

92+
/** @var ?bool $shouldRegister */
93+
$shouldRegister = Theme::dispatch(ThemeEvents::AUTH_PRE_REGISTER, $authSystem, $userData);
94+
if ($shouldRegister === false) {
95+
throw new UserRegistrationException(trans('errors.auth_pre_register_theme_prevention'), '/login');
96+
}
97+
9798
// Create the user
9899
$newUser = $this->userRepo->createWithoutActivity($userData, $emailConfirmed);
99100
$newUser->attachDefaultRole();
@@ -104,7 +105,7 @@ public function registerUser(array $userData, ?SocialAccount $socialAccount = nu
104105
}
105106

106107
Activity::add(ActivityType::AUTH_REGISTER, $socialAccount ?? $newUser);
107-
Theme::dispatch(ThemeEvents::AUTH_REGISTER, $socialAccount ? $socialAccount->driver : auth()->getDefaultDriver(), $newUser);
108+
Theme::dispatch(ThemeEvents::AUTH_REGISTER, $authSystem, $newUser);
108109

109110
// Start email confirmation flow if required
110111
if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) {
@@ -138,7 +139,7 @@ protected function ensureEmailDomainAllowed(string $userEmail): void
138139
}
139140

140141
$restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
141-
$userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, '@'), 1);
142+
$userEmailDomain = mb_substr(mb_strrchr($userEmail, '@'), 1);
142143
if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
143144
$redirect = $this->registrationAllowed() ? '/register' : '/login';
144145

app/Activity/ActivityQueries.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
use BookStack\Entities\Models\Chapter;
88
use BookStack\Entities\Models\Entity;
99
use BookStack\Entities\Models\Page;
10+
use BookStack\Entities\Tools\MixedEntityListLoader;
1011
use BookStack\Permissions\PermissionApplicator;
1112
use BookStack\Users\Models\User;
1213
use Illuminate\Database\Eloquent\Builder;
1314
use Illuminate\Database\Eloquent\Relations\Relation;
1415

1516
class ActivityQueries
1617
{
17-
protected PermissionApplicator $permissions;
18-
19-
public function __construct(PermissionApplicator $permissions)
20-
{
21-
$this->permissions = $permissions;
18+
public function __construct(
19+
protected PermissionApplicator $permissions,
20+
protected MixedEntityListLoader $listLoader,
21+
) {
2222
}
2323

2424
/**
@@ -29,11 +29,13 @@ public function latest(int $count = 20, int $page = 0): array
2929
$activityList = $this->permissions
3030
->restrictEntityRelationQuery(Activity::query(), 'activities', 'entity_id', 'entity_type')
3131
->orderBy('created_at', 'desc')
32-
->with(['user', 'entity'])
32+
->with(['user'])
3333
->skip($count * $page)
3434
->take($count)
3535
->get();
3636

37+
$this->listLoader->loadIntoRelations($activityList->all(), 'entity', false);
38+
3739
return $this->filterSimilar($activityList);
3840
}
3941

app/Activity/CommentRepo.php

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use BookStack\Activity\Models\Comment;
66
use BookStack\Entities\Models\Entity;
77
use BookStack\Facades\Activity as ActivityService;
8-
use League\CommonMark\CommonMarkConverter;
8+
use BookStack\Util\HtmlDescriptionFilter;
99

1010
class CommentRepo
1111
{
@@ -20,13 +20,12 @@ public function getById(int $id): Comment
2020
/**
2121
* Create a new comment on an entity.
2222
*/
23-
public function create(Entity $entity, string $text, ?int $parent_id): Comment
23+
public function create(Entity $entity, string $html, ?int $parent_id): Comment
2424
{
2525
$userId = user()->id;
2626
$comment = new Comment();
2727

28-
$comment->text = $text;
29-
$comment->html = $this->commentToHtml($text);
28+
$comment->html = HtmlDescriptionFilter::filterFromString($html);
3029
$comment->created_by = $userId;
3130
$comment->updated_by = $userId;
3231
$comment->local_id = $this->getNextLocalId($entity);
@@ -42,11 +41,10 @@ public function create(Entity $entity, string $text, ?int $parent_id): Comment
4241
/**
4342
* Update an existing comment.
4443
*/
45-
public function update(Comment $comment, string $text): Comment
44+
public function update(Comment $comment, string $html): Comment
4645
{
4746
$comment->updated_by = user()->id;
48-
$comment->text = $text;
49-
$comment->html = $this->commentToHtml($text);
47+
$comment->html = HtmlDescriptionFilter::filterFromString($html);
5048
$comment->save();
5149

5250
ActivityService::add(ActivityType::COMMENT_UPDATE, $comment);
@@ -64,20 +62,6 @@ public function delete(Comment $comment): void
6462
ActivityService::add(ActivityType::COMMENT_DELETE, $comment);
6563
}
6664

67-
/**
68-
* Convert the given comment Markdown to HTML.
69-
*/
70-
public function commentToHtml(string $commentText): string
71-
{
72-
$converter = new CommonMarkConverter([
73-
'html_input' => 'strip',
74-
'max_nesting_level' => 10,
75-
'allow_unsafe_links' => false,
76-
]);
77-
78-
return $converter->convert($commentText);
79-
}
80-
8165
/**
8266
* Get the next local ID relative to the linked entity.
8367
*/

app/Activity/Controllers/CommentController.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
namespace BookStack\Activity\Controllers;
44

55
use BookStack\Activity\CommentRepo;
6-
use BookStack\Entities\Models\Page;
6+
use BookStack\Entities\Queries\PageQueries;
77
use BookStack\Http\Controller;
88
use Illuminate\Http\Request;
99
use Illuminate\Validation\ValidationException;
1010

1111
class CommentController extends Controller
1212
{
1313
public function __construct(
14-
protected CommentRepo $commentRepo
14+
protected CommentRepo $commentRepo,
15+
protected PageQueries $pageQueries,
1516
) {
1617
}
1718

@@ -22,12 +23,12 @@ public function __construct(
2223
*/
2324
public function savePageComment(Request $request, int $pageId)
2425
{
25-
$this->validate($request, [
26-
'text' => ['required', 'string'],
26+
$input = $this->validate($request, [
27+
'html' => ['required', 'string'],
2728
'parent_id' => ['nullable', 'integer'],
2829
]);
2930

30-
$page = Page::visible()->find($pageId);
31+
$page = $this->pageQueries->findVisibleById($pageId);
3132
if ($page === null) {
3233
return response('Not found', 404);
3334
}
@@ -39,7 +40,7 @@ public function savePageComment(Request $request, int $pageId)
3940

4041
// Create a new comment.
4142
$this->checkPermission('comment-create-all');
42-
$comment = $this->commentRepo->create($page, $request->get('text'), $request->get('parent_id'));
43+
$comment = $this->commentRepo->create($page, $input['html'], $input['parent_id'] ?? null);
4344

4445
return view('comments.comment-branch', [
4546
'readOnly' => false,
@@ -57,17 +58,20 @@ public function savePageComment(Request $request, int $pageId)
5758
*/
5859
public function update(Request $request, int $commentId)
5960
{
60-
$this->validate($request, [
61-
'text' => ['required', 'string'],
61+
$input = $this->validate($request, [
62+
'html' => ['required', 'string'],
6263
]);
6364

6465
$comment = $this->commentRepo->getById($commentId);
6566
$this->checkOwnablePermission('page-view', $comment->entity);
6667
$this->checkOwnablePermission('comment-update', $comment);
6768

68-
$comment = $this->commentRepo->update($comment, $request->get('text'));
69+
$comment = $this->commentRepo->update($comment, $input['html']);
6970

70-
return view('comments.comment', ['comment' => $comment, 'readOnly' => false]);
71+
return view('comments.comment', [
72+
'comment' => $comment,
73+
'readOnly' => false,
74+
]);
7175
}
7276

7377
/**

app/Activity/Controllers/FavouriteController.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace BookStack\Activity\Controllers;
44

5-
use BookStack\Entities\Queries\TopFavourites;
5+
use BookStack\Entities\Queries\QueryTopFavourites;
66
use BookStack\Entities\Tools\MixedEntityRequestHelper;
77
use BookStack\Http\Controller;
88
use Illuminate\Http\Request;
@@ -17,11 +17,11 @@ public function __construct(
1717
/**
1818
* Show a listing of all favourite items for the current user.
1919
*/
20-
public function index(Request $request)
20+
public function index(Request $request, QueryTopFavourites $topFavourites)
2121
{
2222
$viewCount = 20;
2323
$page = intval($request->get('page', 1));
24-
$favourites = (new TopFavourites())->run($viewCount + 1, (($page - 1) * $viewCount));
24+
$favourites = $topFavourites->run($viewCount + 1, (($page - 1) * $viewCount));
2525

2626
$hasMoreLink = ($favourites->count() > $viewCount) ? url('/favourites?page=' . ($page + 1)) : null;
2727

0 commit comments

Comments
 (0)