mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-30 10:33:30 +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\Location;
|
||||
use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Support\Request\AppendsLocationData;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class AccountFormRequest.
|
||||
@@ -39,6 +42,7 @@ class AccountFormRequest extends FormRequest
|
||||
use ConvertsDataTypes;
|
||||
use AppendsLocationData;
|
||||
use ChecksLogin;
|
||||
use ValidatesAdministrationAccess;
|
||||
|
||||
/**
|
||||
* Get all data.
|
||||
@@ -48,6 +52,7 @@ class AccountFormRequest extends FormRequest
|
||||
public function getAccountData(): array
|
||||
{
|
||||
$data = [
|
||||
'administration_id' => $this->convertInteger('administration_id'),
|
||||
'name' => $this->convertString('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'account_type_name' => $this->convertString('objectType'),
|
||||
@@ -67,6 +72,9 @@ class AccountFormRequest extends FormRequest
|
||||
'include_net_worth' => '1',
|
||||
'liability_direction' => $this->convertString('liability_direction'),
|
||||
];
|
||||
if (0 === $data['administration_id']) {
|
||||
$data['administration_id'] = auth()->user()->getAdministrationId();
|
||||
}
|
||||
|
||||
$data = $this->appendLocationData($data, 'location');
|
||||
if (false === $this->boolean('include_net_worth')) {
|
||||
@@ -101,6 +109,7 @@ class AccountFormRequest extends FormRequest
|
||||
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
||||
$rules = [
|
||||
'administration_id' => 'min:1|max:16777216|numeric',
|
||||
'name' => 'required|min:1|uniqueAccountForUser',
|
||||
'opening_balance' => 'numeric|nullable|max:1000000000',
|
||||
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
||||
@@ -130,4 +139,20 @@ class AccountFormRequest extends FormRequest
|
||||
|
||||
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 FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\GroupMembership;
|
||||
use FireflyIII\Models\InvitedUser;
|
||||
use FireflyIII\Models\Role;
|
||||
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();
|
||||
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;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param int $groupId
|
||||
* @return array
|
||||
*/
|
||||
public function getRolesInGroup(User $user, int $groupId): array;
|
||||
|
||||
/**
|
||||
* Gives a user a role.
|
||||
*
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
|
||||
@@ -40,6 +41,7 @@ class UserTransformer extends AbstractTransformer
|
||||
* @param User $user
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function transform(User $user): array
|
||||
{
|
||||
@@ -47,6 +49,7 @@ class UserTransformer extends AbstractTransformer
|
||||
|
||||
return [
|
||||
'id' => (int)$user->id,
|
||||
'administration_id' => (string)$user->getAdministrationId(),
|
||||
'created_at' => $user->created_at->toAtomString(),
|
||||
'updated_at' => $user->updated_at->toAtomString(),
|
||||
'email' => $user->email,
|
||||
|
15
app/User.php
15
app/User.php
@@ -27,6 +27,7 @@ namespace FireflyIII;
|
||||
use Eloquent;
|
||||
use Exception;
|
||||
use FireflyIII\Events\RequestedNewPassword;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
@@ -361,6 +362,20 @@ class User extends Authenticatable
|
||||
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
|
||||
* 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.',
|
||||
'auto_budget_amount_positive' => 'The amount must be more than zero.',
|
||||
'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
|
||||
|
Reference in New Issue
Block a user