Auto commit for release 'develop' on 2024-10-14

This commit is contained in:
github-actions 2024-10-14 05:14:52 +02:00
parent 9463285ac9
commit e0c446dd13
26 changed files with 3613 additions and 3503 deletions

View File

@ -95,7 +95,7 @@ class MFAHandler
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
$user = $event->user; $user = $event->user;
$count = $event->count; $count = $event->count;
try { try {
@ -121,7 +121,7 @@ class MFAHandler
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
$user = $event->user; $user = $event->user;
$count = $event->count; $count = $event->count;
try { try {
@ -143,7 +143,6 @@ class MFAHandler
} }
} }
public function sendBackupNoLeftMail(MFABackupNoLeft $event): void public function sendBackupNoLeftMail(MFABackupNoLeft $event): void
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));

View File

@ -200,7 +200,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
return $this; return $this;
} }
@ -233,7 +233,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id'); $this->query->where('journal_meta.name', '=', 'external_id');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $externalId)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $externalId));
return $this; return $this;
} }
@ -245,7 +245,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id'); $this->query->where('journal_meta.name', '=', 'external_id');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $externalId)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $externalId));
return $this; return $this;
} }
@ -292,7 +292,7 @@ trait MetaCollection
$url = (string)json_encode($url); $url = (string)json_encode($url);
$url = str_replace('\\', '\\\\', trim($url, '"')); $url = str_replace('\\', '\\\\', trim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $url)); $this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $url));
return $this; return $this;
} }
@ -303,7 +303,7 @@ trait MetaCollection
$url = (string)json_encode($url); $url = (string)json_encode($url);
$url = str_replace('\\', '\\\\', trim($url, '"')); $url = str_replace('\\', '\\\\', trim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $url)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $url));
return $this; return $this;
} }
@ -314,7 +314,7 @@ trait MetaCollection
$url = (string)json_encode($url); $url = (string)json_encode($url);
$url = str_replace('\\', '\\\\', ltrim($url, '"')); $url = str_replace('\\', '\\\\', ltrim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s', $url)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s', $url));
return $this; return $this;
} }
@ -327,7 +327,7 @@ trait MetaCollection
// var_dump($url); // var_dump($url);
$this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereNotLike('journal_meta.data', sprintf('%s%%', $url)); $this->query->whereNotLike('journal_meta.data', sprintf('%s%%', $url));
return $this; return $this;
} }
@ -351,7 +351,7 @@ trait MetaCollection
// var_dump($url); // var_dump($url);
$this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereLike('journal_meta.data', sprintf('%s%%', $url)); $this->query->whereLike('journal_meta.data', sprintf('%s%%', $url));
return $this; return $this;
} }
@ -404,7 +404,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $internalReference)); $this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
return $this; return $this;
} }
@ -416,7 +416,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
return $this; return $this;
} }
@ -428,7 +428,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $internalReference)); $this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $internalReference));
return $this; return $this;
} }
@ -440,7 +440,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference)); $this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
return $this; return $this;
} }
@ -452,7 +452,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('%%%s"', $internalReference)); $this->query->whereLike('journal_meta.data', sprintf('%%%s"', $internalReference));
return $this; return $this;
} }
@ -464,7 +464,7 @@ trait MetaCollection
$this->joinMetaDataTables(); $this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference'); $this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference)); $this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
return $this; return $this;
} }
@ -472,7 +472,7 @@ trait MetaCollection
public function notesContain(string $value): GroupCollectorInterface public function notesContain(string $value): GroupCollectorInterface
{ {
$this->withNotes(); $this->withNotes();
$this->query->whereLike('notes.text', sprintf('%%%s%%', $value)); $this->query->whereLike('notes.text', sprintf('%%%s%%', $value));
return $this; return $this;
} }
@ -502,7 +502,7 @@ trait MetaCollection
$this->withNotes(); $this->withNotes();
$this->query->where(static function (Builder $q) use ($value): void { // @phpstan-ignore-line $this->query->where(static function (Builder $q) use ($value): void { // @phpstan-ignore-line
$q->whereNull('notes.text'); $q->whereNull('notes.text');
$q->orWhereNotLike('notes.text', sprintf('%%%s%%', $value)); $q->orWhereNotLike('notes.text', sprintf('%%%s%%', $value));
}); });
return $this; return $this;
@ -513,7 +513,7 @@ trait MetaCollection
$this->withNotes(); $this->withNotes();
$this->query->where(static function (Builder $q) use ($value): void { // @phpstan-ignore-line $this->query->where(static function (Builder $q) use ($value): void { // @phpstan-ignore-line
$q->whereNull('notes.text'); $q->whereNull('notes.text');
$q->orWhereNotLike('notes.text', sprintf('%%%s', $value)); $q->orWhereNotLike('notes.text', sprintf('%%%s', $value));
}); });
return $this; return $this;
@ -524,7 +524,7 @@ trait MetaCollection
$this->withNotes(); $this->withNotes();
$this->query->where(static function (Builder $q) use ($value): void { // @phpstan-ignore-line $this->query->where(static function (Builder $q) use ($value): void { // @phpstan-ignore-line
$q->whereNull('notes.text'); $q->whereNull('notes.text');
$q->orWhereNotLike('notes.text', sprintf('%s%%', $value)); $q->orWhereNotLike('notes.text', sprintf('%s%%', $value));
}); });
return $this; return $this;
@ -533,7 +533,7 @@ trait MetaCollection
public function notesEndWith(string $value): GroupCollectorInterface public function notesEndWith(string $value): GroupCollectorInterface
{ {
$this->withNotes(); $this->withNotes();
$this->query->whereLike('notes.text', sprintf('%%%s', $value)); $this->query->whereLike('notes.text', sprintf('%%%s', $value));
return $this; return $this;
} }
@ -560,7 +560,7 @@ trait MetaCollection
public function notesStartWith(string $value): GroupCollectorInterface public function notesStartWith(string $value): GroupCollectorInterface
{ {
$this->withNotes(); $this->withNotes();
$this->query->whereLike('notes.text', sprintf('%s%%', $value)); $this->query->whereLike('notes.text', sprintf('%s%%', $value));
return $this; return $this;
} }

View File

@ -183,7 +183,7 @@ class GroupCollector implements GroupCollectorInterface
static function (EloquentBuilder $q1) use ($array): void { static function (EloquentBuilder $q1) use ($array): void {
foreach ($array as $word) { foreach ($array as $word) {
$keyword = sprintf('%s%%', $word); $keyword = sprintf('%s%%', $word);
$q1->whereNotLike('transaction_journals.description', $keyword); $q1->whereNotLike('transaction_journals.description', $keyword);
} }
} }
); );
@ -265,7 +265,7 @@ class GroupCollector implements GroupCollectorInterface
static function (EloquentBuilder $q1) use ($array): void { static function (EloquentBuilder $q1) use ($array): void {
foreach ($array as $word) { foreach ($array as $word) {
$keyword = sprintf('%s%%', $word); $keyword = sprintf('%s%%', $word);
$q1->whereLike('transaction_journals.description', $keyword); $q1->whereLike('transaction_journals.description', $keyword);
} }
} }
); );
@ -379,7 +379,7 @@ class GroupCollector implements GroupCollectorInterface
static function (EloquentBuilder $q1) use ($array): void { static function (EloquentBuilder $q1) use ($array): void {
foreach ($array as $word) { foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word); $keyword = sprintf('%%%s%%', $word);
$q1->whereNotLike('transaction_journals.description', $keyword); $q1->whereNotLike('transaction_journals.description', $keyword);
} }
} }
); );
@ -387,7 +387,7 @@ class GroupCollector implements GroupCollectorInterface
static function (EloquentBuilder $q2) use ($array): void { static function (EloquentBuilder $q2) use ($array): void {
foreach ($array as $word) { foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word); $keyword = sprintf('%%%s%%', $word);
$q2->whereNotLike('transaction_groups.title', $keyword); $q2->whereNotLike('transaction_groups.title', $keyword);
$q2->orWhereNull('transaction_groups.title'); $q2->orWhereNull('transaction_groups.title');
} }
} }
@ -944,7 +944,7 @@ class GroupCollector implements GroupCollectorInterface
static function (EloquentBuilder $q1) use ($array): void { static function (EloquentBuilder $q1) use ($array): void {
foreach ($array as $word) { foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word); $keyword = sprintf('%%%s%%', $word);
$q1->whereLike('transaction_journals.description', $keyword); $q1->whereLike('transaction_journals.description', $keyword);
} }
} }
); );

View File

