diff --git a/app/Http/Middleware/PasswordProtection.php b/app/Http/Middleware/PasswordProtection.php index bcb9f9d077c8..54163fac473c 100644 --- a/app/Http/Middleware/PasswordProtection.php +++ b/app/Http/Middleware/PasswordProtection.php @@ -47,8 +47,10 @@ class PasswordProtection //test if password if base64 encoded $x_api_password = $request->header('X-API-PASSWORD'); - if(base64_decode(base64_encode($x_api_password)) === $x_api_password) - $x_api_password = base64_decode($x_api_password); + if($request->header('X-API-PASSWORD-BASE64')) + { + $x_api_password = base64_decode($request->header('X-API-PASSWORD-BASE64')); + } if (Cache::get(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in')) { diff --git a/app/Http/Requests/Login/LoginRequest.php b/app/Http/Requests/Login/LoginRequest.php new file mode 100644 index 000000000000..bb8db25bd0a5 --- /dev/null +++ b/app/Http/Requests/Login/LoginRequest.php @@ -0,0 +1,54 @@ + 'required', + 'password' => 'required', + ]; + } + + protected function prepareForValidation() + { + $input = $this->all(); + + // if(base64_decode(base64_encode($input['password'])) === $input['password']) + // $input['password'] = base64_decode($input['password']); + + // nlog($input['password']); + + $this->replace($input); + } +} diff --git a/app/Listeners/SendVerificationNotification.php b/app/Listeners/SendVerificationNotification.php index b64c2e0d03ca..99e095b10d60 100644 --- a/app/Listeners/SendVerificationNotification.php +++ b/app/Listeners/SendVerificationNotification.php @@ -16,6 +16,7 @@ use App\Jobs\Mail\NinjaMailerJob; use App\Jobs\Mail\NinjaMailerObject; use App\Libraries\MultiDB; use App\Mail\Admin\VerifyUserObject; +use App\Mail\User\UserAdded; use App\Notifications\Ninja\VerifyUser; use App\Utils\Ninja; use Exception; @@ -52,5 +53,13 @@ class SendVerificationNotification implements ShouldQueue $event->user->service()->invite($event->company); + $nmo = new NinjaMailerObject; + $nmo->mailable = new UserAdded($event->company, $event->creating_user, $event->user); + $nmo->company = $event->company; + $nmo->settings = $event->company->settings; + $nmo->to_user = $event->creating_user; + NinjaMailerJob::dispatch($nmo); + + } } diff --git a/app/Mail/User/UserAdded.php b/app/Mail/User/UserAdded.php new file mode 100644 index 000000000000..2c07fbbcb8a7 --- /dev/null +++ b/app/Mail/User/UserAdded.php @@ -0,0 +1,59 @@ +company = $company; + $this->user = $user; + $this->created_user = $created_user; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->from(config('mail.from.address'), config('mail.from.name')) + ->subject(ctrans('texts.created_user')) + ->view('email.admin.user_added') + ->with([ + 'settings' => $this->company->settings, + 'logo' => $this->company->present()->logo(), + 'title' => ctrans('texts.created_user'), + 'body' => ctrans('texts.user_created_user', ['user' => $this->user->present()->name(), 'created_user' => $this->created_user->present()->name(), 'time' => now()]), + 'whitelabel' => $this->company->account->isPaid(), + ]); + } +} diff --git a/app/Utils/Ninja.php b/app/Utils/Ninja.php index 1a31a11daf57..17c859b6f6c6 100644 --- a/app/Utils/Ninja.php +++ b/app/Utils/Ninja.php @@ -170,4 +170,29 @@ class Ninja // return implode('-', $parts); // } + // + + /* + * Available - but not recommended for use + * + * This will guarantee a given string IS the correct format for a + * base64 encoded string , + * but can't guarantee that it is a base64 encoded string + * + */ + public static function isBase64Encoded(string $s) : bool + { + + // Check if there are valid base64 characters + if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s)) return false; + // Decode the string in strict mode and check the results + $decoded = base64_decode($s, true); + if(false === $decoded) return false; + // if string returned contains not printable chars + if (0 < preg_match('/((?![[:graph:]])(?!\s)(?!\p{L}))./', $decoded, $matched)) return false; + // Encode the string again + if(base64_encode($decoded) != $s) return false; + return true; + + } } diff --git a/app/Utils/SystemHealth.php b/app/Utils/SystemHealth.php index cb87d238a52b..b98d5dd3f539 100644 --- a/app/Utils/SystemHealth.php +++ b/app/Utils/SystemHealth.php @@ -83,6 +83,7 @@ class SystemHealth 'flutter_renderer' => (string)config('ninja.flutter_canvas_kit'), 'jobs_pending' => (int) Queue::size(), 'pdf_engine' => (string) self::getPdfEngine(), + 'queue' => (string) config('queue.default'), ]; } diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 2bff23717e28..0b5fa52665a2 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4281,6 +4281,7 @@ $LANG = array( 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved.', 'no_quotes_available_for_download' => 'No quotes available for download.', 'copyright' => 'Copyright', + 'user_created_user' => ':user created :created_user at :time', ); return $LANG; diff --git a/resources/views/email/admin/user_added.blade.php b/resources/views/email/admin/user_added.blade.php new file mode 100644 index 000000000000..2281b8f1bdbe --- /dev/null +++ b/resources/views/email/admin/user_added.blade.php @@ -0,0 +1,6 @@ +@component('email.template.admin', ['logo' => $logo, 'settings' => $settings]) +
+

{!! $title !!}

+

{!! $body !!}

+
+@endcomponent diff --git a/tests/Unit/Base64Test.php b/tests/Unit/Base64Test.php new file mode 100644 index 000000000000..7aed2415f033 --- /dev/null +++ b/tests/Unit/Base64Test.php @@ -0,0 +1,57 @@ +assertFalse(Ninja::isBase64Encoded('x')); + } + + public function testCorrectBase64Encoding() + { + $this->assertTrue(Ninja::isBase64Encoded('MTIzNDU2')); + } + + public function testBadBase64StringScenaro1() + { + $this->assertFalse(Ninja::isBase64Encoded('Matthies')); + } + + public function testBadBase64StringScenaro2() + { + $this->assertFalse(Ninja::isBase64Encoded('Barthels')); + } + + public function testBadBase64StringScenaro3() + { + $this->assertFalse(Ninja::isBase64Encoded('aaa')); + } + +} \ No newline at end of file