Find this useful? Enter your email to receive occasional updates for securing PHP code.

Signing you up...

Thank you for signing up!

PHP Decode

<?php declare(strict_types=1); /** * Passbolt ~ Open source password manager for teams ..

Decoded Output download

<?php
declare(strict_types=1);

/**
 * Passbolt ~ Open source password manager for teams
 * Copyright (c) Passbolt SA (https://www.passbolt.com)
 *
 * Licensed under GNU Affero General Public License version 3 of the or any later version.
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Passbolt SA (https://www.passbolt.com)
 * @license       https://opensource.org/licenses/AGPL-3.0 AGPL License
 * @link          https://www.passbolt.com Passbolt(tm)
 * @since         2.0.0
 */
namespace App\Controller\Users;

use App\Controller\AppController;
use App\Error\Exception\ValidationException;
use App\Model\Entity\Role;
use App\Model\Entity\User;
use App\Model\Table\AvatarsTable;
use App\Model\Table\UsersTable;
use App\Service\Resources\ResourcesExpireResourcesServiceInterface;
use Cake\Event\Event;
use Cake\Http\Exception\BadRequestException;
use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\InternalErrorException;
use Cake\Validation\Validation;
use Exception;
use League\Flysystem\FilesystemAdapter;

/**
 * UsersEditController Class
 */
class UsersEditController extends AppController
{
    protected UsersTable $Users;

    public const EVENT_USER_WAS_DISABLED = 'Controller.UsersEditController.userWasDisabled';
    public const EVENT_ADMIN_WAS_DISABLED = 'Controller.UsersEditController.adminWasDisabled';

    public const EVENT_USER_AFTER_UPDATE = 'Controller.UsersEditController.afterUpdate';

    /**
     * User edit action
     * Allow editing firstname / lastname and role only for admin
     *
     * @param string $id user uuid
     * @param \League\Flysystem\FilesystemAdapter $filesystemAdapter file system adapter to write the avatar in cache if saved
     * @param \App\Service\Resources\ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService Service to expire resources that were consumed by users who lost access to them.
     * @return void
     */
    public function editPost(
        string $id,
        FilesystemAdapter $filesystemAdapter,
        ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService
    ) {
        $this->assertJson();

        $data = $this->_validateRequestData($id);

        // Try to find the user and validate changes it
        /** @var \App\Model\Table\UsersTable $usersTable */
        $usersTable = $this->fetchTable('Users');
        $this->Users = $usersTable;
        try {
            /** @var \App\Model\Entity\User $user */
            $user = $this->Users->findView($id, $this->User->role())->first();
        } catch (Exception $exception) {
            throw new BadRequestException(__('The user does not exist or has been deleted.'));
        }
        if (empty($user)) {
            throw new BadRequestException(__('The user does not exist or has been deleted.'));
        }
        $wasDisabledNull = is_null($user->disabled);

        // Patch
        $user = $this->Users->editEntity($user, $data, $this->User->getAccessControl());
        if ($user->getErrors()) {
            throw new ValidationException(__('Could not validate user data.'), $user, $this->Users);
        }
        $this->Users->checkRules($user);
        if (!empty($user->getErrors())) {
            throw new ValidationException(__('Could not validate user data.'), $user, $this->Users);
        }
        $isBeingDisabled = $wasDisabledNull && !is_null($user->disabled);

        // Used when sending after update event
        // We need entity's dirty state to know which column values has been changed.
        $userEntityWithDirtyState = clone $user;

        // Save
        $saveOptions = [
            'checkrules' => false,
            AvatarsTable::FILESYSTEM_ADAPTER_OPTION => $filesystemAdapter,
        ];
        if (!$this->Users->save($user, $saveOptions)) {
            throw new InternalErrorException('Could not save the user data. Please try again later.');
        }

        if ($isBeingDisabled) {
            /** @var \App\Model\Table\SecretsTable $secretsTable */
            $secretsTable = $this->fetchTable('Secrets');
            $secretToExpire = $secretsTable->findByUserId($id)
                ->select(['id', 'user_id', 'resource_id'])->all()->toArray();
            $resourcesExpireResourcesService->expireResourcesForSecrets($secretToExpire);
        }

        // Get the updated version (ex. Role needs to be fetched again if role_id changed)
        try {
            /** @var \App\Model\Entity\User $user */
            $user = $this->Users->findView($id, $this->User->role())->firstOrFail();
        } catch (Exception $exception) {
            $msg = __('Could not find the user data after save. Maybe it has been deleted in the meantime.');
            throw new InternalErrorException($msg, 500, $exception);
        }

        if ($isBeingDisabled) {
            $this->sendEmailOnUserDisable($user);
        }

        $this->sendAfterUpdateEvent($userEntityWithDirtyState);

        $this->success(__('The user has been updated successfully.'), $user);
    }

