diff --git a/extend.php b/extend.php index cb95068..82572c8 100644 --- a/extend.php +++ b/extend.php @@ -14,6 +14,7 @@ use Flarum\Api\Controller\ShowUserController; use Flarum\Api\Serializer\BasicUserSerializer; use Flarum\Api\Serializer\CurrentUserSerializer; +use Flarum\Api\Serializer\ForumSerializer; use Flarum\Api\Serializer\GroupSerializer; use Flarum\Extend; use Flarum\Group\Event\Saving as GroupSaving; @@ -38,7 +39,9 @@ ->post('/users/twofactor/verify', 'user.twofactor.verify', Api\Controller\VerifyTwoFactorController::class) ->delete('/users/{id}/twofactor/disable', 'user.twofactor.disable', Api\Controller\DisableTwoFactorController::class) ->remove('token') - ->post('/token', 'token', Api\Controller\CreateTwoFactorTokenController::class), + ->post('/token', 'token', Api\Controller\CreateTwoFactorTokenController::class) + ->post('/ianm_twofactor_logo', 'ianm_twofactor.logo', Api\Controller\UploadLogoController::class) + ->delete('/ianm_twofactor_logo', 'ianm_twofactor.logo.delete', Api\Controller\DeleteLogoController::class), (new Extend\Routes('forum')) ->remove('login') @@ -66,6 +69,9 @@ (new Extend\ApiSerializer(GroupSerializer::class)) ->attributes(Api\AddGroupAttributes::class), + (new Extend\ApiSerializer(ForumSerializer::class)) + ->attributes(Api\AddForumAttributes::class), + (new Extend\ApiController(ShowUserController::class)) ->addInclude('twoFactor'), diff --git a/js/src/admin/components/SettingsPage.tsx b/js/src/admin/components/SettingsPage.tsx index 19a6567..b9d4233 100644 --- a/js/src/admin/components/SettingsPage.tsx +++ b/js/src/admin/components/SettingsPage.tsx @@ -1,5 +1,6 @@ import app from 'flarum/admin/app'; import ExtensionPage from 'flarum/admin/components/ExtensionPage'; +import UploadImageButton from 'flarum/admin/components/UploadImageButton'; import ExtractedGroupBar from './ExtractedGroupBar'; export default class SettingsPage extends ExtensionPage { @@ -19,6 +20,11 @@ export default class SettingsPage extends ExtensionPage { label: app.translator.trans('ianm-twofactor.admin.settings.forum_logo_qr'), help: app.translator.trans('ianm-twofactor.admin.settings.forum_logo_qr_help'), })} +
+ +
{app.translator.trans('ianm-twofactor.admin.settings.logo_qr_help')}
+ +
{this.buildSettingComponent({ setting: 'ianm-twofactor.admin.settings.forum_logo_qr_width', type: 'number', diff --git a/locale/en.yml b/locale/en.yml index 34b96da..0b6cbd6 100644 --- a/locale/en.yml +++ b/locale/en.yml @@ -15,6 +15,8 @@ ianm-twofactor: forum_logo_qr_help: Embed the forum logo on the QR code displayed when enabling 2FA. This may help users identify the correct QR code to scan. forum_logo_qr_width: Forum Logo QR Code Width forum_logo_qr_width_help: The width of the forum logo embedded on the QR code displayed when enabling 2FA. Max 200. + logo_qr: Logo on QR Code + logo_qr_help: If logo has been uploaded, this logo will be embedded on the QR code. Leave blank to use the forum logo. forum: user_2fa.alert_message: You must enable 2FA to continue accessing your account. @@ -56,7 +58,7 @@ ianm-twofactor: status_changed: | Hello {recipient_display_name}, - Two-Factor Authentication has been {type} for your account on {forum_url}. + Two-Factor Authentication has been {type} for your account on {forum_url}. If you initiated this action, no further steps are necessary. If you did not authorize this change, please contact the forum administrators immediately. views: diff --git a/src/Api/AddForumAttributes.php b/src/Api/AddForumAttributes.php new file mode 100644 index 0000000..918248a --- /dev/null +++ b/src/Api/AddForumAttributes.php @@ -0,0 +1,55 @@ +assetsFilesystem = $filesystemFactory->disk('flarum-assets'); + $this->settings = $settings; + } + + public function __invoke(ForumSerializer $serializer, $object, array $attributes): array + { + $actor = $serializer->getActor(); + + if ($actor->isAdmin()) { + $attributes['ianm_twofactor_logoUrl'] = $this->getLogoUrl(); + } + + return $attributes; + } + + protected function getLogoUrl(): ?string + { + $logoPath = $this->settings->get('ianm_twofactor_logo_path'); + + return $logoPath ? $this->getAssetUrl($logoPath) : null; + } + + public function getAssetUrl(string $assetPath): string + { + return $this->assetsFilesystem->url($assetPath); + } +} diff --git a/src/Api/Controller/CreateTwoFactorTokenController.php b/src/Api/Controller/CreateTwoFactorTokenController.php index f4a01c8..e18a990 100644 --- a/src/Api/Controller/CreateTwoFactorTokenController.php +++ b/src/Api/Controller/CreateTwoFactorTokenController.php @@ -52,7 +52,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface $user = $this->users->findByIdentification($identification); if (! $user || ! $user->checkPassword($password)) { - throw new NotAuthenticatedException; + throw new NotAuthenticatedException(); } if ($this->twoFactorActive($user)) { diff --git a/src/Api/Controller/DeleteLogoController.php b/src/Api/Controller/DeleteLogoController.php new file mode 100644 index 0000000..d5cac3d --- /dev/null +++ b/src/Api/Controller/DeleteLogoController.php @@ -0,0 +1,44 @@ +uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + protected function delete(ServerRequestInterface $request): void + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('ianm_twofactor_logo_path'); + + $this->settings->set('ianm_twofactor_logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + } +} diff --git a/src/Api/Controller/TwoFactorResetPasswordController.php b/src/Api/Controller/TwoFactorResetPasswordController.php index 11b2cd4..a9c807a 100644 --- a/src/Api/Controller/TwoFactorResetPasswordController.php +++ b/src/Api/Controller/TwoFactorResetPasswordController.php @@ -35,7 +35,7 @@ public function render(Request $request) $token = PasswordToken::findOrFail($token); if ($token->created_at < new DateTime('-1 day')) { - throw new InvalidConfirmationTokenException; + throw new InvalidConfirmationTokenException(); } $hasTwoFactorEnabled = $this->twoFactorActive($token->user); diff --git a/src/Api/Controller/UploadLogoController.php b/src/Api/Controller/UploadLogoController.php new file mode 100644 index 0000000..7b985e2 --- /dev/null +++ b/src/Api/Controller/UploadLogoController.php @@ -0,0 +1,44 @@ +imageManager + ->make($file->getStream()->getMetadata('uri')) + ->heighten(60, fn (Constraint $constraint) => $constraint->upsize())->encode('png'); + + return $encodedImage; + } +} diff --git a/src/Services/QrCodeGenerator.php b/src/Services/QrCodeGenerator.php index 27254da..c1a2cc9 100644 --- a/src/Services/QrCodeGenerator.php +++ b/src/Services/QrCodeGenerator.php @@ -44,7 +44,7 @@ public function generate(string $text, bool $asDataUri = false): string ->validateResult(false) ->backgroundColor(new Color(255, 255, 255, 1)); - if ($this->settings->get('ianm-twofactor.admin.settings.forum_logo_qr')) { + if ($this->settings->get('ianm-twofactor.admin.settings.forum_logo_qr') && $this->getLogoUrl()) { $builder ->logoPath($this->getLogoUrl()) ->logoResizeToWidth($this->settings->get('ianm-twofactor.admin.settings.forum_logo_qr_width') ?? 100) @@ -62,7 +62,7 @@ public function generate(string $text, bool $asDataUri = false): string protected function getLogoUrl(): ?string { - $logoPath = $this->settings->get('logo_path'); + $logoPath = $this->settings->get('ianm_twofactor_logo_path') ?? $this->settings->get('logo_path'); return $logoPath ? $this->getAssetUrl($logoPath) : null; }