@ -63,8 +63,8 @@ class TwoFactorController extends Controller
public function submitMFA(Request $request) public function submitMFA(Request $request)
{ {
/** @var array $mfaHistory */ /** @var array $mfaHistory */
$mfaHistory = app('preferences')->get('mfa_history', [])->data; $mfaHistory = app('preferences')->get('mfa_history', [])->data;
$mfaCode = (string) $request->get('one_time_password'); $mfaCode = (string) $request->get('one_time_password');
// is in history? then refuse to use it. // is in history? then refuse to use it.
if ($this->inMFAHistory($mfaCode, $mfaHistory)) { if ($this->inMFAHistory($mfaCode, $mfaHistory)) {
@ -79,7 +79,7 @@ class TwoFactorController extends Controller
// if not OK, save error. // if not OK, save error.
if (!$authenticator->isAuthenticated()) { if (!$authenticator->isAuthenticated()) {
$user = auth()->user(); $user = auth()->user();
$this->addToMFAFailureCounter(); $this->addToMFAFailureCounter();
$counter = $this->getMFAFailureCounter(); $counter = $this->getMFAFailureCounter();
if (3 === $counter || 10 === $counter) { if (3 === $counter || 10 === $counter) {
@ -198,7 +198,7 @@ class TwoFactorController extends Controller
*/ */
private function removeFromBackupCodes(string $mfaCode): void private function removeFromBackupCodes(string $mfaCode): void
{ {
$list = app('preferences')->get('mfa_recovery', [])->data; $list = app('preferences')->get('mfa_recovery', [])->data;
if (!is_array($list)) { if (!is_array($list)) {
$list = []; $list = [];
} }
@ -223,7 +223,7 @@ class TwoFactorController extends Controller
private function addToMFAFailureCounter(): void private function addToMFAFailureCounter(): void
{ {
$preference = (int) app('preferences')->get('mfa_failure_count', 0)->data; $preference = (int) app('preferences')->get('mfa_failure_count', 0)->data;
$preference++; ++$preference;
Log::channel('audit')->info(sprintf('MFA failure count is set to %d.', $preference)); Log::channel('audit')->info(sprintf('MFA failure count is set to %d.', $preference));
app('preferences')->set('mfa_failure_count', $preference); app('preferences')->set('mfa_failure_count', $preference);
} }
@ -232,6 +232,7 @@ class TwoFactorController extends Controller
{ {
$value = (int) app('preferences')->get('mfa_failure_count', 0)->data; $value = (int) app('preferences')->get('mfa_failure_count', 0)->data;
Log::channel('audit')->info(sprintf('MFA failure count is %d.', $value)); Log::channel('audit')->info(sprintf('MFA failure count is %d.', $value));
return $value; return $value;
} }

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Profile; namespace FireflyIII\Http\Controllers\Profile;
use FireflyIII\Events\ActuallyLoggedIn;
use FireflyIII\Events\Security\DisabledMFA; use FireflyIII\Events\Security\DisabledMFA;
use FireflyIII\Events\Security\EnabledMFA; use FireflyIII\Events\Security\EnabledMFA;
use FireflyIII\Events\Security\MFANewBackupCodes; use FireflyIII\Events\Security\MFANewBackupCodes;
@ -40,9 +39,6 @@ use Illuminate\Http\Request;
use Illuminate\Routing\Redirector; use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
use PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException;
use PragmaRX\Google2FA\Exceptions\InvalidCharactersException;
use PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException;
use PragmaRX\Recovery\Recovery; use PragmaRX\Recovery\Recovery;
/** /**
@ -83,7 +79,7 @@ class MfaController extends Controller
} }
public function index(): Factory | RedirectResponse | View public function index(): Factory|RedirectResponse|View
{ {
if (!$this->internalAuth) { if (!$this->internalAuth) {
request()->session()->flash('error', trans('firefly.external_user_mgt_disabled')); request()->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
@ -91,34 +87,36 @@ class MfaController extends Controller
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
$subTitle = (string)trans('firefly.mfa_index_title'); $subTitle = (string)trans('firefly.mfa_index_title');
$subTitleIcon = 'fa-calculator'; $subTitleIcon = 'fa-calculator';
$enabledMFA = null !== auth()->user()->mfa_secret; $enabledMFA = null !== auth()->user()->mfa_secret;
return view('profile.mfa.index')->with(compact('subTitle', 'subTitleIcon','enabledMFA'));
return view('profile.mfa.index')->with(compact('subTitle', 'subTitleIcon', 'enabledMFA'));
} }
public function disableMFA(Request $request): Factory | RedirectResponse | View public function disableMFA(Request $request): Factory|RedirectResponse|View
{ {
if (!$this->internalAuth) { if (!$this->internalAuth) {
request()->session()->flash('error', trans('firefly.external_user_mgt_disabled')); request()->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
$enabledMFA = null !== auth()->user()->mfa_secret; $enabledMFA = null !== auth()->user()->mfa_secret;
if(false === $enabledMFA){ if (false === $enabledMFA) {
request()->session()->flash('info',trans('firefly.mfa_already_disabled')); request()->session()->flash('info', trans('firefly.mfa_already_disabled'));
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
$subTitle = (string)trans('firefly.mfa_index_title'); $subTitle = (string)trans('firefly.mfa_index_title');
$subTitleIcon = 'fa-calculator'; $subTitleIcon = 'fa-calculator';
return view('profile.mfa.disable-mfa')->with(compact('subTitle', 'subTitleIcon','enabledMFA')); return view('profile.mfa.disable-mfa')->with(compact('subTitle', 'subTitleIcon', 'enabledMFA'));
} }
/** /**
* Delete 2FA routine. * Delete 2FA routine.
*/ */
public function disableMFAPost(ExistingTokenFormRequest $request): Redirector | RedirectResponse public function disableMFAPost(ExistingTokenFormRequest $request): Redirector|RedirectResponse
{ {
if (!$this->internalAuth) { if (!$this->internalAuth) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled')); $request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
@ -130,7 +128,7 @@ class MfaController extends Controller
$repository = app(UserRepositoryInterface::class); $repository = app(UserRepositoryInterface::class);
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
app('preferences')->delete('temp-mfa-secret'); app('preferences')->delete('temp-mfa-secret');
app('preferences')->delete('temp-mfa-codes'); app('preferences')->delete('temp-mfa-codes');
@ -154,7 +152,7 @@ class MfaController extends Controller
/** /**
* Enable 2FA screen. * Enable 2FA screen.
*/ */
public function enableMFA(Request $request): Redirector | RedirectResponse | View public function enableMFA(Request $request): Redirector|RedirectResponse|View
{ {
if (!$this->internalAuth) { if (!$this->internalAuth) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled')); $request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
@ -174,9 +172,9 @@ class MfaController extends Controller
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
$domain = $this->getDomain(); $domain = $this->getDomain();
$secret = \Google2FA::generateSecretKey(); $secret = \Google2FA::generateSecretKey();
$image = \Google2FA::getQRCodeInline($domain, auth()->user()->email, (string) $secret); $image = \Google2FA::getQRCodeInline($domain, auth()->user()->email, (string) $secret);
app('preferences')->set('temp-mfa-secret', $secret); app('preferences')->set('temp-mfa-secret', $secret);
@ -186,41 +184,45 @@ class MfaController extends Controller
} }
public function backupCodesPost(ExistingTokenFormRequest $request): Redirector | RedirectResponse | View { public function backupCodesPost(ExistingTokenFormRequest $request): Redirector|RedirectResponse|View
{
if (!$this->internalAuth) { if (!$this->internalAuth) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled')); $request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
$enabledMFA = null !== auth()->user()->mfa_secret; $enabledMFA = null !== auth()->user()->mfa_secret;
if(false === $enabledMFA){ if (false === $enabledMFA) {
request()->session()->flash('info',trans('firefly.mfa_not_enabled')); request()->session()->flash('info', trans('firefly.mfa_not_enabled'));
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
// generate recovery codes: // generate recovery codes:
$recovery = app(Recovery::class); $recovery = app(Recovery::class);
$recoveryCodes = $recovery->lowercase() $recoveryCodes = $recovery->lowercase()
->setCount(8) // Generate 8 codes ->setCount(8) // Generate 8 codes
->setBlocks(2) // Every code must have 2 blocks ->setBlocks(2) // Every code must have 2 blocks
->setChars(6) // Each block must have 6 chars ->setChars(6) // Each block must have 6 chars
->toArray(); ->toArray()
;
$codes = implode("\r\n", $recoveryCodes); $codes = implode("\r\n", $recoveryCodes);
app('preferences')->set('mfa_recovery', $recoveryCodes); app('preferences')->set('mfa_recovery', $recoveryCodes);
app('preferences')->mark(); app('preferences')->mark();
// send user notification. // send user notification.
$user = auth()->user(); $user = auth()->user();
Log::channel('audit')->info(sprintf('User "%s" has generated new backup codes.', $user->email)); Log::channel('audit')->info(sprintf('User "%s" has generated new backup codes.', $user->email));
event(new MFANewBackupCodes($user)); event(new MFANewBackupCodes($user));
return view('profile.mfa.backup-codes-post')->with(compact('codes')); return view('profile.mfa.backup-codes-post')->with(compact('codes'));
} }
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
public function backupCodes(Request $request): Factory | RedirectResponse | View public function backupCodes(Request $request): Factory|RedirectResponse|View
{ {
if (!$this->internalAuth) { if (!$this->internalAuth) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled')); $request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
@ -228,8 +230,9 @@ class MfaController extends Controller
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
$enabledMFA = null !== auth()->user()->mfa_secret; $enabledMFA = null !== auth()->user()->mfa_secret;
if(false === $enabledMFA){ if (false === $enabledMFA) {
request()->session()->flash('info',trans('firefly.mfa_not_enabled')); request()->session()->flash('info', trans('firefly.mfa_not_enabled'));
return redirect(route('profile.index')); return redirect(route('profile.index'));
} }
@ -252,12 +255,13 @@ class MfaController extends Controller
} }
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
// verify password. // verify password.
$password = $request->get('password'); $password = $request->get('password');
if (!auth()->validate(['email' => $user->email, 'password' => $password])) { if (!auth()->validate(['email' => $user->email, 'password' => $password])) {
session()->flash('error', 'Bad user pw, no MFA for you!'); session()->flash('error', 'Bad user pw, no MFA for you!');
return redirect(route('profile.mfa.index')); return redirect(route('profile.mfa.index'));
} }
@ -267,7 +271,7 @@ class MfaController extends Controller
if (is_array($secret)) { if (is_array($secret)) {
$secret = null; $secret = null;
} }
$secret = (string) $secret; $secret = (string) $secret;
$repository->setMFACode($user, $secret); $repository->setMFACode($user, $secret);
@ -277,7 +281,7 @@ class MfaController extends Controller
app('preferences')->mark(); app('preferences')->mark();
// also save the code so replay attack is prevented. // also save the code so replay attack is prevented.
$mfaCode = $request->get('code'); $mfaCode = $request->get('code');
$this->addToMFAHistory($mfaCode); $this->addToMFAHistory($mfaCode);
// make sure MFA is logged out. // make sure MFA is logged out.
@ -295,7 +299,6 @@ class MfaController extends Controller
return redirect(route('profile.mfa.backup-codes')); return redirect(route('profile.mfa.backup-codes'));
} }
/** /**
* TODO duplicate code. * TODO duplicate code.
* *
@ -336,5 +339,4 @@ class MfaController extends Controller
} }
app('preferences')->set('mfa_history', $newHistory); app('preferences')->set('mfa_history', $newHistory);
} }
} }

View File

@ -30,7 +30,6 @@ use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Http\Requests\DeleteAccountFormRequest; use FireflyIII\Http\Requests\DeleteAccountFormRequest;
use FireflyIII\Http\Requests\EmailFormRequest; use FireflyIII\Http\Requests\EmailFormRequest;
use FireflyIII\Http\Requests\ProfileFormRequest; use FireflyIII\Http\Requests\ProfileFormRequest;
use FireflyIII\Http\Requests\TokenFormRequest;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Http\Controllers\CreateStuff; use FireflyIII\Support\Http\Controllers\CreateStuff;
@ -45,10 +44,6 @@ use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\View\View; use Illuminate\View\View;
use Laravel\Passport\ClientRepository; use Laravel\Passport\ClientRepository;
use PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException;
use PragmaRX\Google2FA\Exceptions\InvalidCharactersException;
use PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException;
use PragmaRX\Recovery\Recovery;
/** /**
* Class ProfileController. * Class ProfileController.

View File

@ -43,7 +43,7 @@ class ExistingTokenFormRequest extends FormRequest
// fixed // fixed
return [ return [
'password' => 'required|currentPassword', 'password' => 'required|currentPassword',
'code' => 'required|existingMfaCode', 'code' => 'required|existingMfaCode',
]; ];
} }

View File

@ -43,7 +43,7 @@ class TokenFormRequest extends FormRequest
// fixed // fixed
return [ return [
'password' => 'required|currentPassword', 'password' => 'required|currentPassword',
'code' => 'required|2faCode', 'code' => 'required|2faCode',
]; ];
} }

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security; namespace FireflyIII\Notifications\Security;
use FireflyIII\Models\Bill;
use FireflyIII\Support\Notifications\UrlValidator; use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;

View File

@ -42,7 +42,7 @@ class MFABackupFewLeftNotification extends Notification
*/ */
public function __construct(User $user, int $count) public function __construct(User $user, int $count)
{ {
$this->user = $user; $this->user = $user;
$this->count = $count; $this->count = $count;
} }

View File

@ -42,7 +42,7 @@ class MFAManyFailedAttemptsNotification extends Notification
*/ */
public function __construct(User $user, int $count) public function __construct(User $user, int $count)
{ {
$this->user = $user; $this->user = $user;
$this->count = $count; $this->count = $count;
} }

View File

@ -100,7 +100,7 @@ class EventServiceProvider extends ServiceProvider
protected $listen protected $listen
= [ = [
// is a User related event. // is a User related event.
RegisteredUser::class => [ RegisteredUser::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationMail', 'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationMail',
'FireflyIII\Handlers\Events\UserEventHandler@sendAdminRegistrationNotification', 'FireflyIII\Handlers\Events\UserEventHandler@sendAdminRegistrationNotification',
'FireflyIII\Handlers\Events\UserEventHandler@attachUserRole', 'FireflyIII\Handlers\Events\UserEventHandler@attachUserRole',
@ -108,116 +108,116 @@ class EventServiceProvider extends ServiceProvider
'FireflyIII\Handlers\Events\UserEventHandler@createExchangeRates', 'FireflyIII\Handlers\Events\UserEventHandler@createExchangeRates',
], ],
// is a User related event. // is a User related event.
Login::class => [ Login::class => [
'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin', 'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin',
'FireflyIII\Handlers\Events\UserEventHandler@demoUserBackToEnglish', 'FireflyIII\Handlers\Events\UserEventHandler@demoUserBackToEnglish',
], ],
ActuallyLoggedIn::class => [ ActuallyLoggedIn::class => [
'FireflyIII\Handlers\Events\UserEventHandler@storeUserIPAddress', 'FireflyIII\Handlers\Events\UserEventHandler@storeUserIPAddress',
], ],
DetectedNewIPAddress::class => [ DetectedNewIPAddress::class => [
'FireflyIII\Handlers\Events\UserEventHandler@notifyNewIPAddress', 'FireflyIII\Handlers\Events\UserEventHandler@notifyNewIPAddress',
], ],
RequestedVersionCheckStatus::class => [ RequestedVersionCheckStatus::class => [
'FireflyIII\Handlers\Events\VersionCheckEventHandler@checkForUpdates', 'FireflyIII\Handlers\Events\VersionCheckEventHandler@checkForUpdates',
], ],
RequestedReportOnJournals::class => [ RequestedReportOnJournals::class => [
'FireflyIII\Handlers\Events\AutomationHandler@reportJournals', 'FireflyIII\Handlers\Events\AutomationHandler@reportJournals',
], ],
// is a User related event. // is a User related event.
RequestedNewPassword::class => [ RequestedNewPassword::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendNewPassword', 'FireflyIII\Handlers\Events\UserEventHandler@sendNewPassword',
], ],
// is a User related event. // is a User related event.
UserChangedEmail::class => [ UserChangedEmail::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeConfirmMail', 'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeConfirmMail',
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeUndoMail', 'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeUndoMail',
], ],
// admin related // admin related
AdminRequestedTestMessage::class => [ AdminRequestedTestMessage::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendTestMessage', 'FireflyIII\Handlers\Events\AdminEventHandler@sendTestMessage',
], ],
NewVersionAvailable::class => [ NewVersionAvailable::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendNewVersion', 'FireflyIII\Handlers\Events\AdminEventHandler@sendNewVersion',
], ],
InvitationCreated::class => [ InvitationCreated::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendInvitationNotification', 'FireflyIII\Handlers\Events\AdminEventHandler@sendInvitationNotification',
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationInvite', 'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationInvite',
], ],
// is a Transaction Journal related event. // is a Transaction Journal related event.
StoredTransactionGroup::class => [ StoredTransactionGroup::class => [
'FireflyIII\Handlers\Events\StoredGroupEventHandler@processRules', 'FireflyIII\Handlers\Events\StoredGroupEventHandler@processRules',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@recalculateCredit', 'FireflyIII\Handlers\Events\StoredGroupEventHandler@recalculateCredit',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerWebhooks', 'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerWebhooks',
], ],
// is a Transaction Journal related event. // is a Transaction Journal related event.
UpdatedTransactionGroup::class => [ UpdatedTransactionGroup::class => [
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@unifyAccounts', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@unifyAccounts',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@processRules', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@processRules',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@recalculateCredit', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@recalculateCredit',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@triggerWebhooks', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@triggerWebhooks',
], ],
DestroyedTransactionGroup::class => [ DestroyedTransactionGroup::class => [
'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks', 'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks',
], ],
// API related events: // API related events:
AccessTokenCreated::class => [ AccessTokenCreated::class => [
'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated', 'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated',
], ],
// Webhook related event: // Webhook related event:
RequestedSendWebhookMessages::class => [ RequestedSendWebhookMessages::class => [
'FireflyIII\Handlers\Events\WebhookEventHandler@sendWebhookMessages', 'FireflyIII\Handlers\Events\WebhookEventHandler@sendWebhookMessages',
], ],
// account related events: // account related events:
StoredAccount::class => [ StoredAccount::class => [
'FireflyIII\Handlers\Events\StoredAccountEventHandler@recalculateCredit', 'FireflyIII\Handlers\Events\StoredAccountEventHandler@recalculateCredit',
], ],
UpdatedAccount::class => [ UpdatedAccount::class => [
'FireflyIII\Handlers\Events\UpdatedAccountEventHandler@recalculateCredit', 'FireflyIII\Handlers\Events\UpdatedAccountEventHandler@recalculateCredit',
], ],
// bill related events: // bill related events:
WarnUserAboutBill::class => [ WarnUserAboutBill::class => [
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill', 'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill',
], ],
// audit log events: // audit log events:
TriggeredAuditLog::class => [ TriggeredAuditLog::class => [
'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent', 'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent',
], ],
// piggy bank related events: // piggy bank related events:
ChangedAmount::class => [ ChangedAmount::class => [
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount', 'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount',
], ],
// budget related events: CRUD budget limit // budget related events: CRUD budget limit
Created::class => [ Created::class => [
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@created', 'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@created',
], ],
Updated::class => [ Updated::class => [
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@updated', 'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@updated',
], ],
Deleted::class => [ Deleted::class => [
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted', 'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted',
], ],
// rule actions // rule actions
RuleActionFailedOnArray::class => [ RuleActionFailedOnArray::class => [
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray', 'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray',
], ],
RuleActionFailedOnObject::class => [ RuleActionFailedOnObject::class => [
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject', 'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject',
], ],
// security related // security related
EnabledMFA::class => [ EnabledMFA::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAEnabledMail', 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAEnabledMail',
], ],
DisabledMFA::class => [ DisabledMFA::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFADisabledMail', 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFADisabledMail',
], ],
MFANewBackupCodes::class => [ MFANewBackupCodes::class => [
@ -226,13 +226,13 @@ class EventServiceProvider extends ServiceProvider
MFAUsedBackupCode::class => [ MFAUsedBackupCode::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendUsedBackupCodeMail', 'FireflyIII\Handlers\Events\Security\MFAHandler@sendUsedBackupCodeMail',
], ],
MFABackupFewLeft::class => [ MFABackupFewLeft::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail', 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail',
], ],
MFABackupNoLeft::class => [ MFABackupNoLeft::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail', 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail',
], ],
MFAManyFailedAttempts::class => [ MFAManyFailedAttempts::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail', 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail',
], ],
]; ];

View File

@ -604,7 +604,7 @@ class AccountRepository implements AccountRepositoryInterface
$search = sprintf('%%%s%%', $part); $search = sprintf('%%%s%%', $part);
$dbQuery->where( $dbQuery->where(
static function (EloquentBuilder $q1) use ($search): void { // @phpstan-ignore-line static function (EloquentBuilder $q1) use ($search): void { // @phpstan-ignore-line
$q1->whereLike('accounts.iban', $search); $q1->whereLike('accounts.iban', $search);
$q1->orWhere( $q1->orWhere(
static function (EloquentBuilder $q2) use ($search): void { static function (EloquentBuilder $q2) use ($search): void {
$q2->where('account_meta.name', '=', 'account_number'); $q2->where('account_meta.name', '=', 'account_number');

View File

@ -70,7 +70,7 @@ class BillRepository implements BillRepositoryInterface
{ {
$search = $this->user->bills(); $search = $this->user->bills();
if ('' !== $query) { if ('' !== $query) {
$search->whereLike('name', sprintf('%s%%', $query)); $search->whereLike('name', sprintf('%s%%', $query));
} }
$search->orderBy('name', 'ASC') $search->orderBy('name', 'ASC')
->where('active', true) ->where('active', true)

View File

@ -70,7 +70,7 @@ class BudgetRepository implements BudgetRepositoryInterface
{ {
$search = $this->user->budgets(); $search = $this->user->budgets();
if ('' !== $query) { if ('' !== $query) {
$search->whereLike('name', sprintf('%s%%', $query)); $search->whereLike('name', sprintf('%s%%', $query));
} }
$search->orderBy('order', 'ASC') $search->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->where('active', true) ->orderBy('name', 'ASC')->where('active', true)
@ -512,7 +512,7 @@ class BudgetRepository implements BudgetRepositoryInterface
} }
$query = sprintf('%%%s%%', $name); $query = sprintf('%%%s%%', $name);
return $this->user->budgets()->whereLike('name', $query)->first(); return $this->user->budgets()->whereLike('name', $query)->first();
} }
/** /**

View File

@ -152,6 +152,7 @@ class Preferences
public function beginsWith(User $user, string $search): Collection public function beginsWith(User $user, string $search): Collection
{ {
$value = sprintf('%s%%', $search); $value = sprintf('%s%%', $search);
return Preference::where('user_id', $user->id)->whereLike('name', $value)->get(); return Preference::where('user_id', $user->id)->whereLike('name', $value)->get();
} }

View File

@ -83,7 +83,7 @@ class AccountSearch implements GenericSearchInterface
static function (Builder $q) use ($originalQuery): void { // @phpstan-ignore-line static function (Builder $q) use ($originalQuery): void { // @phpstan-ignore-line
$json = json_encode($originalQuery, JSON_THROW_ON_ERROR); $json = json_encode($originalQuery, JSON_THROW_ON_ERROR);
$q->where('account_meta.name', '=', 'account_number'); $q->where('account_meta.name', '=', 'account_number');
$q->whereLike('account_meta.data', $json); $q->whereLike('account_meta.data', $json);
} }
); );
@ -95,7 +95,7 @@ class AccountSearch implements GenericSearchInterface
break; break;
case self::SEARCH_NAME: case self::SEARCH_NAME:
$searchQuery->whereLike('accounts.name', $like); $searchQuery->whereLike('accounts.name', $like);
break; break;

View File

@ -62,7 +62,7 @@ class FireflyValidator extends Validator
if (!is_string($value) || 6 !== strlen($value)) { if (!is_string($value) || 6 !== strlen($value)) {
return false; return false;
} }
$user = auth()->user(); $user = auth()->user();
if (null === $user) { if (null === $user) {
app('log')->error('No user during validate2faCode'); app('log')->error('No user during validate2faCode');
@ -73,25 +73,26 @@ class FireflyValidator extends Validator
if (is_array($secret)) { if (is_array($secret)) {
$secret = ''; $secret = '';
} }
$secret = (string) $secret; $secret = (string) $secret;
return (bool) \Google2FA::verifyKey((string) $secret, $value); return (bool) \Google2FA::verifyKey((string) $secret, $value);
} }
public function validateExistingMfaCode($attribute, $value): bool
{
if (!is_string($value) || 6 !== strlen($value)) {
return false;
}
$user = auth()->user();
if (null === $user) {
app('log')->error('No user during validate2faCode');
return false; public function validateExistingMfaCode($attribute, $value): bool
} {
$secret = (string)$user->mfa_secret; if (!is_string($value) || 6 !== strlen($value)) {
return false;
}
$user = auth()->user();
if (null === $user) {
app('log')->error('No user during validate2faCode');
return (bool) \Google2FA::verifyKey($secret, $value); return false;
} }
$secret = (string)$user->mfa_secret;
return (bool) \Google2FA::verifyKey($secret, $value);
}
/** /**
* @param mixed $attribute * @param mixed $attribute
@ -200,10 +201,10 @@ public function validateExistingMfaCode($attribute, $value): bool
$replace = ['', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35']; $replace = ['', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'];
// take // take
$first = substr($value, 0, 4); $first = substr($value, 0, 4);
$last = substr($value, 4); $last = substr($value, 4);
$iban = $last . $first; $iban = $last.$first;
$iban = trim(str_replace($search, $replace, $iban)); $iban = trim(str_replace($search, $replace, $iban));
if ('' === $iban) { if ('' === $iban) {
return false; return false;
} }
@ -274,8 +275,8 @@ public function validateExistingMfaCode($attribute, $value): bool
{ {
// first, get the index from this string: // first, get the index from this string:
$value ??= ''; $value ??= '';
$parts = explode('.', $attribute); $parts = explode('.', $attribute);
$index = (int) ($parts[1] ?? '0'); $index = (int) ($parts[1] ?? '0');
// get the name of the trigger from the data array: // get the name of the trigger from the data array:
$actionType = $this->data['actions'][$index]['type'] ?? 'invalid'; $actionType = $this->data['actions'][$index]['type'] ?? 'invalid';
@ -344,8 +345,8 @@ public function validateExistingMfaCode($attribute, $value): bool
public function validateRuleTriggerValue(string $attribute, ?string $value = null): bool public function validateRuleTriggerValue(string $attribute, ?string $value = null): bool
{ {
// first, get the index from this string: // first, get the index from this string:
$parts = explode('.', $attribute); $parts = explode('.', $attribute);
$index = (int) ($parts[1] ?? '0'); $index = (int) ($parts[1] ?? '0');
// get the name of the trigger from the data array: // get the name of the trigger from the data array:
$triggerType = $this->data['triggers'][$index]['type'] ?? 'invalid'; $triggerType = $this->data['triggers'][$index]['type'] ?? 'invalid';
@ -356,14 +357,14 @@ public function validateExistingMfaCode($attribute, $value): bool
} }
// these trigger types need a numerical check: // these trigger types need a numerical check:
$numerical = ['amount_less', 'amount_more', 'amount_exactly']; $numerical = ['amount_less', 'amount_more', 'amount_exactly'];
if (in_array($triggerType, $numerical, true)) { if (in_array($triggerType, $numerical, true)) {
return is_numeric($value); return is_numeric($value);
} }
// these triggers need just the word "true": // these triggers need just the word "true":
// TODO create a helper to automatically return these. // TODO create a helper to automatically return these.
$needTrue = [ $needTrue = [
'reconciled', 'has_attachments', 'has_any_category', 'has_any_budget', 'has_any_bill', 'has_any_tag', 'any_notes', 'any_external_url', 'has_no_attachments', 'has_no_category', 'has_no_budget', 'has_no_bill', 'has_no_tag', 'no_notes', 'no_external_url', 'reconciled', 'has_attachments', 'has_any_category', 'has_any_budget', 'has_any_bill', 'has_any_tag', 'any_notes', 'any_external_url', 'has_no_attachments', 'has_no_category', 'has_no_budget', 'has_no_bill', 'has_no_tag', 'no_notes', 'no_external_url',
'source_is_cash', 'source_is_cash',
'destination_is_cash', 'destination_is_cash',
@ -378,7 +379,7 @@ public function validateExistingMfaCode($attribute, $value): bool
// these trigger types need a simple strlen check: // these trigger types need a simple strlen check:
// TODO create a helper to automatically return these. // TODO create a helper to automatically return these.
$length = [ $length = [
'source_account_starts', 'source_account_starts',
'source_account_ends', 'source_account_ends',
'source_account_is', 'source_account_is',
@ -513,9 +514,9 @@ public function validateExistingMfaCode($attribute, $value): bool
} }
/** @var User $user */ /** @var User $user */
$user = User::find($this->data['user_id']); $user = User::find($this->data['user_id']);
$type = AccountType::find($this->data['account_type_id'])->first(); $type = AccountType::find($this->data['account_type_id'])->first();
$value = $this->data['name']; $value = $this->data['name'];
/** @var null|Account $result */ /** @var null|Account $result */
$result = $user->accounts()->where('account_type_id', $type->id)->where('name', $value)->first(); $result = $user->accounts()->where('account_type_id', $type->id)->where('name', $value)->first();
@ -526,7 +527,7 @@ public function validateExistingMfaCode($attribute, $value): bool
private function validateByAccountTypeString(string $value, array $parameters, string $type): bool private function validateByAccountTypeString(string $value, array $parameters, string $type): bool
{ {
/** @var null|array $search */ /** @var null|array $search */
$search = \Config::get('firefly.accountTypeByIdentifier.' . $type); $search = \Config::get('firefly.accountTypeByIdentifier.'.$type);
if (null === $search) { if (null === $search) {
return false; return false;
@ -537,9 +538,10 @@ public function validateExistingMfaCode($attribute, $value): bool
$accountTypeIds = $accountTypes->pluck('id')->toArray(); $accountTypeIds = $accountTypes->pluck('id')->toArray();
/** @var null|Account $result */ /** @var null|Account $result */
$result = auth()->user()->accounts()->whereIn('account_type_id', $accountTypeIds)->where('id', '!=', $ignore) $result = auth()->user()->accounts()->whereIn('account_type_id', $accountTypeIds)->where('id', '!=', $ignore)
->where('name', $value) ->where('name', $value)
->first(); ->first()
;
return null === $result; return null === $result;
} }
@ -555,8 +557,9 @@ public function validateExistingMfaCode($attribute, $value): bool
/** @var null|Account $result */ /** @var null|Account $result */
$result = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) $result = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)
->where('name', $value) ->where('name', $value)
->first(); ->first()
;
return null === $result; return null === $result;
} }
@ -569,12 +572,13 @@ public function validateExistingMfaCode($attribute, $value): bool
/** @var Account $existingAccount */ /** @var Account $existingAccount */
$existingAccount = Account::find($accountId); $existingAccount = Account::find($accountId);
$type = $existingAccount->accountType; $type = $existingAccount->accountType;
$ignore = $existingAccount->id; $ignore = $existingAccount->id;
$entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) $entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)
->where('name', $value) ->where('name', $value)
->first(); ->first()
;
return null === $entry; return null === $entry;
} }
@ -587,12 +591,13 @@ public function validateExistingMfaCode($attribute, $value): bool
/** @var Account $existingAccount */ /** @var Account $existingAccount */
$existingAccount = Account::find($this->data['id']); $existingAccount = Account::find($this->data['id']);
$type = $existingAccount->accountType; $type = $existingAccount->accountType;
$ignore = $existingAccount->id; $ignore = $existingAccount->id;
$entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore) $entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)
->where('name', $value) ->where('name', $value)
->first(); ->first()
;
return null === $entry; return null === $entry;
} }
@ -616,18 +621,19 @@ public function validateExistingMfaCode($attribute, $value): bool
$accountId = (int) ($parameters[0] ?? 0.0); $accountId = (int) ($parameters[0] ?? 0.0);
} }
$query = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id') $query = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
->whereNull('accounts.deleted_at') ->whereNull('accounts.deleted_at')
->where('accounts.user_id', auth()->user()->id) ->where('accounts.user_id', auth()->user()->id)
->where('account_meta.name', 'account_number') ->where('account_meta.name', 'account_number')
->where('account_meta.data', json_encode($value)); ->where('account_meta.data', json_encode($value))
;
if ($accountId > 0) { if ($accountId > 0) {
// exclude current account from check. // exclude current account from check.
$query->where('account_meta.account_id', '!=', $accountId); $query->where('account_meta.account_id', '!=', $accountId);
} }
$set = $query->get(['account_meta.*']); $set = $query->get(['account_meta.*']);
$count = $set->count(); $count = $set->count();
if (0 === $count) { if (0 === $count) {
return true; return true;
} }
@ -635,7 +641,7 @@ public function validateExistingMfaCode($attribute, $value): bool
// pretty much impossible but still. // pretty much impossible but still.
return false; return false;
} }
$type = $this->data['objectType'] ?? 'unknown'; $type = $this->data['objectType'] ?? 'unknown';
if ('expense' !== $type && 'revenue' !== $type) { if ('expense' !== $type && 'revenue' !== $type) {
app('log')->warning(sprintf('Account number "%s" is not unique and account type "%s" cannot share its account number.', $value, $type)); app('log')->warning(sprintf('Account number "%s" is not unique and account type "%s" cannot share its account number.', $value, $type));
@ -705,7 +711,7 @@ public function validateExistingMfaCode($attribute, $value): bool
// get existing webhook value: // get existing webhook value:
if (0 !== $existingId) { if (0 !== $existingId) {
/** @var null|Webhook $webhook */ /** @var null|Webhook $webhook */
$webhook = auth()->user()->webhooks()->find($existingId); $webhook = auth()->user()->webhooks()->find($existingId);
if (null === $webhook) { if (null === $webhook) {
return false; return false;
} }
@ -723,11 +729,12 @@ public function validateExistingMfaCode($attribute, $value): bool
$userId = auth()->user()->id; $userId = auth()->user()->id;
return 0 === Webhook::whereUserId($userId) return 0 === Webhook::whereUserId($userId)
->where('trigger', $trigger) ->where('trigger', $trigger)
->where('response', $response) ->where('response', $response)
->where('delivery', $delivery) ->where('delivery', $delivery)
->where('id', '!=', $existingId) ->where('id', '!=', $existingId)
->where('url', $url)->count(); ->where('url', $url)->count()
;
} }
return false; return false;
@ -749,21 +756,22 @@ public function validateExistingMfaCode($attribute, $value): bool
public function validateUniqueObjectForUser($attribute, $value, $parameters): bool public function validateUniqueObjectForUser($attribute, $value, $parameters): bool
{ {
[$table, $field] = $parameters; [$table, $field] = $parameters;
$exclude = (int) ($parameters[2] ?? 0.0); $exclude = (int) ($parameters[2] ?? 0.0);
/* /*
* If other data (in $this->getData()) contains * If other data (in $this->getData()) contains
* ID field, set that field to be the $exclude. * ID field, set that field to be the $exclude.
*/ */
$data = $this->getData(); $data = $this->getData();
if (!array_key_exists(2, $parameters) && array_key_exists('id', $data) && (int) $data['id'] > 0) { if (!array_key_exists(2, $parameters) && array_key_exists('id', $data) && (int) $data['id'] > 0) {
$exclude = (int) $data['id']; $exclude = (int) $data['id'];
} }
// get entries from table // get entries from table
$result = \DB::table($table)->where('user_id', auth()->user()->id)->whereNull('deleted_at') $result = \DB::table($table)->where('user_id', auth()->user()->id)->whereNull('deleted_at')
->where('id', '!=', $exclude) ->where('id', '!=', $exclude)
->where($field, $value) ->where($field, $value)
->first([$field]); ->first([$field])
;
if (null === $result) { if (null === $result) {
return true; // not found, so true. return true; // not found, so true.
} }
@ -783,9 +791,10 @@ public function validateExistingMfaCode($attribute, $value): bool
{ {
$exclude = $parameters[0] ?? null; $exclude = $parameters[0] ?? null;
$query = \DB::table('object_groups') $query = \DB::table('object_groups')
->whereNull('object_groups.deleted_at') ->whereNull('object_groups.deleted_at')
->where('object_groups.user_id', auth()->user()->id) ->where('object_groups.user_id', auth()->user()->id)
->where('object_groups.title', $value); ->where('object_groups.title', $value)
;
if (null !== $exclude) { if (null !== $exclude) {
$query->where('object_groups.id', '!=', (int) $exclude); $query->where('object_groups.id', '!=', (int) $exclude);
} }
@ -804,7 +813,8 @@ public function validateExistingMfaCode($attribute, $value): bool
{ {
$exclude = $parameters[0] ?? null; $exclude = $parameters[0] ?? null;
$query = \DB::table('piggy_banks')->whereNull('piggy_banks.deleted_at') $query = \DB::table('piggy_banks')->whereNull('piggy_banks.deleted_at')
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('accounts.user_id', auth()->user()->id); ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('accounts.user_id', auth()->user()->id)
;
if (null !== $exclude) { if (null !== $exclude) {
$query->where('piggy_banks.id', '!=', (int) $exclude); $query->where('piggy_banks.id', '!=', (int) $exclude);
} }
@ -827,17 +837,17 @@ public function validateExistingMfaCode($attribute, $value): bool
$deliveries = Webhook::getDeliveriesForValidation(); $deliveries = Webhook::getDeliveriesForValidation();
// integers // integers
$trigger = $triggers[$this->data['trigger']] ?? 0; $trigger = $triggers[$this->data['trigger']] ?? 0;
$response = $responses[$this->data['response']] ?? 0; $response = $responses[$this->data['response']] ?? 0;
$delivery = $deliveries[$this->data['delivery']] ?? 0; $delivery = $deliveries[$this->data['delivery']] ?? 0;
$url = $this->data['url']; $url = $this->data['url'];
$userId = auth()->user()->id; $userId = auth()->user()->id;
return 0 === Webhook::whereUserId($userId) return 0 === Webhook::whereUserId($userId)
->where('trigger', $trigger) ->where('trigger', $trigger)
->where('response', $response) ->where('response', $response)
->where('delivery', $delivery) ->where('delivery', $delivery)
->where('url', $url)->count(); ->where('url', $url)->count();
} }
return false; return false;

139
composer.lock generated
View File

@ -755,16 +755,16 @@
}, },
{ {
"name": "dragonmantank/cron-expression", "name": "dragonmantank/cron-expression",
"version": "v3.3.3", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/dragonmantank/cron-expression.git", "url": "https://github.com/dragonmantank/cron-expression.git",
"reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" "reference": "8c784d071debd117328803d86b2097615b457500"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500",
"reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", "reference": "8c784d071debd117328803d86b2097615b457500",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -777,10 +777,14 @@
"require-dev": { "require-dev": {
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.0", "phpstan/phpstan": "^1.0",
"phpstan/phpstan-webmozart-assert": "^1.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0" "phpunit/phpunit": "^7.0|^8.0|^9.0"
}, },
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Cron\\": "src/Cron/" "Cron\\": "src/Cron/"
@ -804,7 +808,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/dragonmantank/cron-expression/issues", "issues": "https://github.com/dragonmantank/cron-expression/issues",
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -812,7 +816,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-08-10T19:36:49+00:00" "time": "2024-10-09T13:47:03+00:00"
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
@ -1996,16 +2000,16 @@
}, },
{ {
"name": "laravel-json-api/eloquent", "name": "laravel-json-api/eloquent",
"version": "v4.2.0", "version": "v4.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel-json-api/eloquent.git", "url": "https://github.com/laravel-json-api/eloquent.git",
"reference": "35ccb634bd605697df3700660dedc0c292ac86ec" "reference": "05644f31eb086e4d640f15eac7d03752ffcde99f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel-json-api/eloquent/zipball/35ccb634bd605697df3700660dedc0c292ac86ec", "url": "https://api.github.com/repos/laravel-json-api/eloquent/zipball/05644f31eb086e4d640f15eac7d03752ffcde99f",
"reference": "35ccb634bd605697df3700660dedc0c292ac86ec", "reference": "05644f31eb086e4d640f15eac7d03752ffcde99f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2054,9 +2058,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/laravel-json-api/eloquent/issues", "issues": "https://github.com/laravel-json-api/eloquent/issues",
"source": "https://github.com/laravel-json-api/eloquent/tree/v4.2.0" "source": "https://github.com/laravel-json-api/eloquent/tree/v4.3.0"
}, },
"time": "2024-08-26T08:11:13+00:00" "time": "2024-10-13T12:53:07+00:00"
}, },
{ {
"name": "laravel-json-api/encoder-neomerx", "name": "laravel-json-api/encoder-neomerx",
@ -2543,16 +2547,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v11.26.0", "version": "v11.27.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "b8cb8998701d5b3cfe68539d3c3da1fc59ddd82b" "reference": "a51d1f2b771c542324a3d9b76a98b1bbc75c0ee9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/b8cb8998701d5b3cfe68539d3c3da1fc59ddd82b", "url": "https://api.github.com/repos/laravel/framework/zipball/a51d1f2b771c542324a3d9b76a98b1bbc75c0ee9",
"reference": "b8cb8998701d5b3cfe68539d3c3da1fc59ddd82b", "reference": "a51d1f2b771c542324a3d9b76a98b1bbc75c0ee9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2748,7 +2752,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2024-10-01T14:29:34+00:00" "time": "2024-10-09T04:17:35+00:00"
}, },
{ {
"name": "laravel/passport", "name": "laravel/passport",
@ -3204,38 +3208,38 @@
}, },
{ {
"name": "lcobucci/jwt", "name": "lcobucci/jwt",
"version": "5.3.0", "version": "5.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/lcobucci/jwt.git", "url": "https://github.com/lcobucci/jwt.git",
"reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83" "reference": "aac4fd512681fd5cb4b77d2105ab7ec700c72051"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", "url": "https://api.github.com/repos/lcobucci/jwt/zipball/aac4fd512681fd5cb4b77d2105ab7ec700c72051",
"reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", "reference": "aac4fd512681fd5cb4b77d2105ab7ec700c72051",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-openssl": "*", "ext-openssl": "*",
"ext-sodium": "*", "ext-sodium": "*",
"php": "~8.1.0 || ~8.2.0 || ~8.3.0", "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
"psr/clock": "^1.0" "psr/clock": "^1.0"
}, },
"require-dev": { "require-dev": {
"infection/infection": "^0.27.0", "infection/infection": "^0.29",
"lcobucci/clock": "^3.0", "lcobucci/clock": "^3.2",
"lcobucci/coding-standard": "^11.0", "lcobucci/coding-standard": "^11.0",
"phpbench/phpbench": "^1.2.9", "phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.2", "phpstan/extension-installer": "^1.2",
"phpstan/phpstan": "^1.10.7", "phpstan/phpstan": "^1.10.7",
"phpstan/phpstan-deprecation-rules": "^1.1.3", "phpstan/phpstan-deprecation-rules": "^1.1.3",
"phpstan/phpstan-phpunit": "^1.3.10", "phpstan/phpstan-phpunit": "^1.3.10",
"phpstan/phpstan-strict-rules": "^1.5.0", "phpstan/phpstan-strict-rules": "^1.5.0",
"phpunit/phpunit": "^10.2.6" "phpunit/phpunit": "^11.1"
}, },
"suggest": { "suggest": {
"lcobucci/clock": ">= 3.0" "lcobucci/clock": ">= 3.2"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -3261,7 +3265,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/lcobucci/jwt/issues", "issues": "https://github.com/lcobucci/jwt/issues",
"source": "https://github.com/lcobucci/jwt/tree/5.3.0" "source": "https://github.com/lcobucci/jwt/tree/5.4.0"
}, },
"funding": [ "funding": [
{ {
@ -3273,7 +3277,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2024-04-11T23:07:54+00:00" "time": "2024-10-08T22:06:45+00:00"
}, },
{ {
"name": "league/commonmark", "name": "league/commonmark",
@ -3465,16 +3469,16 @@
}, },
{ {
"name": "league/csv", "name": "league/csv",
"version": "9.16.0", "version": "9.17.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/csv.git", "url": "https://github.com/thephpleague/csv.git",
"reference": "998280c6c34bd67d8125fdc8b45bae28d761b440" "reference": "8cab815fb11ec93aa2f7b8a57b3daa1f1a364011"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/998280c6c34bd67d8125fdc8b45bae28d761b440", "url": "https://api.github.com/repos/thephpleague/csv/zipball/8cab815fb11ec93aa2f7b8a57b3daa1f1a364011",
"reference": "998280c6c34bd67d8125fdc8b45bae28d761b440", "reference": "8cab815fb11ec93aa2f7b8a57b3daa1f1a364011",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3482,17 +3486,16 @@
"php": "^8.1.2" "php": "^8.1.2"
}, },
"require-dev": { "require-dev": {
"doctrine/collections": "^2.2.2",
"ext-dom": "*", "ext-dom": "*",
"ext-xdebug": "*", "ext-xdebug": "*",
"friendsofphp/php-cs-fixer": "^3.57.1", "friendsofphp/php-cs-fixer": "^3.64.0",
"phpbench/phpbench": "^1.2.15", "phpbench/phpbench": "^1.3.1",
"phpstan/phpstan": "^1.11.1", "phpstan/phpstan": "^1.12.5",
"phpstan/phpstan-deprecation-rules": "^1.2.0", "phpstan/phpstan-deprecation-rules": "^1.2.1",
"phpstan/phpstan-phpunit": "^1.4.0", "phpstan/phpstan-phpunit": "^1.4.0",
"phpstan/phpstan-strict-rules": "^1.6.0", "phpstan/phpstan-strict-rules": "^1.6.1",
"phpunit/phpunit": "^10.5.16 || ^11.1.3", "phpunit/phpunit": "^10.5.16 || ^11.4.0",
"symfony/var-dumper": "^6.4.6 || ^7.0.7" "symfony/var-dumper": "^6.4.8 || ^7.1.5"
}, },
"suggest": { "suggest": {
"ext-dom": "Required to use the XMLConverter and the HTMLConverter classes", "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes",
@ -3510,7 +3513,7 @@
"src/functions_include.php" "src/functions_include.php"
], ],
"psr-4": { "psr-4": {
"League\\Csv\\": "src" "League\\Csv\\": "src/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -3549,7 +3552,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-05-24T11:04:54+00:00" "time": "2024-10-10T10:30:28+00:00"
}, },
{ {
"name": "league/event", "name": "league/event",
@ -3607,16 +3610,16 @@
}, },
{ {
"name": "league/flysystem", "name": "league/flysystem",
"version": "3.29.0", "version": "3.29.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem.git", "url": "https://github.com/thephpleague/flysystem.git",
"reference": "0adc0d9a51852e170e0028a60bd271726626d3f0" "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/0adc0d9a51852e170e0028a60bd271726626d3f0", "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319",
"reference": "0adc0d9a51852e170e0028a60bd271726626d3f0", "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3684,9 +3687,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem/issues", "issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.29.0" "source": "https://github.com/thephpleague/flysystem/tree/3.29.1"
}, },
"time": "2024-09-29T11:59:11+00:00" "time": "2024-10-08T08:58:34+00:00"
}, },
{ {
"name": "league/flysystem-local", "name": "league/flysystem-local",
@ -11490,16 +11493,16 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v5.3.0", "version": "v5.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a" "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
"reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a", "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -11542,9 +11545,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.0" "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
}, },
"time": "2024-09-29T13:56:26+00:00" "time": "2024-10-08T18:51:32+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@ -11912,16 +11915,16 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.32.0", "version": "1.33.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4" "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ca22b154efdd9e3c68c56f5d94670920a1c19a4", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140",
"reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4", "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -11953,9 +11956,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.32.0" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0"
}, },
"time": "2024-09-26T07:23:32+00:00" "time": "2024-10-13T11:25:22+00:00"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
@ -12434,16 +12437,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.5.35", "version": "10.5.36",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "7ac8b4e63f456046dcb4c9787da9382831a1874b" "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7ac8b4e63f456046dcb4c9787da9382831a1874b", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870",
"reference": "7ac8b4e63f456046dcb4c9787da9382831a1874b", "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -12515,7 +12518,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.35" "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.36"
}, },
"funding": [ "funding": [
{ {
@ -12531,7 +12534,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-19T10:52:21+00:00" "time": "2024-10-08T15:36:51+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@ -110,7 +110,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false), 'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag. // see cer.php for exchange rates feature flag.
], ],
'version' => 'develop/2024-10-07', 'version' => 'develop/2024-10-14',
'api_version' => '2.1.0', 'api_version' => '2.1.0',
'db_version' => 24, 'db_version' => 24,

782
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -82,8 +82,8 @@ return [
'placeholder' => '[Placeholder]', 'placeholder' => '[Placeholder]',
// mfa // mfa
'profile_mfa' => 'Multi-factor authentication', 'profile_mfa' => 'Multi-factor authentication',
'mfa_enableMFA' => 'Enable multi-factor authentication', 'mfa_enableMFA' => 'Enable multi-factor authentication',
'mfa_backup_codes' => 'Backup codes', 'mfa_backup_codes' => 'Backup codes',
'mfa_disableMFA' => 'Disable multi-factor authentication', 'mfa_disableMFA' => 'Disable multi-factor authentication',
]; ];