    /**
     * Assert request sanity and return the sanitized data
     *
     * @param string $id user uuid
     * @return array
     * @throws \Cake\Http\Exception\BadRequestException if gpgkey is sent (v2 only)
     * @throws \Cake\Http\Exception\BadRequestException if groups data is sent (v2 only)
     * @throws \Cake\Http\Exception\BadRequestException if role data is sent (v2 only)
     * @throws \Cake\Http\Exception\ForbiddenException if the user is not admin or not editing themselves
     * @throws \Cake\Http\Exception\BadRequestException if the user id is invalid, if data is not provided or invalid
     */
    protected function _validateRequestData(string $id): array
    {
        // Admin can edit all users, other users can only edit themselves
        if ($this->User->role() !== Role::ADMIN && $id !== $this->User->id()) {
            throw new ForbiddenException(__('You are not authorized to access that location.'));
        }

        // Baseline validation
        if (!Validation::uuid($id)) {
            throw new BadRequestException(__('The user identifier should be a valid UUID.'));
        }
        $data = $this->request->getData();
        $data['id'] = $id;
        if (empty($data) || count($data) < 2) {
            throw new BadRequestException(__('Some user data should be provided.'));
        }

        if (isset($data['gpgkey'])) {
            throw new BadRequestException(__('Updating the OpenPGP key is not allowed.'));
        }
        if (isset($data['groups_user'])) {
            throw new BadRequestException(__('Updating the groups is not allowed.'));
        }
        if ($this->User->role() !== Role::ADMIN && (isset($data['role']) || isset($data['role_id']))) {
            throw new ForbiddenException(__('You are not authorized to edit the role.'));
        }

        // Sanitize data as the marshaller will throw a type error if the payload has integers as fields
        $sanitizedData = [];
        $allowedKeys = [
            'role_id',
            'disabled',
            'profile' => [
                'first_name',
                'last_name',
                'avatar',
            ],
        ];

        foreach ($allowedKeys as $allowedMainKey => $allowedKey) {
            if (!is_array($allowedKey)) {
                if (array_key_exists($allowedKey, $data)) {
                    $sanitizedData[$allowedKey] = $data[$allowedKey];
                }
            } else {
                foreach ($allowedKey as $allowedNestedKey) {
                    if (!array_key_exists($allowedMainKey, $data)) {
                        break;
                    }

                    if (array_key_exists($allowedNestedKey, $data[$allowedMainKey])) {
                        $sanitizedData[$allowedMainKey][$allowedNestedKey] = $data[$allowedMainKey][$allowedNestedKey];
                    }
                }
            }
        }

        return $sanitizedData;
    }

    /**
     * Sends an email to all admins when a user has been disabled
     * Sends an email to the user disabled if that user is an admin
     *
     * @param \App\Model\Entity\User $user User being edited
     * @return void
     */
    protected function sendEmailOnUserDisable(User $user): void
    {
        $operator = $this->User->getAccessControl();
        $emailData = compact('user', 'operator');
        $event = new Event(static::EVENT_USER_WAS_DISABLED, $this, $emailData);
        $this->getEventManager()->dispatch($event);

        if ($user->role->name === Role::ADMIN) {
            $event = new Event(static::EVENT_ADMIN_WAS_DISABLED, $this, $emailData);
            $this->getEventManager()->dispatch($event);
        }
    }

    /**
     * Dispatch a common after update event to hook into several functionality on top.
     *
     * @param \App\Model\Entity\User $user User entity object with dirty state(before save).
     * @return void
     */
    private function sendAfterUpdateEvent(User $user): void
    {
        $operator = $this->User->getExtendAccessControl();

        $emailData = [
            'operator' => $operator,
            'user' => $user,
        ];

        $event = new Event(static::EVENT_USER_AFTER_UPDATE, $this, $emailData);
        $this->getEventManager()->dispatch($event);
    }
}
 ?>

