<commit_before><?php
App::uses('ConnectionManager', 'Model');
App::uses('Controller', 'Controller');
App::uses('File', 'Utility');
App::uses('RequestRearrangeTool', 'Tools');
App::uses('BlowfishConstantPasswordHasher', 'Controller/Component/Auth');
App::uses('BetterCakeEventManager', 'Tools');

/**
 * Application Controller
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @package       app.Controller
 * @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
 *
 * @property ACLComponent $ACL
 * @property RestResponseComponent $RestResponse
 * @property CRUDComponent $CRUD
 * @property IndexFilterComponent $IndexFilter
 * @property RateLimitComponent $RateLimit
 * @property CompressedRequestHandlerComponent $CompressedRequestHandler
 * @property DeprecationComponent $Deprecation
 * @property RestSearchComponent $RestSearch
 * @property BetterSecurityComponent $Security
 */
class AppController extends Controller
{
    /**
     * @var string
     * @deprecated Use modelClass instead
     */
    public $defaultModel = '';

    public $helpers = array('OrgImg', 'FontAwesome', 'UserName');

    private $__queryVersion = '145';
    public $pyMispVersion = '2.4.162';
    public $phpmin = '7.2';
    public $phprec = '7.4';
    public $phptoonew = '8.0';
    public $pythonmin = '3.6';
    public $pythonrec = '3.7';
    private $isApiAuthed = false;

    public $baseurl = '';
    public $sql_dump = false;

    public $restResponsePayload = null;

    protected $_legacyParams = array();
    /** @var array */
    public $userRole;

    /** @var User */
    public $User;

    public function __construct($request = null, $response = null)
    {
        parent::__construct($request, $response);
        $this->defaultModel = $this->modelClass;
    }

    public $components = array(
        'Session',
        'Auth' => array(
            'authError' => 'Unauthorised access.',
            'authenticate' => array(
                'Form' => array(
                    'passwordHasher' => '<PASSWORD>',
                    'fields' => array(
                        'username' => 'email'
                    )
                )
            )
        ),
        'Security' => [
            'className' => 'BetterSecurity',
        ],
        'ACL',
        'CompressedRequestHandler',
        'RestResponse',
        'Flash',
        'Toolbox',
        'RateLimit',
        'IndexFilter',
        'Deprecation',
        'RestSearch',
        'CRUD'
        //,'DebugKit.Toolbar'
    );