View File

@ -26,154 +26,154 @@ declare(strict_types=1);
return [ return [
// common items // common items
'greeting' => 'Hi there,', 'greeting' => 'Hi there,',
'closing' => 'Beep boop,', 'closing' => 'Beep boop,',
'signature' => 'The Firefly III Mail Robot', 'signature' => 'The Firefly III Mail Robot',
'footer_ps' => 'PS: This message was sent because a request from IP :ipAddress triggered it.', 'footer_ps' => 'PS: This message was sent because a request from IP :ipAddress triggered it.',
// admin test // admin test
'admin_test_subject' => 'A test message from your Firefly III installation', 'admin_test_subject' => 'A test message from your Firefly III installation',
'admin_test_body' => 'This is a test message from your Firefly III instance. It was sent to :email.', 'admin_test_body' => 'This is a test message from your Firefly III instance. It was sent to :email.',
// Ignore this comment // Ignore this comment
// invite // invite
'invitation_created_subject' => 'An invitation has been created', 'invitation_created_subject' => 'An invitation has been created',
'invitation_created_body' => 'Admin user ":email" created a user invitation which can be used by whoever is behind email address ":invitee". The invite will be valid for 48hrs.', 'invitation_created_body' => 'Admin user ":email" created a user invitation which can be used by whoever is behind email address ":invitee". The invite will be valid for 48hrs.',
'invite_user_subject' => 'You\'ve been invited to create a Firefly III account.', 'invite_user_subject' => 'You\'ve been invited to create a Firefly III account.',
'invitation_introduction' => 'You\'ve been invited to create a Firefly III account on **:host**. Firefly III is a personal, self-hosted, private personal finance manager. All the cool kids are using it.', 'invitation_introduction' => 'You\'ve been invited to create a Firefly III account on **:host**. Firefly III is a personal, self-hosted, private personal finance manager. All the cool kids are using it.',
'invitation_invited_by' => 'You\'ve been invited by ":admin" and this invitation was sent to ":invitee". That\'s you, right?', 'invitation_invited_by' => 'You\'ve been invited by ":admin" and this invitation was sent to ":invitee". That\'s you, right?',
'invitation_url' => 'The invitation is valid for 48 hours and can be redeemed by surfing to [Firefly III](:url). Enjoy!', 'invitation_url' => 'The invitation is valid for 48 hours and can be redeemed by surfing to [Firefly III](:url). Enjoy!',
// new IP // new IP
'login_from_new_ip' => 'New login on Firefly III', 'login_from_new_ip' => 'New login on Firefly III',
'slack_login_from_new_ip' => 'New Firefly III login from IP :ip (:host)', 'slack_login_from_new_ip' => 'New Firefly III login from IP :ip (:host)',
'new_ip_body' => 'Firefly III detected a new login on your account from an unknown IP address. If you never logged in from the IP address below, or it has been more than six months ago, Firefly III will warn you.', 'new_ip_body' => 'Firefly III detected a new login on your account from an unknown IP address. If you never logged in from the IP address below, or it has been more than six months ago, Firefly III will warn you.',
'new_ip_warning' => 'If you recognize this IP address or the login, you can ignore this message. If you didn\'t login, of if you have no idea what this is about, verify your password security, change it, and log out all other sessions. To do this, go to your profile page. Of course you have 2FA enabled already, right? Stay safe!', 'new_ip_warning' => 'If you recognize this IP address or the login, you can ignore this message. If you didn\'t login, of if you have no idea what this is about, verify your password security, change it, and log out all other sessions. To do this, go to your profile page. Of course you have 2FA enabled already, right? Stay safe!',
'ip_address' => 'IP address', 'ip_address' => 'IP address',
'host_name' => 'Host', 'host_name' => 'Host',
'date_time' => 'Date + time', 'date_time' => 'Date + time',
// access token created // access token created
'access_token_created_subject' => 'A new access token was created', 'access_token_created_subject' => 'A new access token was created',
'access_token_created_body' => 'Somebody (hopefully you) just created a new Firefly III API Access Token for your user account.', 'access_token_created_body' => 'Somebody (hopefully you) just created a new Firefly III API Access Token for your user account.',
'access_token_created_explanation' => 'With this token, they can access **all** of your financial records through the Firefly III API.', 'access_token_created_explanation' => 'With this token, they can access **all** of your financial records through the Firefly III API.',
'access_token_created_revoke' => 'If this wasn\'t you, please revoke this token as soon as possible at :url', 'access_token_created_revoke' => 'If this wasn\'t you, please revoke this token as soon as possible at :url',
// registered // registered
'registered_subject' => 'Welcome to Firefly III!', 'registered_subject' => 'Welcome to Firefly III!',
'registered_subject_admin' => 'A new user has registered', 'registered_subject_admin' => 'A new user has registered',
'admin_new_user_registered' => 'A new user has registered. User **:email** was given user ID #:id.', 'admin_new_user_registered' => 'A new user has registered. User **:email** was given user ID #:id.',
'registered_welcome' => 'Welcome to [Firefly III](:address). Your registration has made it, and this email is here to confirm it. Yay!', 'registered_welcome' => 'Welcome to [Firefly III](:address). Your registration has made it, and this email is here to confirm it. Yay!',
'registered_pw' => 'If you have forgotten your password already, please reset it using [the password reset tool](:address/password/reset).', 'registered_pw' => 'If you have forgotten your password already, please reset it using [the password reset tool](:address/password/reset).',
'registered_help' => 'There is a help-icon in the top right corner of each page. If you need help, click it!', 'registered_help' => 'There is a help-icon in the top right corner of each page. If you need help, click it!',
'registered_closing' => 'Enjoy!', 'registered_closing' => 'Enjoy!',
'registered_firefly_iii_link' => 'Firefly III:', 'registered_firefly_iii_link' => 'Firefly III:',
'registered_pw_reset_link' => 'Password reset:', 'registered_pw_reset_link' => 'Password reset:',
'registered_doc_link' => 'Documentation:', 'registered_doc_link' => 'Documentation:',
// Ignore this comment // Ignore this comment
// new version // new version
'new_version_email_subject' => 'A new Firefly III version is available', 'new_version_email_subject' => 'A new Firefly III version is available',
// email change // email change
'email_change_subject' => 'Your Firefly III email address has changed', 'email_change_subject' => 'Your Firefly III email address has changed',
'email_change_body_to_new' => 'You or somebody with access to your Firefly III account has changed your email address. If you did not expect this message, please ignore and delete it.', 'email_change_body_to_new' => 'You or somebody with access to your Firefly III account has changed your email address. If you did not expect this message, please ignore and delete it.',
'email_change_body_to_old' => 'You or somebody with access to your Firefly III account has changed your email address. If you did not expect this to happen, you **must** follow the "undo"-link below to protect your account!', 'email_change_body_to_old' => 'You or somebody with access to your Firefly III account has changed your email address. If you did not expect this to happen, you **must** follow the "undo"-link below to protect your account!',
'email_change_ignore' => 'If you initiated this change, you may safely ignore this message.', 'email_change_ignore' => 'If you initiated this change, you may safely ignore this message.',
'email_change_old' => 'The old email address was: :email', 'email_change_old' => 'The old email address was: :email',
'email_change_old_strong' => 'The old email address was: **:email**', 'email_change_old_strong' => 'The old email address was: **:email**',
'email_change_new' => 'The new email address is: :email', 'email_change_new' => 'The new email address is: :email',
'email_change_new_strong' => 'The new email address is: **:email**', 'email_change_new_strong' => 'The new email address is: **:email**',
'email_change_instructions' => 'You cannot use Firefly III until you confirm this change. Please follow the link below to do so.', 'email_change_instructions' => 'You cannot use Firefly III until you confirm this change. Please follow the link below to do so.',
'email_change_undo_link' => 'To undo the change, follow this link:', 'email_change_undo_link' => 'To undo the change, follow this link:',
// OAuth token created // OAuth token created
'oauth_created_subject' => 'A new OAuth client has been created', 'oauth_created_subject' => 'A new OAuth client has been created',
'oauth_created_body' => 'Somebody (hopefully you) just created a new Firefly III API OAuth Client for your user account. It\'s labeled ":name" and has callback URL `:url`.', 'oauth_created_body' => 'Somebody (hopefully you) just created a new Firefly III API OAuth Client for your user account. It\'s labeled ":name" and has callback URL `:url`.',
'oauth_created_explanation' => 'With this client, they can access **all** of your financial records through the Firefly III API.', 'oauth_created_explanation' => 'With this client, they can access **all** of your financial records through the Firefly III API.',
'oauth_created_undo' => 'If this wasn\'t you, please revoke this client as soon as possible at `:url`', 'oauth_created_undo' => 'If this wasn\'t you, please revoke this client as soon as possible at `:url`',
// reset password // reset password
'reset_pw_subject' => 'Your password reset request', 'reset_pw_subject' => 'Your password reset request',
'reset_pw_instructions' => 'Somebody tried to reset your password. If it was you, please follow the link below to do so.', 'reset_pw_instructions' => 'Somebody tried to reset your password. If it was you, please follow the link below to do so.',
'reset_pw_warning' => '**PLEASE** verify that the link actually goes to the Firefly III you expect it to go!', 'reset_pw_warning' => '**PLEASE** verify that the link actually goes to the Firefly III you expect it to go!',
// error // error
'error_subject' => 'Caught an error in Firefly III', 'error_subject' => 'Caught an error in Firefly III',
'error_intro' => 'Firefly III v:version ran into an error: <span style="font-family: monospace;">:errorMessage</span>.', 'error_intro' => 'Firefly III v:version ran into an error: <span style="font-family: monospace;">:errorMessage</span>.',
'error_type' => 'The error was of type ":class".', 'error_type' => 'The error was of type ":class".',
'error_timestamp' => 'The error occurred on/at: :time.', 'error_timestamp' => 'The error occurred on/at: :time.',
'error_location' => 'This error occurred in file "<span style="font-family: monospace;">:file</span>" on line :line with code :code.', 'error_location' => 'This error occurred in file "<span style="font-family: monospace;">:file</span>" on line :line with code :code.',
'error_user' => 'The error was encountered by user #:id, <a href="mailto::email">:email</a>.', 'error_user' => 'The error was encountered by user #:id, <a href="mailto::email">:email</a>.',
'error_no_user' => 'There was no user logged in for this error or no user was detected.', 'error_no_user' => 'There was no user logged in for this error or no user was detected.',
'error_ip' => 'The IP address related to this error is: :ip', 'error_ip' => 'The IP address related to this error is: :ip',
'error_url' => 'URL is: :url', 'error_url' => 'URL is: :url',
'error_user_agent' => 'User agent: :userAgent', 'error_user_agent' => 'User agent: :userAgent',
'error_stacktrace' => 'The full stacktrace is below. If you think this is a bug in Firefly III, you can forward this message to <a href="mailto:james@firefly-iii.org?subject=I%20found%20a%20bug!">james@firefly-iii.org</a>. This can help fix the bug you just encountered.', 'error_stacktrace' => 'The full stacktrace is below. If you think this is a bug in Firefly III, you can forward this message to <a href="mailto:james@firefly-iii.org?subject=I%20found%20a%20bug!">james@firefly-iii.org</a>. This can help fix the bug you just encountered.',
'error_github_html' => 'If you prefer, you can also open a new issue on <a href="https://github.com/firefly-iii/firefly-iii/issues">GitHub</a>.', 'error_github_html' => 'If you prefer, you can also open a new issue on <a href="https://github.com/firefly-iii/firefly-iii/issues">GitHub</a>.',
'error_github_text' => 'If you prefer, you can also open a new issue on https://github.com/firefly-iii/firefly-iii/issues.', 'error_github_text' => 'If you prefer, you can also open a new issue on https://github.com/firefly-iii/firefly-iii/issues.',
'error_stacktrace_below' => 'The full stacktrace is below:', 'error_stacktrace_below' => 'The full stacktrace is below:',
'error_headers' => 'The following headers may also be relevant:', 'error_headers' => 'The following headers may also be relevant:',
'error_post' => 'This was submitted by the user:', 'error_post' => 'This was submitted by the user:',
// Ignore this comment // Ignore this comment
// report new journals // report new journals
'new_journals_subject' => 'Firefly III has created a new transaction|Firefly III has created :count new transactions', 'new_journals_subject' => 'Firefly III has created a new transaction|Firefly III has created :count new transactions',
'new_journals_header' => 'Firefly III has created a transaction for you. You can find it in your Firefly III installation:|Firefly III has created :count transactions for you. You can find them in your Firefly III installation:', 'new_journals_header' => 'Firefly III has created a transaction for you. You can find it in your Firefly III installation:|Firefly III has created :count transactions for you. You can find them in your Firefly III installation:',
// bill warning // bill warning
'bill_warning_subject_end_date' => 'Your bill ":name" is due to end in :diff days', 'bill_warning_subject_end_date' => 'Your bill ":name" is due to end in :diff days',
'bill_warning_subject_now_end_date' => 'Your bill ":name" is due to end TODAY', 'bill_warning_subject_now_end_date' => 'Your bill ":name" is due to end TODAY',
'bill_warning_subject_extension_date' => 'Your bill ":name" is due to be extended or cancelled in :diff days', 'bill_warning_subject_extension_date' => 'Your bill ":name" is due to be extended or cancelled in :diff days',
'bill_warning_subject_now_extension_date' => 'Your bill ":name" is due to be extended or cancelled TODAY', 'bill_warning_subject_now_extension_date' => 'Your bill ":name" is due to be extended or cancelled TODAY',
'bill_warning_end_date' => 'Your bill **":name"** is due to end on :date. This moment will pass in about **:diff days**.', 'bill_warning_end_date' => 'Your bill **":name"** is due to end on :date. This moment will pass in about **:diff days**.',
'bill_warning_extension_date' => 'Your bill **":name"** is due to be extended or cancelled on :date. This moment will pass in about **:diff days**.', 'bill_warning_extension_date' => 'Your bill **":name"** is due to be extended or cancelled on :date. This moment will pass in about **:diff days**.',
'bill_warning_end_date_zero' => 'Your bill **":name"** is due to end on :date. This moment will pass **TODAY!**', 'bill_warning_end_date_zero' => 'Your bill **":name"** is due to end on :date. This moment will pass **TODAY!**',
'bill_warning_extension_date_zero' => 'Your bill **":name"** is due to be extended or cancelled on :date. This moment will pass **TODAY!**', 'bill_warning_extension_date_zero' => 'Your bill **":name"** is due to be extended or cancelled on :date. This moment will pass **TODAY!**',
'bill_warning_please_action' => 'Please take the appropriate action.', 'bill_warning_please_action' => 'Please take the appropriate action.',
// user has enabled MFA // user has enabled MFA
'enabled_mfa_subject' => 'You have enabled multi-factor authentication', 'enabled_mfa_subject' => 'You have enabled multi-factor authentication',
'enabled_mfa_slack' => 'You (:email) have enabled multi-factor authentication. Is this not correct? Check your settings!', 'enabled_mfa_slack' => 'You (:email) have enabled multi-factor authentication. Is this not correct? Check your settings!',
'have_enabled_mfa' => 'You have enabled multi-factor authentication on your Firefly III account ":email". This means that you will need to use an authenticator app to log in from now on.', 'have_enabled_mfa' => 'You have enabled multi-factor authentication on your Firefly III account ":email". This means that you will need to use an authenticator app to log in from now on.',
'enabled_mfa_warning' => 'If you did not enable this, please contact your administrator immediately or check out the Firefly III documentation.', 'enabled_mfa_warning' => 'If you did not enable this, please contact your administrator immediately or check out the Firefly III documentation.',
'disabled_mfa_subject' => 'You have disabled multi-factor authentication!', 'disabled_mfa_subject' => 'You have disabled multi-factor authentication!',
'disabled_mfa_slack' => 'You (:email) have disabled multi-factor authentication. Is this not correct? Check your settings!', 'disabled_mfa_slack' => 'You (:email) have disabled multi-factor authentication. Is this not correct? Check your settings!',
'have_disabled_mfa' => 'You have disabled multi-factor authentication on your Firefly III account ":email".', 'have_disabled_mfa' => 'You have disabled multi-factor authentication on your Firefly III account ":email".',
'disabled_mfa_warning' => 'If you did not disable this, please contact your administrator immediately or check out the Firefly III documentation.', 'disabled_mfa_warning' => 'If you did not disable this, please contact your administrator immediately or check out the Firefly III documentation.',
'new_backup_codes_subject' => 'You have generated new back-up codes', 'new_backup_codes_subject' => 'You have generated new back-up codes',
'new_backup_codes_slack' => 'You (:email) have generated new back-up codes. These can be used to login to Firefly III. Is this not correct? Check your settings!', 'new_backup_codes_slack' => 'You (:email) have generated new back-up codes. These can be used to login to Firefly III. Is this not correct? Check your settings!',
'new_backup_codes_intro' => 'You (:email) have generated new back-up codes. These can be used to login to Firefly III if you lose access to your authenticator app.', 'new_backup_codes_intro' => 'You (:email) have generated new back-up codes. These can be used to login to Firefly III if you lose access to your authenticator app.',
'new_backup_codes_warning' => 'Please store these codes in a safe place. If you lose them, you will not be able to log in to Firefly III. If you did not do this, please contact your administrator immediately or check out the Firefly III documentation.', 'new_backup_codes_warning' => 'Please store these codes in a safe place. If you lose them, you will not be able to log in to Firefly III. If you did not do this, please contact your administrator immediately or check out the Firefly III documentation.',
'used_backup_code_subject' => 'You have used a back-up code to login', 'used_backup_code_subject' => 'You have used a back-up code to login',
'used_backup_code_slack' => 'You (:email) have used a back-up code to login', 'used_backup_code_slack' => 'You (:email) have used a back-up code to login',
'used_backup_code_intro' => 'You (:email) have used a back-up code to login to Firefly III. You now have one less back-up code to login with. Please remove it from your list.', 'used_backup_code_intro' => 'You (:email) have used a back-up code to login to Firefly III. You now have one less back-up code to login with. Please remove it from your list.',
'used_backup_code_warning' => 'If you did not do this, please contact your administrator immediately or check out the Firefly III documentation.', 'used_backup_code_warning' => 'If you did not do this, please contact your administrator immediately or check out the Firefly III documentation.',
// few left: // few left:
'mfa_few_backups_left_subject' => 'You have only :count backup code(s) left!', 'mfa_few_backups_left_subject' => 'You have only :count backup code(s) left!',
'mfa_few_backups_left_slack' => 'You (:email) have only :count backup code(s) left!', 'mfa_few_backups_left_slack' => 'You (:email) have only :count backup code(s) left!',
'few_backup_codes_intro' => 'You (:email) have used most of your backup codes, and now have only :count left. Please generate new ones as soon as possible.', 'few_backup_codes_intro' => 'You (:email) have used most of your backup codes, and now have only :count left. Please generate new ones as soon as possible.',
'few_backup_codes_warning' => 'Without backup codes, you cannot recover your MFA login if you lose access to your code generator.', 'few_backup_codes_warning' => 'Without backup codes, you cannot recover your MFA login if you lose access to your code generator.',
// NO left: // NO left:
'mfa_no_backups_left_subject' => 'You have NO backup codes left!', 'mfa_no_backups_left_subject' => 'You have NO backup codes left!',
'mfa_no_backups_left_slack' => 'You (:email) NO backup codes left!', 'mfa_no_backups_left_slack' => 'You (:email) NO backup codes left!',
'no_backup_codes_intro' => 'You (:email) have used ALL of your backup codes. Please generate new ones as soon as possible.', 'no_backup_codes_intro' => 'You (:email) have used ALL of your backup codes. Please generate new ones as soon as possible.',
'no_backup_codes_warning' => 'Without backup codes, you cannot recover your MFA login if you lose access to your code generator.', 'no_backup_codes_warning' => 'Without backup codes, you cannot recover your MFA login if you lose access to your code generator.',
// many failed MFA attempts // many failed MFA attempts
'mfa_many_failed_subject' => 'You have tried and failed to use multi-factor authentication :count times now!', 'mfa_many_failed_subject' => 'You have tried and failed to use multi-factor authentication :count times now!',
'mfa_many_failed_slack' => 'You (:email) have tried and failed to use multi-factor authentication :count times now. Is this not correct? Check your settings!', 'mfa_many_failed_slack' => 'You (:email) have tried and failed to use multi-factor authentication :count times now. Is this not correct? Check your settings!',
'mfa_many_failed_attempts_intro' => 'You (:email) have tried :count times to use a multi-factor authentication code, but these login attempts have failed. Are you sure you are using the right MFA code? Are you sure the time on the server is correct?', 'mfa_many_failed_attempts_intro' => 'You (:email) have tried :count times to use a multi-factor authentication code, but these login attempts have failed. Are you sure you are using the right MFA code? Are you sure the time on the server is correct?',
'mfa_many_failed_attempts_warning' => 'If you did not do this, please contact your administrator immediately or check out the Firefly III documentation.', 'mfa_many_failed_attempts_warning' => 'If you did not do this, please contact your administrator immediately or check out the Firefly III documentation.',
]; ];
// Ignore this comment // Ignore this comment

