array( self::ACTION_DISPLAY_ADMIN_MENU => array( 'controller' => 'Dashboard_Controller', 'action' => 'show_dashboard_page', 'method' => array( 'GET' ), 'middleware' => array( 'admin', 'account_exists' ) ), self::ACTION_CREATE_ACCOUNT => array( 'controller' => 'Account_Controller', 'action' => 'create_account', 'method' => array( 'GET', 'POST' ), 'middleware' => array( 'admin', 'account_not_exists', 'nonce' ) ), self::ACTION_RESET_PASSWORD => array( 'controller' => 'Account_Controller', 'action' => 'reset_password', 'method' => array( 'GET', 'POST' ), 'middleware' => array( 'admin', 'account_not_exists', 'nonce' ) ), self::ACTION_LOGIN => array( 'controller' => 'Account_Controller', 'action' => 'login', 'method' => array( 'GET', 'POST' ), 'middleware' => array( 'admin', 'account_not_exists', 'nonce' ) ), self::ACTION_LOGOUT => array( 'controller' => 'Account_Controller', 'action' => 'logout', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_ENABLE_PLUGIN => array( 'controller' => 'Dashboard_Controller', 'action' => 'enable_plugin', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_DISABLE_PLUGIN => array( 'controller' => 'Dashboard_Controller', 'action' => 'disable_plugin', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_UPGRADE_PLAN => array( 'controller' => 'Dashboard_Controller', 'action' => 'upgrade_to_premium', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_DOWNGRADE_PLAN => array( 'controller' => 'Dashboard_Controller', 'action' => 'downgrade_to_basic', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_DEFAULT => array( 'controller' => 'Dashboard_Controller', 'action' => 'show_dashboard_page', 'method' => array( 'GET' ), 'middleware' => array( 'admin', 'account_exists' ) ), ), self::SUBMENU_SETTINGS => array( self::ACTION_DISPLAY_SETTINGS => array( 'controller' => 'Settings_Controller', 'action' => 'show_settings_page', 'method' => array( 'GET' ), 'middleware' => array( 'admin', 'account_exists' ) ), self::ACTION_SAVE_ROLES => array( 'controller' => 'Settings_Controller', 'action' => 'save_roles', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_SAVE_LOGGING => array( 'controller' => 'Settings_Controller', 'action' => 'save_logging', 'method' => array( 'POST' ), 'middleware' => array( 'admin', 'account_exists', 'nonce' ) ), self::ACTION_DEFAULT => array( 'controller' => 'Settings_Controller', 'action' => 'show_settings_page', 'method' => array( 'GET' ), 'middleware' => array( 'admin', 'account_exists' ) ) ), self::SUBMENU_CHANNEL => array( self::ACTION_CONFIGURE_TOTP => array( 'controller' => 'Totp_Configuration_Controller', 'action' => 'configure', 'method' => array( 'GET', 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce' ) ), self::ACTION_ENABLE_TOTP => array( 'controller' => 'Totp_Configuration_Controller', 'action' => 'enable', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce' ) ), self::ACTION_DISABLE_TOTP => array( 'controller' => 'Totp_Configuration_Controller', 'action' => 'disable', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce' ) ), self::ACTION_REMOVE_TOTP_CONFIGURATION => array( 'controller' => 'Totp_Configuration_Controller', 'action' => 'remove_configuration', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'nonce' ) ), self::ACTION_RELOAD_QR_CODE => array( 'controller' => 'Totp_Configuration_Controller', 'action' => 'reload', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'nonce' ) ), self::ACTION_REQUEST_AUTH_VIA_SMS => array( 'controller' => 'Sms_Configuration_Controller', 'action' => 'request_auth_via_sms', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'premium_plan', 'second_factor_enabled', 'nonce' ) ), self::ACTION_CONFIGURE_SMS => array( 'controller' => 'Sms_Configuration_Controller', 'action' => 'configure', 'method' => array( 'GET', 'POST' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'premium_plan', 'second_factor_enabled', 'nonce' ) ), self::ACTION_ENABLE_SMS => array( 'controller' => 'Sms_Configuration_Controller', 'action' => 'enable', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'premium_plan', 'second_factor_enabled', 'nonce' ) ), self::ACTION_DISABLE_SMS => array( 'controller' => 'Sms_Configuration_Controller', 'action' => 'disable', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce' ) ), self::ACTION_REMOVE_SMS_CONFIGURATION => array( 'controller' => 'Sms_Configuration_Controller', 'action' => 'remove_configuration', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'nonce' ) ), self::ACTION_CONFIGURE_OFFLINE_CODES => array( 'controller' => 'Offline_Codes_Configuration_Controller', 'action' => 'show_offline_codes', 'method' => array( 'GET' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'second_factor_enabled' ) ), self::ACTION_GENERATE_OFFLINE_CODES => array( 'controller' => 'Offline_Codes_Configuration_Controller', 'action' => 'generate', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'second_factor_enabled', 'nonce' ) ), self::ACTION_ENABLE_OFFLINE_CODES => array( 'controller' => 'Offline_Codes_Configuration_Controller', 'action' => 'enable', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'second_factor_enabled', 'nonce' ) ), self::ACTION_DISABLE_OFFLINE_CODES => array( 'controller' => 'Offline_Codes_Configuration_Controller', 'action' => 'disable', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce' ) ), self::ACTION_PRINT_OFFLINE_CODES => array( 'controller' => 'Offline_Codes_Configuration_Controller', 'action' => 'print_codes', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'second_factor_enabled', 'nonce' ) ), self::ACTION_DISPLAY_TRUSTED_DEVICES => array( 'controller' => 'Trusted_Devices_Controller', 'action' => 'show_trusted_devices', 'method' => array( 'GET' ), 'middleware' => array( 'user', 'account_exists', 'integration_user', 'second_factor_enabled' ) ), self::ACTION_ADD_TRUSTED_DEVICE => array( 'controller' => 'Trusted_Devices_Controller', 'action' => 'add_trusted_device', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'second_factor_enabled', 'nonce' ) ), self::ACTION_REMOVE_TRUSTED_DEVICE => array( 'controller' => 'Trusted_Devices_Controller', 'action' => 'remove_trusted_device', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce' ) ), self::ACTION_DISABLE_RELOAD_MODAL => array( 'controller' => 'Modal_Controller', 'action' => 'disable_reload', 'method' => array( 'POST' ), 'middleware' => array( 'user', 'account_exists', 'nonce', 'ajax' ) ), self::ACTION_DEFAULT => array( 'controller' => 'Totp_Configuration_Controller', 'action' => 'configure', 'method' => array( 'GET' ), 'middleware' => array( 'user', 'account_exists' ) ), ), self::SUBMENU_AJAX => array( self::ACTION_AUTHENTICATE_CHANNEL => array( 'controller' => 'Channel_Controller', 'action' => 'authenticate', 'method' => array( 'POST' ), 'middleware' => array( 'nonce' ) ), ) ); /** * @param Request $request * @param Controller_Factory $controller_factory * @param Middleware_Bag $middleware_bag * @param Error_Handler $error_handler */ public function __construct( Request $request, Controller_Factory $controller_factory, Middleware_Bag $middleware_bag, Error_Handler $error_handler ) { $this->request = $request; $this->controller_factory = $controller_factory; $this->middleware_bag = $middleware_bag; $this->error_handler = $error_handler; } /** * @return array */ public function get_routes() { return $this->routes; } /** * @return View_Response|Redirection_Response|JSON_Response * * @throws Exception */ public function create_response() { $page = $this->request->page(); $action = $this->request->action(); $method = $this->request->http_method(); if ( empty( $action ) ) { $action = self::ACTION_DEFAULT; } if ( ! $this->can_process_route( $page ) || ! $this->route_exists( $page, $action ) ) { return new View_Response( Views::NOT_FOUND ); } if ( ! $this->method_allowed( $page, $action, $method ) ) { if ( $this->request->is_ajax() ) { return new JSON_Response( array( 'error' => 'Method not allowed.', ), 405 ); } else { return new View_Response( Views::NOT_ALLOWED ); } } $route = $this->match( $page, $action ); $controller = $this->create_controller( $route['controller'] ); $middleware = $this->create_middleware( $controller, $route ); return $middleware->handle(); } /** * @param Exception $e * * @return JSON_Response|View_Response */ public function create_error_response( Exception $e ) { $handler = $this->error_handler->capture_exception( $e ); if ( $this->request->is_ajax() ) { return $handler->to_json( $e ); } return $handler->to_view( $e ); } /** * @param string $page * * @return bool */ private function can_process_route( $page ) { if ( empty( $page ) ) { return false; } return array_key_exists( $page, $this->routes ); } /** * @param string $page * @param string $action * @param string $method * * @return bool */ private function method_allowed( $page, $action, $method ) { return in_array( $method, $this->routes[ $page ][ $action ]['method'], true ); } /** * @param string $page * @param string $action * * @return array */ private function match( $page, $action ) { return array( 'controller' => $this->routes[ $page ][ $action ]['controller'], 'action' => $this->routes[ $page ][ $action ]['action'], 'middleware' => $this->routes[ $page ][ $action ]['middleware'] ); } /** * @param string $page * @param string $action * * @return bool */ private function route_exists( $page, $action ) { return array_key_exists( $page, $this->routes ) && array_key_exists( $action, $this->routes[ $page ] ); } /** * @param string $controller_name * * @return Controller * * @throws LogicException */ private function create_controller( $controller_name ) { return $this->controller_factory->create( $controller_name ); } /** * @param Controller $controller * @param array $route * * @return Middleware_Interface * * @throws LogicException */ private function create_middleware( Controller $controller, array $route ) { $all_middleware = $this->middleware_bag->get_middleware(); $ordered_middleware = array_map( function ( $middleware_name ) use ( $all_middleware ) { if ( array_key_exists( $middleware_name, $all_middleware ) ) { return $all_middleware[ $middleware_name ]; } throw new LogicException( 'Some middleware\'s does not exist.' ); }, $route['middleware'] ); $ordered_middleware[] = new Create_Response( $this->request, $controller, $route['action'] ); $first = array_shift( $ordered_middleware ); array_reduce( $ordered_middleware, function ( Middleware_Interface $current, Middleware_Interface $next ) { $current->add_next( $next ); return $next; }, $first ); return $first; } }