    public function beforeFilter()
    {
        if (Configure::read('MISP.system_setting_db')) {
            App::uses('SystemSetting', 'Model');
            SystemSetting::setGlobalSetting();
        }

        $this->_setupBaseurl();
        $this->Auth->loginRedirect = $this->baseurl . '/users/routeafterlogin';

        $customLogout = Configure::read('Plugin.CustomAuth_custom_logout');
        $this->Auth->logoutRedirect = $customLogout ?: ($this->baseurl . '/users/login');

        $this->__sessionMassage();

        // If server is running behind reverse proxy, PHP will not recognize that user is accessing site by HTTPS connection.
        // By setting `Security.force_https` to `true`, session cookie will be set as Secure and CSP headers will upgrade insecure requests.
        if (Configure::read('Security.force_https')) {
            $_SERVER['HTTPS'] = 'on';
        }
        $this->__cors();
        if (Configure::read('Security.check_sec_fetch_site_header')) {
            $secFetchSite = $this->request->header('Sec-Fetch-Site');
            if ($secFetchSite !== false && $secFetchSite !== 'same-origin' && ($this->request->is('post') || $this->request->is('put') || $this->request->is('ajax'))) {
                throw new MethodNotAllowedException("POST, PUT and AJAX requests are allowed just from same origin.");
            }
        }
        if (Configure::read('Security.disable_browser_cache')) {
            $this->response->disableCache();
        }
        if (!$this->_isRest()) {
            $this->__contentSecurityPolicy();
            $this->response->header('X-XSS-Protection', '1; mode=block');
        }

        if (!empty($this->request->params['named']['sql'])) {
            $this->sql_dump = intval($this->request->params['named']['sql']);
        }

        $this->_setupDatabaseConnection();

        $this->set('debugMode', Configure::read('debug') >= 1 ? 'debugOn' : 'debugOff');
        $isAjax = $this->request->is('ajax');
        $this->set('ajax', $isAjax);
        $this->set('queryVersion', $this->__queryVersion);
        $this->User = ClassRegistry::init('User');

        $language = Configure::read('MISP.language');
        if (!empty($language) && $language !== 'eng') {
            Configure::write('Config.language', $language);
        } else {
            Configure::write('Config.language', 'eng');
        }

        // For fresh installation (salt empty) generate a new salt
        if (!Configure::read('Security.salt')) {
            $this->User->Server->serverSettingsSaveValue('Security.salt', $this->User->generateRandomPassword(32));
        }

        // Check if the instance has a UUID, if not assign one.
        if (!Configure::read('MISP.uuid')) {
            $this->User->Server->serverSettingsSaveValue('MISP.uuid', CakeText::uuid());
        }

        // Check if Apache provides kerberos authentication data
        $authUserFields = $this->User->describeAuthFields();
        $envvar = Configure::read('ApacheSecureAuth.apacheEnv');
        if ($envvar && isset($_SERVER[$envvar])) {
            $this->Auth->className = 'ApacheSecureAuth';
            $this->Auth->authenticate = array(
                'Apache' => array(
                    // envvar = field returned by Apache if user is authenticated
                    'fields' => array('username' => 'email', 'envvar' => $envvar),
                    'userFields' => $authUserFields,
                )
            );
        } else {
            $this->Auth->authenticate[AuthComponent::ALL]['userFields'] = $authUserFields;
        }
        if (!empty($this->request->params['named']['disable_background_processing'])) {
            Configure::write('MISP.background_jobs', 0);
        }
        Configure::write('CurrentController', $this->request->params['controller']);
        Configure::write('CurrentAction', $this->request->params['action']);
        $versionArray = $this->User->checkMISPVersion();
        $this->mispVersion = implode('.', $versionArray);
        $this->Security->blackHoleCallback = 'blackHole';

        // send users away that are using ancient versions of IE
        // Make sure to update this if IE 20 comes out :)
        if (isset($_SERVER['HTTP_USER_AGENT'])) {
            if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT']) && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
                throw new MethodNotAllowedException('You are using an unsecure and outdated version of IE, please download Google Chrome, Mozilla Firefox or update to a newer version of IE. If you are running IE9 or newer and still receive this error message, please make sure that you are not running your browser in compatibility mode. If you still have issues accessing the site, get in touch with your administration team at ' . Configure::read('MISP.contact'));
            }
        }
        $userLoggedIn = false;
        if (Configure::read('Plugin.CustomAuth_enable')) {
            $userLoggedIn = $this->__customAuthentication($_SERVER);
        }
        if ($this->_isRest()) {
            $jsonDecode = function ($dataToDecode) {
                if (empty($dataToDecode)) {
                    return null;
                }
                return $this->_jsonDecode($dataToDecode);
            };
            //  Throw exception if JSON in request is invalid. Default CakePHP behaviour would just ignore that error.
            $this->RequestHandler->addInputType('json', [$jsonDecode]);
            $this->Security->unlockedActions = array($this->request->action);
            $this->Security->doNotGenerateToken = true;
        }