Did this file decode correctly?

Original Code

<?php
declare(strict_types=1);

/**
 * Passbolt ~ Open source password manager for teams
 * Copyright (c) Passbolt SA (https://www.passbolt.com)
 *
 * Licensed under GNU Affero General Public License version 3 of the or any later version.
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Passbolt SA (https://www.passbolt.com)
 * @license       https://opensource.org/licenses/AGPL-3.0 AGPL License
 * @link          https://www.passbolt.com Passbolt(tm)
 * @since         2.0.0
 */
namespace App\Controller\Users;

use App\Controller\AppController;
use App\Error\Exception\ValidationException;
use App\Model\Entity\Role;
use App\Model\Entity\User;
use App\Model\Table\AvatarsTable;
use App\Model\Table\UsersTable;
use App\Service\Resources\ResourcesExpireResourcesServiceInterface;
use Cake\Event\Event;
use Cake\Http\Exception\BadRequestException;
use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\InternalErrorException;
use Cake\Validation\Validation;
use Exception;
use League\Flysystem\FilesystemAdapter;

/**
 * UsersEditController Class
 */
class UsersEditController extends AppController
{
    protected UsersTable $Users;

    public const EVENT_USER_WAS_DISABLED = 'Controller.UsersEditController.userWasDisabled';
    public const EVENT_ADMIN_WAS_DISABLED = 'Controller.UsersEditController.adminWasDisabled';

    public const EVENT_USER_AFTER_UPDATE = 'Controller.UsersEditController.afterUpdate';

    /**
     * User edit action
     * Allow editing firstname / lastname and role only for admin
     *
     * @param string $id user uuid
     * @param \League\Flysystem\FilesystemAdapter $filesystemAdapter file system adapter to write the avatar in cache if saved
     * @param \App\Service\Resources\ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService Service to expire resources that were consumed by users who lost access to them.
     * @return void
     */
    public function editPost(
        string $id,
        FilesystemAdapter $filesystemAdapter,
        ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService
    ) {
        $this->assertJson();

        $data = $this->_validateRequestData($id);

        // Try to find the user and validate changes it
        /** @var \App\Model\Table\UsersTable $usersTable */
        $usersTable = $this->fetchTable('Users');
        $this->Users = $usersTable;
        try {
            /** @var \App\Model\Entity\User $user */
            $user = $this->Users->findView($id, $this->User->role())->first();
        } catch (Exception $exception) {
            throw new BadRequestException(__('The user does not exist or has been deleted.'));
        }
        if (empty($user)) {
            throw new BadRequestException(__('The user does not exist or has been deleted.'));
        }
        $wasDisabledNull = is_null($user->disabled);

        // Patch
        $user = $this->Users->editEntity($user, $data, $this->User->getAccessControl());
        if ($user->getErrors()) {
            throw new ValidationException(__('Could not validate user data.'), $user, $this->Users);
        }
        $this->Users->checkRules($user);
        if (!empty($user->getErrors())) {
            throw new ValidationException(__('Could not validate user data.'), $user, $this->Users);
        }
        $isBeingDisabled = $wasDisabledNull && !is_null($user->disabled);

        // Used when sending after update event
        // We need entity's dirty state to know which column values has been changed.
        $userEntityWithDirtyState = clone $user;

        // Save
        $saveOptions = [
            'checkrules' => false,
            AvatarsTable::FILESYSTEM_ADAPTER_OPTION => $filesystemAdapter,
        ];
        if (!$this->Users->save($user, $saveOptions)) {
            throw new InternalErrorException('Could not save the user data. Please try again later.');
        }

        if ($isBeingDisabled) {
            /** @var \App\Model\Table\SecretsTable $secretsTable */
            $secretsTable = $this->fetchTable('Secrets');
            $secretToExpire = $secretsTable->findByUserId($id)
                ->select(['id', 'user_id', 'resource_id'])->all()->toArray();
            $resourcesExpireResourcesService->expireResourcesForSecrets($secretToExpire);
        }

        // Get the updated version (ex. Role needs to be fetched again if role_id changed)
        try {
            /** @var \App\Model\Entity\User $user */
            $user = $this->Users->findView($id, $this->User->role())->firstOrFail();
        } catch (Exception $exception) {
            $msg = __('Could not find the user data after save. Maybe it has been deleted in the meantime.');
            throw new InternalErrorException($msg, 500, $exception);
        }

        if ($isBeingDisabled) {
            $this->sendEmailOnUserDisable($user);
        }

        $this->sendAfterUpdateEvent($userEntityWithDirtyState);

        $this->success(__('The user has been updated successfully.'), $user);
    }