File diff suppressed because it is too large Load Diff

View File

@ -25,162 +25,162 @@
declare(strict_types=1); declare(strict_types=1);
return [ return [
'filter_must_be_in' => 'Filter ":filter" must be one of: :values', 'filter_must_be_in' => 'Filter ":filter" must be one of: :values',
'filter_not_string' => 'Filter ":filter" is expected to be a string of text', 'filter_not_string' => 'Filter ":filter" is expected to be a string of text',
'bad_api_filter' => 'This API endpoint does not support ":filter" as a filter.', 'bad_api_filter' => 'This API endpoint does not support ":filter" as a filter.',
'nog_logged_in' => 'You are not logged in.', 'nog_logged_in' => 'You are not logged in.',
'bad_type_source' => 'Firefly III can\'t determine the transaction type based on this source account.', 'bad_type_source' => 'Firefly III can\'t determine the transaction type based on this source account.',
'bad_type_destination' => 'Firefly III can\'t determine the transaction type based on this destination account.', 'bad_type_destination' => 'Firefly III can\'t determine the transaction type based on this destination account.',
'missing_where' => 'Array is missing "where"-clause', 'missing_where' => 'Array is missing "where"-clause',
'missing_update' => 'Array is missing "update"-clause', 'missing_update' => 'Array is missing "update"-clause',
'invalid_where_key' => 'JSON contains an invalid key for the "where"-clause', 'invalid_where_key' => 'JSON contains an invalid key for the "where"-clause',
'invalid_update_key' => 'JSON contains an invalid key for the "update"-clause', 'invalid_update_key' => 'JSON contains an invalid key for the "update"-clause',
'invalid_query_data' => 'There is invalid data in the %s:%s field of your query.', 'invalid_query_data' => 'There is invalid data in the %s:%s field of your query.',
'invalid_query_account_type' => 'Your query contains accounts of different types, which is not allowed.', 'invalid_query_account_type' => 'Your query contains accounts of different types, which is not allowed.',
'invalid_query_currency' => 'Your query contains accounts that have different currency settings, which is not allowed.', 'invalid_query_currency' => 'Your query contains accounts that have different currency settings, which is not allowed.',
'iban' => 'This is not a valid IBAN.', 'iban' => 'This is not a valid IBAN.',
'zero_or_more' => 'The value cannot be negative.', 'zero_or_more' => 'The value cannot be negative.',
'more_than_zero' => 'The value must be more than zero.', 'more_than_zero' => 'The value must be more than zero.',
'more_than_zero_correct' => 'The value must be zero or more.', 'more_than_zero_correct' => 'The value must be zero or more.',
'no_asset_account' => 'This is not an asset account.', 'no_asset_account' => 'This is not an asset account.',
'date_or_time' => 'The value must be a valid date or time value (ISO 8601).', 'date_or_time' => 'The value must be a valid date or time value (ISO 8601).',
'source_equals_destination' => 'The source account equals the destination account.', 'source_equals_destination' => 'The source account equals the destination account.',
'unique_account_number_for_user' => 'It looks like this account number is already in use.', 'unique_account_number_for_user' => 'It looks like this account number is already in use.',
'unique_iban_for_user' => 'It looks like this IBAN is already in use.', 'unique_iban_for_user' => 'It looks like this IBAN is already in use.',
'reconciled_forbidden_field' => 'This transaction is already reconciled, you cannot change the ":field"', 'reconciled_forbidden_field' => 'This transaction is already reconciled, you cannot change the ":field"',
'deleted_user' => 'Due to security constraints, you cannot register using this email address.', 'deleted_user' => 'Due to security constraints, you cannot register using this email address.',
'rule_trigger_value' => 'This value is invalid for the selected trigger.', 'rule_trigger_value' => 'This value is invalid for the selected trigger.',
'rule_action_expression' => 'Invalid expression. :error', 'rule_action_expression' => 'Invalid expression. :error',
'rule_action_value' => 'This value is invalid for the selected action.', 'rule_action_value' => 'This value is invalid for the selected action.',
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.', 'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
'file_attached' => 'Successfully uploaded file ":name".', 'file_attached' => 'Successfully uploaded file ":name".',
'file_zero' => 'The file is zero bytes in size.', 'file_zero' => 'The file is zero bytes in size.',
'must_exist' => 'The ID in field :attribute does not exist in the database.', 'must_exist' => 'The ID in field :attribute does not exist in the database.',
'all_accounts_equal' => 'All accounts in this field must be equal.', 'all_accounts_equal' => 'All accounts in this field must be equal.',
'group_title_mandatory' => 'A group title is mandatory when there is more than one transaction.', 'group_title_mandatory' => 'A group title is mandatory when there is more than one transaction.',
'transaction_types_equal' => 'All splits must be of the same type.', 'transaction_types_equal' => 'All splits must be of the same type.',
'invalid_transaction_type' => 'Invalid transaction type.', 'invalid_transaction_type' => 'Invalid transaction type.',
'invalid_selection' => 'Your selection is invalid.', 'invalid_selection' => 'Your selection is invalid.',
'belongs_user' => 'This value is linked to an object that does not seem to exist.', 'belongs_user' => 'This value is linked to an object that does not seem to exist.',
'belongs_user_or_user_group' => 'This value is linked to an object that does not seem to exist in your current financial administration.', 'belongs_user_or_user_group' => 'This value is linked to an object that does not seem to exist in your current financial administration.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'The user has no access to this user group.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'at_least_one_transaction' => 'Need at least one transaction.', 'at_least_one_transaction' => 'Need at least one transaction.',
'recurring_transaction_id' => 'Need at least one transaction.', 'recurring_transaction_id' => 'Need at least one transaction.',
'need_id_to_match' => 'You need to submit this entry with an ID for the API to be able to match it.', 'need_id_to_match' => 'You need to submit this entry with an ID for the API to be able to match it.',
'too_many_unmatched' => 'Too many submitted transactions cannot be matched to their respective database entries. Make sure existing entries have a valid ID.', 'too_many_unmatched' => 'Too many submitted transactions cannot be matched to their respective database entries. Make sure existing entries have a valid ID.',
'id_does_not_match' => 'Submitted ID #:id does not match expected ID. Make sure it matches or omit the field.', 'id_does_not_match' => 'Submitted ID #:id does not match expected ID. Make sure it matches or omit the field.',
'at_least_one_repetition' => 'Need at least one repetition.', 'at_least_one_repetition' => 'Need at least one repetition.',
'require_repeat_until' => 'Require either a number of repetitions, or an end date (repeat_until). Not both.', 'require_repeat_until' => 'Require either a number of repetitions, or an end date (repeat_until). Not both.',
'require_currency_info' => 'The content of this field is invalid without currency information.', 'require_currency_info' => 'The content of this field is invalid without currency information.',
'not_transfer_account' => 'This account is not an account that can be used for transfers.', 'not_transfer_account' => 'This account is not an account that can be used for transfers.',
'require_currency_amount' => 'The content of this field is invalid without foreign amount information.', 'require_currency_amount' => 'The content of this field is invalid without foreign amount information.',
'require_foreign_currency' => 'This field requires a number', 'require_foreign_currency' => 'This field requires a number',
'require_foreign_dest' => 'This field value must match the currency of the destination account.', 'require_foreign_dest' => 'This field value must match the currency of the destination account.',
'require_foreign_src' => 'This field value must match the currency of the source account.', 'require_foreign_src' => 'This field value must match the currency of the source account.',
'equal_description' => 'Transaction description should not equal global description.', 'equal_description' => 'Transaction description should not equal global description.',
'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.', 'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.',
'file_too_large' => 'File ":name" is too large.', 'file_too_large' => 'File ":name" is too large.',
'belongs_to_user' => 'The value of :attribute is unknown.', 'belongs_to_user' => 'The value of :attribute is unknown.',
'accepted' => 'The :attribute must be accepted.', 'accepted' => 'The :attribute must be accepted.',
'bic' => 'This is not a valid BIC.', 'bic' => 'This is not a valid BIC.',
'at_least_one_trigger' => 'Rule must have at least one trigger.', 'at_least_one_trigger' => 'Rule must have at least one trigger.',
'at_least_one_active_trigger' => 'Rule must have at least one active trigger.', 'at_least_one_active_trigger' => 'Rule must have at least one active trigger.',
'at_least_one_action' => 'Rule must have at least one action.', 'at_least_one_action' => 'Rule must have at least one action.',
'at_least_one_active_action' => 'Rule must have at least one active action.', 'at_least_one_active_action' => 'Rule must have at least one active action.',
'base64' => 'This is not valid base64 encoded data.', 'base64' => 'This is not valid base64 encoded data.',
'model_id_invalid' => 'The given ID seems invalid for this model.', 'model_id_invalid' => 'The given ID seems invalid for this model.',
'less' => ':attribute must be less than 10,000,000', 'less' => ':attribute must be less than 10,000,000',
'active_url' => 'The :attribute is not a valid URL.', 'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.', 'after' => 'The :attribute must be a date after :date.',
'date_after' => 'The start date must be before the end date.', 'date_after' => 'The start date must be before the end date.',
'alpha' => 'The :attribute may only contain letters.', 'alpha' => 'The :attribute may only contain letters.',
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
'alpha_num' => 'The :attribute may only contain letters and numbers.', 'alpha_num' => 'The :attribute may only contain letters and numbers.',
'array' => 'The :attribute must be an array.', 'array' => 'The :attribute must be an array.',
'unique_for_user' => 'There already is an entry with this :attribute.', 'unique_for_user' => 'There already is an entry with this :attribute.',
'before' => 'The :attribute must be a date before :date.', 'before' => 'The :attribute must be a date before :date.',
'unique_object_for_user' => 'This name is already in use.', 'unique_object_for_user' => 'This name is already in use.',
'unique_account_for_user' => 'This account name is already in use.', 'unique_account_for_user' => 'This account name is already in use.',
// Ignore this comment // Ignore this comment
'between.numeric' => 'The :attribute must be between :min and :max.', 'between.numeric' => 'The :attribute must be between :min and :max.',
'between.file' => 'The :attribute must be between :min and :max kilobytes.', 'between.file' => 'The :attribute must be between :min and :max kilobytes.',
'between.string' => 'The :attribute must be between :min and :max characters.', 'between.string' => 'The :attribute must be between :min and :max characters.',
'between.array' => 'The :attribute must have between :min and :max items.', 'between.array' => 'The :attribute must have between :min and :max items.',
'boolean' => 'The :attribute field must be true or false.', 'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.', 'confirmed' => 'The :attribute confirmation does not match.',
'date' => 'The :attribute is not a valid date.', 'date' => 'The :attribute is not a valid date.',
'date_format' => 'The :attribute does not match the format :format.', 'date_format' => 'The :attribute does not match the format :format.',
'different' => 'The :attribute and :other must be different.', 'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.', 'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.', 'digits_between' => 'The :attribute must be between :min and :max digits.',
'email' => 'The :attribute must be a valid email address.', 'email' => 'The :attribute must be a valid email address.',
'filled' => 'The :attribute field is required.', 'filled' => 'The :attribute field is required.',
'exists' => 'The selected :attribute is invalid.', 'exists' => 'The selected :attribute is invalid.',
'image' => 'The :attribute must be an image.', 'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.', 'in' => 'The selected :attribute is invalid.',
'integer' => 'The :attribute must be an integer.', 'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.', 'ip' => 'The :attribute must be a valid IP address.',
'json' => 'The :attribute must be a valid JSON string.', 'json' => 'The :attribute must be a valid JSON string.',
'max.numeric' => 'The :attribute may not be greater than :max.', 'max.numeric' => 'The :attribute may not be greater than :max.',
'max.file' => 'The :attribute may not be greater than :max kilobytes.', 'max.file' => 'The :attribute may not be greater than :max kilobytes.',
'max.string' => 'The :attribute may not be greater than :max characters.', 'max.string' => 'The :attribute may not be greater than :max characters.',
'max.array' => 'The :attribute may not have more than :max items.', 'max.array' => 'The :attribute may not have more than :max items.',
'mimes' => 'The :attribute must be a file of type: :values.', 'mimes' => 'The :attribute must be a file of type: :values.',
'min.numeric' => 'The :attribute must be at least :min.', 'min.numeric' => 'The :attribute must be at least :min.',
'lte.numeric' => 'The :attribute must be less than or equal :value.', 'lte.numeric' => 'The :attribute must be less than or equal :value.',
'min.file' => 'The :attribute must be at least :min kilobytes.', 'min.file' => 'The :attribute must be at least :min kilobytes.',
'min.string' => 'The :attribute must be at least :min characters.', 'min.string' => 'The :attribute must be at least :min characters.',
'min.array' => 'The :attribute must have at least :min items.', 'min.array' => 'The :attribute must have at least :min items.',
'not_in' => 'The selected :attribute is invalid.', 'not_in' => 'The selected :attribute is invalid.',
'numeric' => 'The :attribute must be a number.', 'numeric' => 'The :attribute must be a number.',
'scientific_notation' => 'The :attribute cannot use the scientific notation.', 'scientific_notation' => 'The :attribute cannot use the scientific notation.',
'numeric_native' => 'The native amount must be a number.', 'numeric_native' => 'The native amount must be a number.',
'numeric_destination' => 'The destination amount must be a number.', 'numeric_destination' => 'The destination amount must be a number.',
'numeric_source' => 'The source amount must be a number.', 'numeric_source' => 'The source amount must be a number.',
'regex' => 'The :attribute format is invalid.', 'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.', 'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.', 'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.', 'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.', 'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values is present.', 'required_with_all' => 'The :attribute field is required when :values is present.',
'required_without' => 'The :attribute field is required when :values is not present.', 'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.', 'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.', 'same' => 'The :attribute and :other must match.',
'size.numeric' => 'The :attribute must be :size.', 'size.numeric' => 'The :attribute must be :size.',
'amount_min_over_max' => 'The minimum amount cannot be larger than the maximum amount.', 'amount_min_over_max' => 'The minimum amount cannot be larger than the maximum amount.',
'size.file' => 'The :attribute must be :size kilobytes.', 'size.file' => 'The :attribute must be :size kilobytes.',
'size.string' => 'The :attribute must be :size characters.', 'size.string' => 'The :attribute must be :size characters.',
'size.array' => 'The :attribute must contain :size items.', 'size.array' => 'The :attribute must contain :size items.',
'unique' => 'The :attribute has already been taken.', 'unique' => 'The :attribute has already been taken.',
'string' => 'The :attribute must be a string.', 'string' => 'The :attribute must be a string.',
'url' => 'The :attribute format is invalid.', 'url' => 'The :attribute format is invalid.',
'timezone' => 'The :attribute must be a valid zone.', 'timezone' => 'The :attribute must be a valid zone.',
'2fa_code' => 'The :attribute field is invalid.', '2fa_code' => 'The :attribute field is invalid.',
'dimensions' => 'The :attribute has invalid image dimensions.', 'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.', 'distinct' => 'The :attribute field has a duplicate value.',
'file' => 'The :attribute must be a file.', 'file' => 'The :attribute must be a file.',
'in_array' => 'The :attribute field does not exist in :other.', 'in_array' => 'The :attribute field does not exist in :other.',
'present' => 'The :attribute field must be present.', 'present' => 'The :attribute field must be present.',
'amount_zero' => 'The total amount cannot be zero.', 'amount_zero' => 'The total amount cannot be zero.',
'current_target_amount' => 'The current amount must be less than the target amount.', 'current_target_amount' => 'The current amount must be less than the target amount.',
'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.', 'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.',
'unique_object_group' => 'The group name must be unique', 'unique_object_group' => 'The group name must be unique',
'starts_with' => 'The value must start with :values.', 'starts_with' => 'The value must start with :values.',
'unique_webhook' => 'You already have a webhook with this combination of URL, trigger, response and delivery.', 'unique_webhook' => 'You already have a webhook with this combination of URL, trigger, response and delivery.',
'unique_existing_webhook' => 'You already have another webhook with this combination of URL, trigger, response and delivery.', 'unique_existing_webhook' => 'You already have another webhook with this combination of URL, trigger, response and delivery.',
'same_account_type' => 'Both accounts must be of the same account type', 'same_account_type' => 'Both accounts must be of the same account type',
'same_account_currency' => 'Both accounts must have the same currency setting', 'same_account_currency' => 'Both accounts must have the same currency setting',
// Ignore this comment // Ignore this comment
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password', 'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.', 'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.',
'valid_recurrence_rep_moment' => 'Invalid repetition moment for this type of repetition.', 'valid_recurrence_rep_moment' => 'Invalid repetition moment for this type of repetition.',
'invalid_account_info' => 'Invalid account information.', 'invalid_account_info' => 'Invalid account information.',
'attributes' => [ 'attributes' => [
'email' => 'email address', 'email' => 'email address',
'description' => 'description', 'description' => 'description',
'amount' => 'amount', 'amount' => 'amount',
@ -219,60 +219,60 @@ return [
], ],
// validation of accounts: // validation of accounts:
'withdrawal_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.', 'withdrawal_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
'withdrawal_source_bad_data' => '[a] Could not find a valid source account when searching for ID ":id" or name ":name".', 'withdrawal_source_bad_data' => '[a] Could not find a valid source account when searching for ID ":id" or name ":name".',
'withdrawal_dest_need_data' => '[a] Need to get a valid destination account ID and/or valid destination account name to continue.', 'withdrawal_dest_need_data' => '[a] Need to get a valid destination account ID and/or valid destination account name to continue.',
'withdrawal_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".', 'withdrawal_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
'withdrawal_dest_iban_exists' => 'This destination account IBAN is already in use by an asset account or a liability and cannot be used as a withdrawal destination.', 'withdrawal_dest_iban_exists' => 'This destination account IBAN is already in use by an asset account or a liability and cannot be used as a withdrawal destination.',
'deposit_src_iban_exists' => 'This source account IBAN is already in use by an asset account or a liability and cannot be used as a deposit source.', 'deposit_src_iban_exists' => 'This source account IBAN is already in use by an asset account or a liability and cannot be used as a deposit source.',
'reconciliation_source_bad_data' => 'Could not find a valid reconciliation account when searching for ID ":id" or name ":name".', 'reconciliation_source_bad_data' => 'Could not find a valid reconciliation account when searching for ID ":id" or name ":name".',
'generic_source_bad_data' => '[e] Could not find a valid source account when searching for ID ":id" or name ":name".', 'generic_source_bad_data' => '[e] Could not find a valid source account when searching for ID ":id" or name ":name".',
'deposit_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.', 'deposit_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
'deposit_source_bad_data' => '[b] Could not find a valid source account when searching for ID ":id" or name ":name".', 'deposit_source_bad_data' => '[b] Could not find a valid source account when searching for ID ":id" or name ":name".',
'deposit_dest_need_data' => '[b] Need to get a valid destination account ID and/or valid destination account name to continue.', 'deposit_dest_need_data' => '[b] Need to get a valid destination account ID and/or valid destination account name to continue.',
'deposit_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".', 'deposit_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
'deposit_dest_wrong_type' => 'The submitted destination account is not of the right type.', 'deposit_dest_wrong_type' => 'The submitted destination account is not of the right type.',
// Ignore this comment // Ignore this comment
'transfer_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.', 'transfer_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
'transfer_source_bad_data' => '[c] Could not find a valid source account when searching for ID ":id" or name ":name".', 'transfer_source_bad_data' => '[c] Could not find a valid source account when searching for ID ":id" or name ":name".',
'transfer_dest_need_data' => '[c] Need to get a valid destination account ID and/or valid destination account name to continue.', 'transfer_dest_need_data' => '[c] Need to get a valid destination account ID and/or valid destination account name to continue.',
'transfer_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".', 'transfer_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
'need_id_in_edit' => 'Each split must have transaction_journal_id (either valid ID or 0).', 'need_id_in_edit' => 'Each split must have transaction_journal_id (either valid ID or 0).',
'ob_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.', 'ob_source_need_data' => 'Need to get a valid source account ID and/or valid source account name to continue.',
'lc_source_need_data' => 'Need to get a valid source account ID to continue.', 'lc_source_need_data' => 'Need to get a valid source account ID to continue.',
'ob_dest_need_data' => '[d] Need to get a valid destination account ID and/or valid destination account name to continue.', 'ob_dest_need_data' => '[d] Need to get a valid destination account ID and/or valid destination account name to continue.',
'ob_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".', 'ob_dest_bad_data' => 'Could not find a valid destination account when searching for ID ":id" or name ":name".',
'reconciliation_either_account' => 'To submit a reconciliation, you must submit either a source or a destination account. Not both, not neither.', 'reconciliation_either_account' => 'To submit a reconciliation, you must submit either a source or a destination account. Not both, not neither.',
'generic_invalid_source' => 'You can\'t use this account as the source account.', 'generic_invalid_source' => 'You can\'t use this account as the source account.',
'generic_invalid_destination' => 'You can\'t use this account as the destination account.', 'generic_invalid_destination' => 'You can\'t use this account as the destination account.',
'generic_no_source' => 'You must submit source account information or submit a transaction journal ID.', 'generic_no_source' => 'You must submit source account information or submit a transaction journal ID.',
'generic_no_destination' => 'You must submit destination account information or submit a transaction journal ID.', 'generic_no_destination' => 'You must submit destination account information or submit a transaction journal ID.',
'gte.numeric' => 'The :attribute must be greater than or equal to :value.', 'gte.numeric' => 'The :attribute must be greater than or equal to :value.',
'gt.numeric' => 'The :attribute must be greater than :value.', 'gt.numeric' => 'The :attribute must be greater than :value.',
'gte.file' => 'The :attribute must be greater than or equal to :value kilobytes.', 'gte.file' => 'The :attribute must be greater than or equal to :value kilobytes.',
'gte.string' => 'The :attribute must be greater than or equal to :value characters.', 'gte.string' => 'The :attribute must be greater than or equal to :value characters.',
'gte.array' => 'The :attribute must have :value items or more.', 'gte.array' => 'The :attribute must have :value items or more.',
'amount_required_for_auto_budget' => 'The amount is required.', 'amount_required_for_auto_budget' => 'The amount is required.',
'auto_budget_amount_positive' => 'The amount must be more than zero.', 'auto_budget_amount_positive' => 'The amount must be more than zero.',
'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.', 'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.',
// no access to administration: // no access to administration:
'no_auth_user_group' => 'You have to be logged in to access this administration.', 'no_auth_user_group' => 'You have to be logged in to access this administration.',
'no_access_user_group' => 'You do not have the correct access rights for this administration.', 'no_access_user_group' => 'You do not have the correct access rights for this administration.',
'administration_owner_rename' => 'You can\'t rename your standard administration.', 'administration_owner_rename' => 'You can\'t rename your standard administration.',
'existing_mfa_code' => 'Please enter a valid code', 'existing_mfa_code' => 'Please enter a valid code',
]; ];
// Ignore this comment // Ignore this comment

View File

@ -836,15 +836,15 @@ Route::group(
Route::get('index', ['uses' => 'Profile\MfaController@index', 'as' => 'index']); Route::get('index', ['uses' => 'Profile\MfaController@index', 'as' => 'index']);
// enable MFA (goes to code page) // enable MFA (goes to code page)
Route::get('enableMFA', ['uses' => 'Profile\MfaController@enableMFA', 'as' => 'enableMFA']); Route::get('enableMFA', ['uses' => 'Profile\MfaController@enableMFA', 'as' => 'enableMFA']);
Route::post('enableMFA', ['uses' => 'Profile\MfaController@enableMFAPost', 'as' => 'enableMFA.post']); Route::post('enableMFA', ['uses' => 'Profile\MfaController@enableMFAPost', 'as' => 'enableMFA.post']);
// show backup codes // show backup codes
Route::get('backup-codes', ['uses' => 'Profile\MfaController@backupCodes', 'as' => 'backup-codes']); Route::get('backup-codes', ['uses' => 'Profile\MfaController@backupCodes', 'as' => 'backup-codes']);
Route::post('backup-codes', ['uses' => 'Profile\MfaController@backupCodesPost', 'as' => 'backup-codes.post']); Route::post('backup-codes', ['uses' => 'Profile\MfaController@backupCodesPost', 'as' => 'backup-codes.post']);
// enable MFA // enable MFA
// Route::get('2fa/code', ['uses' => 'Profile\MfaController@code', 'as' => 'code']); // Route::get('2fa/code', ['uses' => 'Profile\MfaController@code', 'as' => 'code']);
// disable MFA // disable MFA
Route::get('/disableMFA', ['uses' => 'Profile\MfaController@disableMFA', 'as' => 'disableMFA']); Route::get('/disableMFA', ['uses' => 'Profile\MfaController@disableMFA', 'as' => 'disableMFA']);
@ -853,7 +853,7 @@ Route::group(
} }
); );
// Recurring Transactions Controller. // Recurring Transactions Controller.
Route::group( Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'recurring', 'as' => 'recurring.'], ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'recurring', 'as' => 'recurring.'],