        if (
            !$userLoggedIn &&
            (
                $this->request->params['controller'] !== 'users' ||
                $this->request->params['action'] !== 'register' ||
                empty(Configure::read('Security.allow_self_registration'))
            )
        ) {
            // REST authentication
            if ($this->_isRest() || $this->_isAutomation()) {
                // disable CSRF for REST access
                $this->Security->csrfCheck = false;
                if ($this->__loginByAuthKey() === false || $this->Auth->user() === null) {
                    if ($this->__loginByAuthKey() === null) {
                        $this->loadModel('Log');
                        $this->Log->createLogEntry('SYSTEM', 'auth_fail', 'User', 0, "Failed API authentication. No authkey was provided.");
                    }
                    throw new ForbiddenException('Authentication failed. Please make sure you pass the API key of an API enabled user along in the Authorization header.');
                }
            } elseif (!$this->Session->read(AuthComponent::$sessionKey)) {
                $this->_loadAuthenticationPlugins();
            }
        }

        $user = $this->Auth->user();
        if ($user) {
            Configure::write('CurrentUserId', $user['id']);
            $this->__logAccess($user);

            // Try to run updates
            if ($user['Role']['perm_site_admin'] || (!$this->_isRest() && !$isAjax && $this->_isLive())) {
                $this->User->runUpdates();
            }

            // Put username to response header for webserver or proxy logging
            if (Configure::read('Security.username_in_response_header')) {
                $headerValue = $user['email'];
                if (isset($user['logged_by_authkey']) && $user['logged_by_authkey']) {
                    $headerValue .= isset($user['authkey_id']) ? "/API/{$user['authkey_id']}" :  '/API/default';
                }
                $this->response->header('X-Username', $headerValue);
                $this->RestResponse->setHeader('X-Username', $headerValue);
            }

            if (!$this->__verifyUser($user))  {
                $this->_stop(); // just for sure
            }
            $user = $this->Auth->user(); // user info in session could change (see __verifyUser) method, so reload user variable

            if (isset($user['logged_by_authkey']) && $user['logged_by_authkey'] && !($this->_isRest() || $this->_isAutomation())) {
                throw new ForbiddenException("When user is authenticated by authkey, just REST request can be processed.");
            }

            // Put token expiration time to response header that can be processed by automation tool
            if (isset($user['authkey_expiration']) && $user['authkey_expiration']) {
                $expiration = date('c', $user['authkey_expiration']);
                $this->response->header('X-Auth-Key-Expiration', $expiration);
                $this->RestResponse->setHeader('X-Auth-Key-Expiration', $expiration);
            }

            $this->set('default_memory_limit', ini_get('memory_limit'));
            if (isset($user['Role']['memory_limit']) && $user['Role']['memory_limit'] !== '') {
                 ini_set('memory_limit', $user['Role']['memory_limit']);
            }
            $this->set('default_max_execution_time', ini_get('max_execution_time'));
            if (isset($user['Role']['max_execution_time']) && $user['Role']['max_execution_time'] !== '') {
                ini_set('max_execution_time', $user['Role']['max_execution_time']);
            }

            $this->set('mispVersion', "{$versionArray['major']}.{$versionArray['minor']}.0");
            $this->set('mispVersionFull', $this->mispVersion);
            $this->set('me', $user);
            $role = $user['Role'];
            $this->set('isAdmin', $role['perm_admin']);
            $this->set('isSiteAdmin', $role['perm_site_admin']);
            $this->set('hostOrgUser', $user['org_id'] == Configure::read('MISP.host_org_id'));
            $this->set('isAclAdd', $role['perm_add']);
            $this->set('isAclModify', $role['perm_modify']);
            $this->set('isAclModifyOrg', $role['perm_modify_org']);
            $this->set('isAclPublish', $role['perm_publish']);
            $this->set('isAclDelegate', $role['perm_delegate']);
            $this->set('isAclSync', $role['perm_sync']);
            $this->set('isAclAdmin', $role['perm_admin']);
            $this->set('isAclAudit', $role['perm_audit']);
            $this->set('isAclAuth', $role['perm_auth']);
            $this->set('isAclRegexp', $role['perm_regexp_access']);
            $this->set('isAclTagger', $role['perm_tagger']);
            $this->set('isAclTagEditor', $role['perm_tag_editor']);
            $this->set('isAclTemplate', $role['perm_template']);
            $this->set('isAclGalaxyEditor', !empty($role['perm_galaxy_editor']));
            $this->set('isAclSharingGroup', $role['perm_sharing_group']);
            $this->set('isAclSighting', $role['perm_sighting'] ?? false);
            $this->set('isAclZmq', $role['perm_publish_zmq'] ?? false);
            $this->set('isAclKafka', $role['perm_publish_kafka'] ?? false);
            $this->set('isAclDecaying', $role['perm_decaying'] ?? false);
            $this->set('aclComponent', $this->ACL);
            $this->userRole = $role;

            $this->__accessMonitor($user);

        } else {
            $preAuthActions = array('login', 'register', 'getGpgPublicKey');
            if (!empty(Configure::read('Security.email_otp_enabled'))) {
                $preAuthActions[] = 'email_otp';
            }
            if (!$this->_isControllerAction(['users' => $preAuthActions, 'servers' => ['cspReport']])) {
                if ($isAjax) {
                    $response = $this->RestResponse->throwException(401, "Unauthorized");
                    $response->send();
                    $this->_stop();
                } else {
                    $this->Session->write('pre_login_requested_url', $this->request->here);
                    $this->_redirectToLogin();
                }
            }
            $this->set('me', false);
        }

