diff options
Diffstat (limited to 'app/Controller/Base.php')
-rw-r--r-- | app/Controller/Base.php | 263 |
1 files changed, 115 insertions, 148 deletions
diff --git a/app/Controller/Base.php b/app/Controller/Base.php index a8e22fd8..fcd07b99 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -2,166 +2,171 @@ namespace Controller; -use Core\Tool; -use Core\Registry; +use Pimple\Container; use Core\Security; +use Core\Request; +use Core\Response; +use Core\Template; +use Core\Session; use Model\LastLogin; +use Symfony\Component\EventDispatcher\Event; /** * Base controller * * @package controller * @author Frederic Guillot - * - * @property \Model\Acl $acl - * @property \Model\Authentication $authentication - * @property \Model\Action $action - * @property \Model\Board $board - * @property \Model\Category $category - * @property \Model\Color $color - * @property \Model\Comment $comment - * @property \Model\Config $config - * @property \Model\File $file - * @property \Model\LastLogin $lastLogin - * @property \Model\Notification $notification - * @property \Model\Project $project - * @property \Model\ProjectPermission $projectPermission - * @property \Model\SubTask $subTask - * @property \Model\Task $task - * @property \Model\TaskHistory $taskHistory - * @property \Model\TaskExport $taskExport - * @property \Model\TaskFinder $taskFinder - * @property \Model\TaskPermission $taskPermission - * @property \Model\TaskValidator $taskValidator - * @property \Model\CommentHistory $commentHistory - * @property \Model\SubtaskHistory $subtaskHistory - * @property \Model\TimeTracking $timeTracking - * @property \Model\User $user - * @property \Model\Webhook $webhook */ -abstract class Base +abstract class Base extends \Core\Base { /** * Request instance * - * @accesss public + * @accesss protected * @var \Core\Request */ - public $request; + protected $request; /** * Response instance * - * @accesss public + * @accesss protected * @var \Core\Response */ - public $response; - - /** - * Template instance - * - * @accesss public - * @var \Core\Template - */ - public $template; - - /** - * Session instance - * - * @accesss public - * @var \Core\Session - */ - public $session; - - /** - * Registry instance - * - * @access private - * @var \Core\Registry - */ - private $registry; + protected $response; /** * Constructor * * @access public - * @param \Core\Registry $registry Registry instance + * @param \Pimple\Container $container */ - public function __construct(Registry $registry) + public function __construct(Container $container) { - $this->registry = $registry; + $this->container = $container; + $this->request = new Request; + $this->response = new Response; + + if (DEBUG) { + $this->container['logger']->debug('START_REQUEST='.$_SERVER['REQUEST_URI']); + } } /** - * Load automatically models + * Destructor * * @access public - * @param string $name Model name - * @return mixed */ - public function __get($name) + public function __destruct() { - return Tool::loadModel($this->registry, $name); + if (DEBUG) { + + foreach ($this->container['db']->getLogMessages() as $message) { + $this->container['logger']->debug($message); + } + + $this->container['logger']->debug('SQL_QUERIES={nb}', array('nb' => $this->container['db']->nb_queries)); + $this->container['logger']->debug('RENDERING={time}', array('time' => microtime(true) - @$_SERVER['REQUEST_TIME_FLOAT'])); + $this->container['logger']->debug('END_REQUEST='.$_SERVER['REQUEST_URI']); + } } /** - * Method executed before each action + * Send HTTP headers * - * @access public + * @access private */ - public function beforeAction($controller, $action) + private function sendHeaders($action) { - // Start the session - $this->session->open(BASE_URL_DIRECTORY, SESSION_SAVE_PATH); - // HTTP secure headers - $this->response->csp(array('style-src' => "'self' 'unsafe-inline'")); + $this->response->csp(array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '*')); $this->response->nosniff(); $this->response->xss(); // Allow the public board iframe inclusion - if ($action !== 'readonly') { + if (ENABLE_XFRAME && $action !== 'readonly') { $this->response->xframe(); } if (ENABLE_HSTS) { $this->response->hsts(); } + } + + /** + * Method executed before each action + * + * @access public + */ + public function beforeAction($controller, $action) + { + // Start the session + $this->session->open(BASE_URL_DIRECTORY); + $this->sendHeaders($action); + $this->container['dispatcher']->dispatch('session.bootstrap', new Event); - $this->config->setupTranslations(); - $this->config->setupTimezone(); + if (! $this->acl->isPublicAction($controller, $action)) { + $this->handleAuthentication(); + $this->handle2FA($controller, $action); + $this->handleAuthorization($controller, $action); - // Authentication - if (! $this->authentication->isAuthenticated($controller, $action)) { - $this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString())); + $this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId()); } + } - // Check if the user is allowed to see this page - if (! $this->acl->isPageAccessAllowed($controller, $action)) { - $this->response->redirect('?controller=user&action=forbidden'); + /** + * Check authentication + * + * @access public + */ + public function handleAuthentication() + { + if (! $this->authentication->isAuthenticated()) { + + if ($this->request->isAjax()) { + $this->response->text('Not Authorized', 401); + } + + $this->response->redirect($this->helper->url->to('auth', 'login', array('redirect_query' => urlencode($this->request->getQueryString())))); } + } - // Attach events - $this->attachEvents(); + /** + * Check 2FA + * + * @access public + */ + public function handle2FA($controller, $action) + { + $ignore = ($controller === 'twofactor' && in_array($action, array('code', 'check'))) || ($controller === 'auth' && $action === 'logout'); + + if ($ignore === false && $this->userSession->has2FA() && ! $this->userSession->check2FA()) { + + if ($this->request->isAjax()) { + $this->response->text('Not Authorized', 401); + } + + $this->response->redirect($this->helper->url->to('twofactor', 'code')); + } } /** - * Attach events + * Check page access and authorization * - * @access private + * @access public */ - private function attachEvents() + public function handleAuthorization($controller, $action) { - $models = array( - 'projectActivity', // Order is important - 'action', - 'project', - 'webhook', - 'notification', - ); - - foreach ($models as $model) { - $this->$model->attachEvents(); + $project_id = $this->request->getIntegerParam('project_id'); + $task_id = $this->request->getIntegerParam('task_id'); + + // Allow urls without "project_id" + if ($task_id > 0 && $project_id === 0) { + $project_id = $this->taskFinder->getProjectId($task_id); + } + + if (! $this->acl->isAllowed($controller, $action, $project_id)) { + $this->forbidden(); } } @@ -173,7 +178,7 @@ abstract class Base */ public function notfound($no_layout = false) { - $this->response->html($this->template->layout('app_notfound', array( + $this->response->html($this->template->layout('app/notfound', array( 'title' => t('Page not found'), 'no_layout' => $no_layout, ))); @@ -187,7 +192,7 @@ abstract class Base */ public function forbidden($no_layout = false) { - $this->response->html($this->template->layout('app_forbidden', array( + $this->response->html($this->template->layout('app/forbidden', array( 'title' => t('Access Forbidden'), 'no_layout' => $no_layout, ))); @@ -206,19 +211,6 @@ abstract class Base } /** - * Check if the current user have access to the given project - * - * @access protected - * @param integer $project_id Project id - */ - protected function checkProjectPermissions($project_id) - { - if ($this->acl->isRegularUser() && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) { - $this->forbidden(); - } - } - - /** * Redirection when there is no project in the database * * @access protected @@ -239,14 +231,12 @@ abstract class Base */ protected function taskLayout($template, array $params) { - if (isset($params['task']) && $this->taskPermission->canRemoveTask($params['task']) === false) { - $params['hide_remove_menu'] = true; - } - - $content = $this->template->load($template, $params); + $content = $this->template->render($template, $params); $params['task_content_for_layout'] = $content; + $params['title'] = $params['task']['project_name'].' > '.$params['task']['title']; + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); - return $this->template->layout('task_layout', $params); + return $this->template->layout('task/layout', $params); } /** @@ -257,13 +247,15 @@ abstract class Base * @param array $params Template parameters * @return string */ - protected function projectLayout($template, array $params) + protected function projectLayout($template, array $params, $sidebar_template = 'project/sidebar') { - $content = $this->template->load($template, $params); + $content = $this->template->render($template, $params); $params['project_content_for_layout'] = $content; - $params['menu'] = 'projects'; + $params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' > '.$params['title']; + $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId()); + $params['sidebar_template'] = $sidebar_template; - return $this->template->layout('project_layout', $params); + return $this->template->layout('project/layout', $params); } /** @@ -276,12 +268,10 @@ abstract class Base { $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); - if (! $task) { + if (empty($task)) { $this->notfound(); } - $this->checkProjectPermissions($task['project_id']); - return $task; } @@ -297,34 +287,11 @@ abstract class Base $project_id = $this->request->getIntegerParam('project_id', $project_id); $project = $this->project->getById($project_id); - if (! $project) { + if (empty($project)) { $this->session->flashError(t('Project not found.')); $this->response->redirect('?controller=project'); } - $this->checkProjectPermissions($project['id']); - - return $project; - } - - /** - * Common method to get a project with administration rights - * - * @access protected - * @return array - */ - protected function getProjectManagement() - { - $project = $this->project->getById($this->request->getIntegerParam('project_id')); - - if (! $project) { - $this->notfound(); - } - - if ($this->acl->isRegularUser() && ! $this->projectPermission->adminAllowed($project['id'], $this->acl->getUserId())) { - $this->forbidden(); - } - return $project; } } |