mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-29 18:20:01 +00:00
Basic check for user's administration ID
This commit is contained in:
@@ -25,11 +25,14 @@ namespace FireflyIII\Http\Requests;
|
|||||||
|
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Location;
|
use FireflyIII\Models\Location;
|
||||||
|
use FireflyIII\Models\UserRole;
|
||||||
use FireflyIII\Rules\UniqueIban;
|
use FireflyIII\Rules\UniqueIban;
|
||||||
use FireflyIII\Support\Request\AppendsLocationData;
|
use FireflyIII\Support\Request\AppendsLocationData;
|
||||||
use FireflyIII\Support\Request\ChecksLogin;
|
use FireflyIII\Support\Request\ChecksLogin;
|
||||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||||
|
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AccountFormRequest.
|
* Class AccountFormRequest.
|
||||||
@@ -39,6 +42,7 @@ class AccountFormRequest extends FormRequest
|
|||||||
use ConvertsDataTypes;
|
use ConvertsDataTypes;
|
||||||
use AppendsLocationData;
|
use AppendsLocationData;
|
||||||
use ChecksLogin;
|
use ChecksLogin;
|
||||||
|
use ValidatesAdministrationAccess;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all data.
|
* Get all data.
|
||||||
@@ -48,6 +52,7 @@ class AccountFormRequest extends FormRequest
|
|||||||
public function getAccountData(): array
|
public function getAccountData(): array
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
'administration_id' => $this->convertInteger('administration_id'),
|
||||||
'name' => $this->convertString('name'),
|
'name' => $this->convertString('name'),
|
||||||
'active' => $this->boolean('active'),
|
'active' => $this->boolean('active'),
|
||||||
'account_type_name' => $this->convertString('objectType'),
|
'account_type_name' => $this->convertString('objectType'),
|
||||||
@@ -67,6 +72,9 @@ class AccountFormRequest extends FormRequest
|
|||||||
'include_net_worth' => '1',
|
'include_net_worth' => '1',
|
||||||
'liability_direction' => $this->convertString('liability_direction'),
|
'liability_direction' => $this->convertString('liability_direction'),
|
||||||
];
|
];
|
||||||
|
if (0 === $data['administration_id']) {
|
||||||
|
$data['administration_id'] = auth()->user()->getAdministrationId();
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->appendLocationData($data, 'location');
|
$data = $this->appendLocationData($data, 'location');
|
||||||
if (false === $this->boolean('include_net_worth')) {
|
if (false === $this->boolean('include_net_worth')) {
|
||||||
@@ -101,6 +109,7 @@ class AccountFormRequest extends FormRequest
|
|||||||
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||||
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
||||||
$rules = [
|
$rules = [
|
||||||
|
'administration_id' => 'min:1|max:16777216|numeric',
|
||||||
'name' => 'required|min:1|uniqueAccountForUser',
|
'name' => 'required|min:1|uniqueAccountForUser',
|
||||||
'opening_balance' => 'numeric|nullable|max:1000000000',
|
'opening_balance' => 'numeric|nullable|max:1000000000',
|
||||||
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
||||||
@@ -130,4 +139,20 @@ class AccountFormRequest extends FormRequest
|
|||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Configure the validator instance with special rules for after the basic validation rules.
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function withValidator(Validator $validator): void
|
||||||
|
{
|
||||||
|
$validator->after(
|
||||||
|
function (Validator $validator) {
|
||||||
|
// validate if the account can access this administration
|
||||||
|
$this->validateAdministration($validator, [UserRole::CHANGE_TRANSACTIONS]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@ use Carbon\Carbon;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use FireflyIII\Models\GroupMembership;
|
||||||
use FireflyIII\Models\InvitedUser;
|
use FireflyIII\Models\InvitedUser;
|
||||||
use FireflyIII\Models\Role;
|
use FireflyIII\Models\Role;
|
||||||
use FireflyIII\Models\UserGroup;
|
use FireflyIII\Models\UserGroup;
|
||||||
@@ -466,4 +467,25 @@ class UserRepository implements UserRepositoryInterface
|
|||||||
$invitee = InvitedUser::where('invite_code', $code)->where('expires', '>', $now->format('Y-m-d H:i:s'))->where('redeemed', 0)->first();
|
$invitee = InvitedUser::where('invite_code', $code)->where('expires', '>', $now->format('Y-m-d H:i:s'))->where('redeemed', 0)->first();
|
||||||
return null !== $invitee;
|
return null !== $invitee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function getRolesInGroup(User $user, int $groupId): array
|
||||||
|
{
|
||||||
|
/** @var UserGroup $group */
|
||||||
|
$group = UserGroup::find($groupId);
|
||||||
|
if (null === $group) {
|
||||||
|
throw new FireflyException(sprintf('Could not find group #%d', $groupId));
|
||||||
|
}
|
||||||
|
$memberships = $group->groupMemberships()->where('user_id', $user->id)->get();
|
||||||
|
$roles = [];
|
||||||
|
/** @var GroupMembership $membership */
|
||||||
|
foreach ($memberships as $membership) {
|
||||||
|
$role = $membership->userRole;
|
||||||
|
$roles[] = $role->title;
|
||||||
|
}
|
||||||
|
return $roles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,13 @@ interface UserRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function all(): Collection;
|
public function all(): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
* @param int $groupId
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getRolesInGroup(User $user, int $groupId): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives a user a role.
|
* Gives a user a role.
|
||||||
*
|
*
|
||||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Transformers;
|
namespace FireflyIII\Transformers;
|
||||||
|
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ class UserTransformer extends AbstractTransformer
|
|||||||
* @param User $user
|
* @param User $user
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function transform(User $user): array
|
public function transform(User $user): array
|
||||||
{
|
{
|
||||||
@@ -47,6 +49,7 @@ class UserTransformer extends AbstractTransformer
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => (int)$user->id,
|
'id' => (int)$user->id,
|
||||||
|
'administration_id' => (string)$user->getAdministrationId(),
|
||||||
'created_at' => $user->created_at->toAtomString(),
|
'created_at' => $user->created_at->toAtomString(),
|
||||||
'updated_at' => $user->updated_at->toAtomString(),
|
'updated_at' => $user->updated_at->toAtomString(),
|
||||||
'email' => $user->email,
|
'email' => $user->email,
|
||||||
|
15
app/User.php
15
app/User.php
@@ -27,6 +27,7 @@ namespace FireflyIII;
|
|||||||
use Eloquent;
|
use Eloquent;
|
||||||
use Exception;
|
use Exception;
|
||||||
use FireflyIII\Events\RequestedNewPassword;
|
use FireflyIII\Events\RequestedNewPassword;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Attachment;
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\AvailableBudget;
|
use FireflyIII\Models\AvailableBudget;
|
||||||
@@ -361,6 +362,20 @@ class User extends Authenticatable
|
|||||||
return $this->hasMany(GroupMembership::class)->with(['userGroup', 'userRole']);
|
return $this->hasMany(GroupMembership::class)->with(['userGroup', 'userRole']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A safe method that returns the user's current administration ID (group ID).
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function getAdministrationId(): int {
|
||||||
|
$groupId = (int)$this->user_group_id;
|
||||||
|
if(0 === $groupId) {
|
||||||
|
throw new FireflyException('User has no administration ID.');
|
||||||
|
}
|
||||||
|
return $groupId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* Link to object groups.
|
* Link to object groups.
|
||||||
|
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* ValidatesAdministrationAccess.php
|
||||||
|
* Copyright (c) 2023 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FireflyIII\Validation\Administration;
|
||||||
|
|
||||||
|
use FireflyIII\Models\UserRole;
|
||||||
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait ValidatesAdministrationAccess
|
||||||
|
*/
|
||||||
|
trait ValidatesAdministrationAccess
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Validator $validator
|
||||||
|
* @param array $allowedRoles
|
||||||
|
* @return void
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
|
protected function validateAdministration(Validator $validator, array $allowedRoles): void
|
||||||
|
{
|
||||||
|
Log::debug('Now in validateAdministration()');
|
||||||
|
if (!auth()->check()) {
|
||||||
|
Log::error('User is not authenticated.');
|
||||||
|
throw new AuthenticationException('No access to validateAdministration() method.');
|
||||||
|
}
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
// get data from request:
|
||||||
|
$data = $validator->getData();
|
||||||
|
// check if user is part of this administration
|
||||||
|
$administrationId = (int)($data['administration_id'] ?? $user->getAdministrationId());
|
||||||
|
// safety catch:
|
||||||
|
if (0 === $administrationId) {
|
||||||
|
Log::error('validateAdministration ran into empty administration ID.');
|
||||||
|
throw new AuthenticationException('Cannot validate administration.');
|
||||||
|
}
|
||||||
|
// grab the group:
|
||||||
|
$repository = app(UserRepositoryInterface::class);
|
||||||
|
|
||||||
|
// collect the user's roles in this group:
|
||||||
|
$administrationId = 2;
|
||||||
|
$array = $repository->getRolesInGroup($user, $administrationId);
|
||||||
|
if (0 === count($array)) {
|
||||||
|
Log::error(sprintf('User #%d ("%s") has no membership in group #%d.', $user->id, $user->email, $administrationId));
|
||||||
|
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (in_array(UserRole::OWNER, $array, true)) {
|
||||||
|
Log::debug('User is owner of this administration.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (in_array(UserRole::FULL, $array, true)) {
|
||||||
|
Log::debug('User has full access to this administration.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$access = true;
|
||||||
|
foreach ($allowedRoles as $allowedRole) {
|
||||||
|
if (!in_array($allowedRole, $array, true)) {
|
||||||
|
$access = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (false === $access) {
|
||||||
|
Log::error(
|
||||||
|
sprintf(
|
||||||
|
'User #%d has memberships [%s] to group #%d but needs [%s].',
|
||||||
|
$user->id,
|
||||||
|
join(', ', $array),
|
||||||
|
$administrationId,
|
||||||
|
join(', ', $allowedRoles)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$validator->errors()->add('administration', (string)trans('validation.no_access_user_group'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -240,6 +240,9 @@ return [
|
|||||||
'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_user_group' => 'You do not have the correct access rights for this administration.',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Ignore this comment
|
// Ignore this comment
|
||||||
|
Reference in New Issue
Block a user