        if ($user && $this->_isSiteAdmin()) {
            if (Configure::read('Session.defaults') === 'database') {
                $db = ConnectionManager::getDataSource('default');
                $sqlResult = $db->query('SELECT COUNT(id) AS session_count FROM cake_sessions WHERE expires < ' . time() . ';');
                if (isset($sqlResult[0][0]['session_count']) && $sqlResult[0][0]['session_count'] > 1000) {
                    $this->User->Server->updateDatabase('cleanSessionTable');
                }
            }
            if (Configure::read('site_admin_debug') && Configure::read('debug') < 2) {
                Configure::write('debug', 1);
            }
        }

        $this->ACL->checkAccess($user, Inflector::variable($this->request->params['controller']), $this->request->action);
        if ($user && $this->_isRest()) {
            $this->__rateLimitCheck($user);
        }
        if ($this->modelClass !== 'CakeError') {
            $deprecationWarnings = $this->Deprecation->checkDeprecation($this->request->params['controller'], $this->request->action, $this->User, $user ? $user['id'] : null);
            if ($deprecationWarnings) {
                $deprecationWarnings = __('WARNING: This functionality is deprecated and will be removed in the near future. ') . $deprecationWarnings;
                if ($this->_isRest()) {
                    $this->response->header('X-Deprecation-Warning', $deprecationWarnings);
                    $this->RestResponse->setHeader('X-Deprecation-Warning', $deprecationWarnings);
                } else {
                    $this->Flash->warning($deprecationWarnings);
                }
            }
        }
    }

    public function beforeRender()
    {
        // Notifications and homepage is not necessary for AJAX or REST requests
        $user = $this->Auth->user();
        if ($user && !$this->_isRest() && isset($this->User) && !$this->request->is('ajax')) {
            $hasNotifications = $this->User->hasNotifications($user);
            $this->set('hasNotifications', $hasNotifications);

            $homepage = $this->User->UserSetting->getValueForUser($user['id'], 'homepage');
            if (!empty($homepage)) {
                $this->set('homepage', $homepage);
            }
            if (PHP_MAJOR_VERSION >= 8) {
                $this->Flash->error(__('WARNING: MISP is currently running under PHP 8.0, which is unsupported. Background jobs will fail, so please contact your administrator to run a supported PHP version (such as 7.4)'));
            }
        }
    }

    /**
     * @return null|bool True if authkey was correct, False if incorrect and Null if not provided
     * @throws Exception
     */
    private function __loginByAuthKey()
    {<commit_msg>fix: [internal] Check if user is logged after checking if it is ajax request<commit_after><?php
App::uses('ConnectionManager', 'Model');
App::uses('Controller', 'Controller');
App::uses('File', 'Utility');
App::uses('RequestRearrangeTool', 'Tools');
App::uses('BlowfishConstantPasswordHasher', 'Controller/Component/Auth');
App::uses('BetterCakeEventManager', 'Tools');

/**
 * Application Controller
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @package       app.Controller
 * @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
 *
 * @property ACLComponent $ACL
 * @property RestResponseComponent $RestResponse
 * @property CRUDComponent $CRUD
 * @property IndexFilterComponent $IndexFilter
 * @property RateLimitComponent $RateLimit
 * @property CompressedRequestHandlerComponent $CompressedRequestHandler
 * @property DeprecationComponent $Deprecation
 * @property RestSearchComponent $RestSearch
 * @property BetterSecurityComponent $Security
 */
class AppController extends Controller
{
    /**
     * @var string
     * @deprecated Use modelClass instead
     */
    public $defaultModel = '';

    public $helpers = array('OrgImg', 'FontAwesome', 'UserName');

    private $__queryVersion = '145';
    public $pyMispVersion = '2.4.162';
    public $phpmin = '7.2';
    public $phprec = '7.4';
    public $phptoonew = '8.0';
    public $pythonmin = '3.6';
    public $pythonrec = '3.7';
    private $isApiAuthed = false;

    public $baseurl = '';
    public $sql_dump = false;

    public $restResponsePayload = null;

    protected $_legacyParams = array();
    /** @var array */
    public $userRole;

    /** @var User */
    public $User;

    public function __construct($request = null, $response = null)
    {
        parent::__construct($request, $response);
        $this->defaultModel = $this->modelClass;
    }

    public $components = array(
        'Session',
        'Auth' => array(
            'authError' => 'Unauthorised access.',
            'authenticate' => array(
                'Form' => array(
                    'passwordHasher' => '<PASSWORD>',
                    'fields' => array(
                        'username' => 'email'
                    )
                )
            )
        ),
        'Security' => [
            'className' => 'BetterSecurity',
        ],
        'ACL',
        'CompressedRequestHandler',
        'RestResponse',
        'Flash',
        'Toolbox',
        'RateLimit',
        'IndexFilter',
        'Deprecation',
        'RestSearch',
        'CRUD'
        //,'DebugKit.Toolbar'
    );

    public function beforeFilter()
    {
        if (Configure::read('MISP.system_setting_db')) {
            App::uses('SystemSetting', 'Model');
            SystemSetting::setGlobalSetting();
        }

        $this->_setupBaseurl();
        $this->Auth->loginRedirect = $this->baseurl . '/users/routeafterlogin';

        $customLogout = Configure::read('Plugin.CustomAuth_custom_logout');
        $this->Auth->logoutRedirect = $customLogout ?: ($this->baseurl . '/users/login');

        $this->__sessionMassage();

        // If server is running behind reverse proxy, PHP will not recognize that user is accessing site by HTTPS connection.
        // By setting `Security.force_https` to `true`, session cookie will be set as Secure and CSP headers will upgrade insecure requests.
        if (Configure::read('Security.force_https')) {
            $_SERVER['HTTPS'] = 'on';
        }
        $this->__cors();
        if (Configure::read('Security.check_sec_fetch_site_header')) {
            $secFetchSite = $this->request->header('Sec-Fetch-Site');
            if ($secFetchSite !== false && $secFetchSite !== 'same-origin' && ($this->request->is('post') || $this->request->is('put') || $this->request->is('ajax'))) {
                throw new MethodNotAllowedException("POST, PUT and AJAX requests are allowed just from same origin.");
            }
        }
        if (Configure::read('Security.disable_browser_cache')) {
            $this->response->disableCache();
        }
        if (!$this->_isRest()) {
            $this->__contentSecurityPolicy();
            $this->response->header('X-XSS-Protection', '1; mode=block');
        }

        if (!empty($this->request->params['named']['sql'])) {
            $this->sql_dump = intval($this->request->params['named']['sql']);
        }

        $this->_setupDatabaseConnection();

        $this->set('debugMode', Configure::read('debug') >= 1 ? 'debugOn' : 'debugOff');
        $isAjax = $this->request->is('ajax');
        $this->set('ajax', $isAjax);
        $this->set('queryVersion', $this->__queryVersion);
        $this->User = ClassRegistry::init('User');

        $language = Configure::read('MISP.language');
        if (!empty($language) && $language !== 'eng') {
            Configure::write('Config.language', $language);
        } else {
            Configure::write('Config.language', 'eng');
        }

        // For fresh installation (salt empty) generate a new salt
        if (!Configure::read('Security.salt')) {
            $this->User->Server->serverSettingsSaveValue('Security.salt', $this->User->generateRandomPassword(32));
        }

        // Check if the instance has a UUID, if not assign one.
        if (!Configure::read('MISP.uuid')) {
            $this->User->Server->serverSettingsSaveValue('MISP.uuid', CakeText::uuid());
        }

        // Check if Apache provides kerberos authentication data
        $authUserFields = $this->User->describeAuthFields();
        $envvar = Configure::read('ApacheSecureAuth.apacheEnv');
        if ($envvar && isset($_SERVER[$envvar])) {
            $this->Auth->className = 'ApacheSecureAuth';
            $this->Auth->authenticate = array(
                'Apache' => array(
                    // envvar = field returned by Apache if user is authenticated
                    'fields' => array('username' => 'email', 'envvar' => $envvar),
                    'userFields' => $authUserFields,
                )
            );
        } else {
            $this->Auth->authenticate[AuthComponent::ALL]['userFields'] = $authUserFields;
        }
        if (!empty($this->request->params['named']['disable_background_processing'])) {
            Configure::write('MISP.background_jobs', 0);
        }
        Configure::write('CurrentController', $this->request->params['controller']);
        Configure::write('CurrentAction', $this->request->params['action']);
        $versionArray = $this->User->checkMISPVersion();
        $this->mispVersion = implode('.', $versionArray);
        $this->Security->blackHoleCallback = 'blackHole';

        // send users away that are using ancient versions of IE
        // Make sure to update this if IE 20 comes out :)
        if (isset($_SERVER['HTTP_USER_AGENT'])) {
            if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT']) && !strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
                throw new MethodNotAllowedException('You are using an unsecure and outdated version of IE, please download Google Chrome, Mozilla Firefox or update to a newer version of IE. If you are running IE9 or newer and still receive this error message, please make sure that you are not running your browser in compatibility mode. If you still have issues accessing the site, get in touch with your administration team at ' . Configure::read('MISP.contact'));
            }
        }
        $userLoggedIn = false;
        if (Configure::read('Plugin.CustomAuth_enable')) {
            $userLoggedIn = $this->__customAuthentication($_SERVER);
        }
        if ($this->_isRest()) {
            $jsonDecode = function ($dataToDecode) {
                if (empty($dataToDecode)) {
                    return null;
                }
                return $this->_jsonDecode($dataToDecode);
            };
            //  Throw exception if JSON in request is invalid. Default CakePHP behaviour would just ignore that error.
            $this->RequestHandler->addInputType('json', [$jsonDecode]);
            $this->Security->unlockedActions = array($this->request->action);
            $this->Security->doNotGenerateToken = true;
        }

        if (
            !$userLoggedIn &&
            (
                $this->request->params['controller'] !== 'users' ||
                $this->request->params['action'] !== 'register' ||
                empty(Configure::read('Security.allow_self_registration'))
            )
        ) {
            // REST authentication
            if ($this->_isRest() || $this->_isAutomation()) {
                // disable CSRF for REST access
                $this->Security->csrfCheck = false;
                if ($this->__loginByAuthKey() === false || $this->Auth->user() === null) {
                    if ($this->__loginByAuthKey() === null) {
                        $this->loadModel('Log');
                        $this->Log->createLogEntry('SYSTEM', 'auth_fail', 'User', 0, "Failed API authentication. No authkey was provided.");
                    }
                    throw new ForbiddenException('Authentication failed. Please make sure you pass the API key of an API enabled user along in the Authorization header.');
                }
            } elseif (!$this->Session->read(AuthComponent::$sessionKey)) {
                $this->_loadAuthenticationPlugins();
            }
        }

        $user = $this->Auth->user();
        if ($user) {
            Configure::write('CurrentUserId', $user['id']);
            $this->__logAccess($user);

            // Try to run updates
            if ($user['Role']['perm_site_admin'] || (!$this->_isRest() && !$isAjax && $this->_isLive())) {
                $this->User->runUpdates();
            }

            // Put username to response header for webserver or proxy logging
            if (Configure::read('Security.username_in_response_header')) {
                $headerValue = $user['email'];
                if (isset($user['logged_by_authkey']) && $user['logged_by_authkey']) {
                    $headerValue .= isset($user['authkey_id']) ? "/API/{$user['authkey_id']}" :  '/API/default';
                }
                $this->response->header('X-Username', $headerValue);
                $this->RestResponse->setHeader('X-Username', $headerValue);
            }

            if (!$this->__verifyUser($user))  {
                $this->_stop(); // just for sure
            }
            $user = $this->Auth->user(); // user info in session could change (see __verifyUser) method, so reload user variable

            if (isset($user['logged_by_authkey']) && $user['logged_by_authkey'] && !($this->_isRest() || $this->_isAutomation())) {
                throw new ForbiddenException("When user is authenticated by authkey, just REST request can be processed.");
            }

            // Put token expiration time to response header that can be processed by automation tool
            if (isset($user['authkey_expiration']) && $user['authkey_expiration']) {
                $expiration = date('c', $user['authkey_expiration']);
                $this->response->header('X-Auth-Key-Expiration', $expiration);
                $this->RestResponse->setHeader('X-Auth-Key-Expiration', $expiration);
            }

            $this->set('default_memory_limit', ini_get('memory_limit'));
            if (isset($user['Role']['memory_limit']) && $user['Role']['memory_limit'] !== '') {
                 ini_set('memory_limit', $user['Role']['memory_limit']);
            }
            $this->set('default_max_execution_time', ini_get('max_execution_time'));
            if (isset($user['Role']['max_execution_time']) && $user['Role']['max_execution_time'] !== '') {
                ini_set('max_execution_time', $user['Role']['max_execution_time']);
            }

            $this->set('mispVersion', "{$versionArray['major']}.{$versionArray['minor']}.0");
            $this->set('mispVersionFull', $this->mispVersion);
            $this->set('me', $user);
            $role = $user['Role'];
            $this->set('isAdmin', $role['perm_admin']);
            $this->set('isSiteAdmin', $role['perm_site_admin']);
            $this->set('hostOrgUser', $user['org_id'] == Configure::read('MISP.host_org_id'));
            $this->set('isAclAdd', $role['perm_add']);
            $this->set('isAclModify', $role['perm_modify']);
            $this->set('isAclModifyOrg', $role['perm_modify_org']);
            $this->set('isAclPublish', $role['perm_publish']);
            $this->set('isAclDelegate', $role['perm_delegate']);
            $this->set('isAclSync', $role['perm_sync']);
            $this->set('isAclAdmin', $role['perm_admin']);
            $this->set('isAclAudit', $role['perm_audit']);
            $this->set('isAclAuth', $role['perm_auth']);
            $this->set('isAclRegexp', $role['perm_regexp_access']);
            $this->set('isAclTagger', $role['perm_tagger']);
            $this->set('isAclTagEditor', $role['perm_tag_editor']);
            $this->set('isAclTemplate', $role['perm_template']);
            $this->set('isAclGalaxyEditor', !empty($role['perm_galaxy_editor']));
            $this->set('isAclSharingGroup', $role['perm_sharing_group']);
            $this->set('isAclSighting', $role['perm_sighting'] ?? false);
            $this->set('isAclZmq', $role['perm_publish_zmq'] ?? false);
            $this->set('isAclKafka', $role['perm_publish_kafka'] ?? false);
            $this->set('isAclDecaying', $role['perm_decaying'] ?? false);
            $this->set('aclComponent', $this->ACL);
            $this->userRole = $role;

            $this->__accessMonitor($user);

        } else {
            $preAuthActions = array('login', 'register', 'getGpgPublicKey');
            if (!empty(Configure::read('Security.email_otp_enabled'))) {
                $preAuthActions[] = 'email_otp';
            }
            if (!$this->_isControllerAction(['users' => $preAuthActions, 'servers' => ['cspReport']])) {
                if ($isAjax) {
                    $response = $this->RestResponse->throwException(401, "Unauthorized");
                    $response->send();
                    $this->_stop();
                } else {
                    $this->Session->write('pre_login_requested_url', $this->request->here);
                    $this->_redirectToLogin();
                }
            }
            $this->set('me', false);
        }

        if ($user && $this->_isSiteAdmin()) {
            if (Configure::read('Session.defaults') === 'database') {
                $db = ConnectionManager::getDataSource('default');
                $sqlResult = $db->query('SELECT COUNT(id) AS session_count FROM cake_sessions WHERE expires < ' . time() . ';');
                if (isset($sqlResult[0][0]['session_count']) && $sqlResult[0][0]['session_count'] > 1000) {
                    $this->User->Server->updateDatabase('cleanSessionTable');
                }
            }
            if (Configure::read('site_admin_debug') && Configure::read('debug') < 2) {
                Configure::write('debug', 1);
            }
        }

        $this->ACL->checkAccess($user, Inflector::variable($this->request->params['controller']), $this->request->action);
        if ($user && $this->_isRest()) {
            $this->__rateLimitCheck($user);
        }
        if ($this->modelClass !== 'CakeError') {
            $deprecationWarnings = $this->Deprecation->checkDeprecation($this->request->params['controller'], $this->request->action, $this->User, $user ? $user['id'] : null);
            if ($deprecationWarnings) {
                $deprecationWarnings = __('WARNING: This functionality is deprecated and will be removed in the near future. ') . $deprecationWarnings;
                if ($this->_isRest()) {
                    $this->response->header('X-Deprecation-Warning', $deprecationWarnings);
                    $this->RestResponse->setHeader('X-Deprecation-Warning', $deprecationWarnings);
                } else {
                    $this->Flash->warning($deprecationWarnings);
                }
            }
        }
    }

    public function beforeRender()
    {
        // Notifications and homepage is not necessary for AJAX or REST requests
        if (!$this->_isRest() && isset($this->User) && !$this->request->is('ajax')) {
            $user = $this->Auth->user();
            if (!$user) {
                return;
            }
            $hasNotifications = $this->User->hasNotifications($user);
            $this->set('hasNotifications', $hasNotifications);

            $homepage = $this->User->UserSetting->getValueForUser($user['id'], 'homepage');
            if (!empty($homepage)) {
                $this->set('homepage', $homepage);
            }
            if (PHP_MAJOR_VERSION >= 8) {
                $this->Flash->error(__('WARNING: MISP is currently running under PHP 8.0, which is unsupported. Background jobs will fail, so please contact your administrator to run a supported PHP version (such as 7.4)'));
            }
        }
    }

    /**
     * @return null|bool True if authkey was correct, False if incorrect and Null if not provided
     * @throws Exception
     */
    private function __loginByAuthKey()
    {
{'fraction_non_alphanumeric': 0.16168722135371433, 'fraction_numerical': 0.002895026344739737, 'mean_word_length': 2.363813419028143, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 445, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4531470', 'n_tokens_mistral': 9635, 'n_tokens_neox': 9294, 'n_words': 1881}