    /**
     * Assert request sanity and return the sanitized data
     *
     * @param string $id user uuid
     * @return array
     * @throws \Cake\Http\Exception\BadRequestException if gpgkey is sent (v2 only)
     * @throws \Cake\Http\Exception\BadRequestException if groups data is sent (v2 only)
     * @throws \Cake\Http\Exception\BadRequestException if role data is sent (v2 only)
     * @throws \Cake\Http\Exception\ForbiddenException if the user is not admin or not editing themselves
     * @throws \Cake\Http\Exception\BadRequestException if the user id is invalid, if data is not provided or invalid
     */
    protected function _validateRequestData(string $id): array
    {
        // Admin can edit all users, other users can only edit themselves
        if ($this->User->role() !== Role::ADMIN && $id !== $this->User->id()) {
            throw new ForbiddenException(__('You are not authorized to access that location.'));
        }

        // Baseline validation
        if (!Validation::uuid($id)) {
            throw new BadRequestException(__('The user identifier should be a valid UUID.'));
        }
        $data = $this->request->getData();
        $data['id'] = $id;
        if (empty($data) || count($data) < 2) {
            throw new BadRequestException(__('Some user data should be provided.'));
        }

        if (isset($data['gpgkey'])) {
            throw new BadRequestException(__('Updating the OpenPGP key is not allowed.'));
        }
        if (isset($data['groups_user'])) {
            throw new BadRequestException(__('Updating the groups is not allowed.'));
        }
        if ($this->User->role() !== Role::ADMIN && (isset($data['role']) || isset($data['role_id']))) {
            throw new ForbiddenException(__('You are not authorized to edit the role.'));
        }

        // Sanitize data as the marshaller will throw a type error if the payload has integers as fields
        $sanitizedData = [];
        $allowedKeys = [
            'role_id',
            'disabled',
            'profile' => [
                'first_name',
                'last_name',
                'avatar',
            ],
        ];

        foreach ($allowedKeys as $allowedMainKey => $allowedKey) {
            if (!is_array($allowedKey)) {
                if (array_key_exists($allowedKey, $data)) {
                    $sanitizedData[$allowedKey] = $data[$allowedKey];
                }
            } else {
                foreach ($allowedKey as $allowedNestedKey) {
                    if (!array_key_exists($allowedMainKey, $data)) {
                        break;
                    }

                    if (array_key_exists($allowedNestedKey, $data[$allowedMainKey])) {
                        $sanitizedData[$allowedMainKey][$allowedNestedKey] = $data[$allowedMainKey][$allowedNestedKey];
                    }
                }
            }
        }

        return $sanitizedData;
    }

    /**
     * Sends an email to all admins when a user has been disabled
     * Sends an email to the user disabled if that user is an admin
     *
     * @param \App\Model\Entity\User $user User being edited
     * @return void
     */
    protected function sendEmailOnUserDisable(User $user): void
    {
        $operator = $this->User->getAccessControl();
        $emailData = compact('user', 'operator');
        $event = new Event(static::EVENT_USER_WAS_DISABLED, $this, $emailData);
        $this->getEventManager()->dispatch($event);

        if ($user->role->name === Role::ADMIN) {
            $event = new Event(static::EVENT_ADMIN_WAS_DISABLED, $this, $emailData);
            $this->getEventManager()->dispatch($event);
        }
    }

    /**
     * Dispatch a common after update event to hook into several functionality on top.
     *
     * @param \App\Model\Entity\User $user User entity object with dirty state(before save).
     * @return void
     */
    private function sendAfterUpdateEvent(User $user): void
    {
        $operator = $this->User->getExtendAccessControl();

        $emailData = [
            'operator' => $operator,
            'user' => $user,
        ];

        $event = new Event(static::EVENT_USER_AFTER_UPDATE, $this, $emailData);
        $this->getEventManager()->dispatch($event);
    }
}

Function Calls

None

Variables

None

Stats

MD5 4bfaea11eddc02276f56d4bf12982af7
Eval Count 0
Decode Time 105 ms