_register_route('/urls', [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_rules' ] ], self::PERMISSIONS); // Define new URL permission $this->_register_route('/urls', [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [ $this, 'create_rule' ], 'args' => array( 'url_schema' => array( 'description' => 'URL schema', 'type' => 'string', 'required' => true ), 'effect' => array( 'description' => 'Wether allow or deny access to URL', 'type' => 'string', 'required' => true, 'enum' => [ 'allow', 'deny' ] ), 'redirect' => [ 'type' => 'object', 'required' => false, 'properties' => [ 'type' => [ 'description' => 'Redirect type', 'type' => 'string', 'required' => true ], 'message' => [ 'description' => 'Custom access denied message', 'type' => 'string', 'validate_callback' => function ($value, $request) { return $this->_validate_message( $value, $request ); } ], 'redirect_page_id' => [ 'description' => 'Existing page ID to redirect to', 'type' => 'number', 'validate_callback' => function ($value, $request) { return $this->_validate_redirect_page_id( $value, $request ); } ], 'redirect_url' => [ 'description' => 'Valid URL to redirect to', 'type' => 'string', 'validate_callback' => function ($value, $request) { return $this->_validate_redirect_url( $value, $request ); } ], 'callback' => array( 'description' => 'Custom callback function', 'type' => 'string', 'validate_callback' => function ($value, $request) { return $this->_validate_callback( $value, $request ); } ), 'http_status_code' => [ 'description' => 'HTTP Status Code', 'type' => 'number' ] ] ] ) ], self::PERMISSIONS); // Get a permission $this->_register_route('/url/(?P[A-Za-z0-9\/\+=]+)', [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_rule' ], 'args' => array( 'id' => array( 'description' => 'Base64 encoded URL schema', 'type' => 'string', 'required' => true ) ) ], self::PERMISSIONS); // Update an existing permission $this->_register_route('/url/(?P[A-Za-z0-9\/\+=]+)', [ 'methods' => WP_REST_Server::EDITABLE, 'callback' => array($this, 'update_rule'), 'args' => array( 'id' => array( 'description' => 'Based64 encoded URL schema', 'type' => 'string', 'required' => true ), 'url_schema' => array( 'description' => 'New URL schema', 'type' => 'string', 'required' => false ), 'effect' => array( 'description' => 'Wether allow or deny access to URL', 'type' => 'string', 'required' => true, 'enum' => [ 'allow', 'deny' ] ), 'redirect' => [ 'type' => 'object', 'required' => false, 'properties' => [ 'type' => [ 'description' => 'Redirect type', 'type' => 'string' ], 'message' => [ 'description' => 'Custom access denied message', 'type' => 'string', 'validate_callback' => function ($value, $request) { return $this->_validate_message( $value, $request ); } ], 'redirect_page_id' => [ 'description' => 'Existing page ID to redirect to', 'type' => 'number', 'validate_callback' => function ($value, $request) { return $this->_validate_redirect_page_id( $value, $request ); } ], 'redirect_url' => [ 'description' => 'Valid URL to redirect to', 'type' => 'string', 'validate_callback' => function ($value, $request) { return $this->_validate_redirect_url( $value, $request ); } ], 'callback' => array( 'description' => 'Custom callback function', 'type' => 'string', 'validate_callback' => function ($value, $request) { return $this->_validate_callback( $value, $request ); } ), 'http_status_code' => [ 'description' => 'HTTP Status Code', 'type' => 'number' ] ] ] ) ], self::PERMISSIONS); // Delete a permission $this->_register_route('/url/(?P[A-Za-z0-9\/\+=]+)', [ 'methods' => WP_REST_Server::DELETABLE, 'callback' => [ $this, 'delete_rule' ], 'args' => array( 'id' => array( 'description' => 'Base64 encoded URL schema', 'type' => 'string', 'required' => true ) ) ], self::PERMISSIONS); // Reset all permissions $this->_register_route('/urls', [ 'methods' => WP_REST_Server::DELETABLE, 'callback' => [ $this, 'reset' ] ], self::PERMISSIONS); }); } /** * Get list of all defined URL permissions * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.6 */ public function get_rules(WP_REST_Request $request) { try { $result = $this->_get_permissions($request); } catch(Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Create new permission for given URL * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.6 */ public function create_rule(WP_REST_Request $request) { try { $service = $this->_get_service($request); // Grab all the necessary permission attributes $url_schema = AAM::api()->misc->sanitize_url( $request->get_param('url_schema') ); $effect = strtolower($request->get_param('effect')); $redirect = $request->get_param('redirect'); // Persist the permission if ($effect === 'allow') { $service->allow($url_schema); } else { $service->deny($url_schema, $redirect); } // Prepare the response $result = $this->_prepare_output( $url_schema, $this->_find_permission_by_id(base64_encode($url_schema), $request), true ); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get a rule * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.6 */ public function get_rule(WP_REST_Request $request) { try { // Prepare result $result = $this->_prepare_output( base64_decode($request->get_param('id')), $this->_find_permission_by_id($request->get_param('id'), $request), true ); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Update permissions for a specific URL * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.6 */ public function update_rule(WP_REST_Request $request) { try { $service = $this->_get_service($request); // Get all the necessary attributes $original_url = base64_decode($request->get_param('id')); $new_url = $request->get_param('url_schema'); $redirect = $request->get_param('redirect'); $effect = strtolower($request->get_param('effect')); // If we are updating URL, then first, let's delete the original rule if (!empty($new_url) && ($original_url !== $new_url)) { $service->reset($original_url); } // Now we are settings permission for the given URL $url_schema = AAM::api()->misc->sanitize_url( !empty($new_url) ? $new_url : $original_url ); if ($effect === 'allow') { $service->allow($url_schema); } else { $service->deny($url_schema, $redirect); } // Prepare the response $result = $this->_prepare_output( $url_schema, $this->_find_permission_by_id(base64_encode($url_schema), $request), true ); } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Delete permission for a given URL * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.6 */ public function delete_rule(WP_REST_Request $request) { try { $service = $this->_get_service($request); $url_schema = base64_decode($request->get_param('id')); // Reset the permission $service->reset($url_schema); // Prepare the result $result = [ 'success' => true ]; } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Reset permissions to all URLs * * @param WP_REST_Request $request * * @return WP_REST_Response * @access public * * @version 7.0.6 */ public function reset(WP_REST_Request $request) { try { $service = $this->_get_service($request); // Reset all permissions $service->reset(); // Prepare the result $result = [ 'success' => true ]; } catch (Exception $e) { $result = $this->_prepare_error_response($e); } return rest_ensure_response($result); } /** * Get complete list of defined permissions * * @param WP_REST_Request $request * * @return array * @access private * * @version 7.0.0 */ private function _get_permissions($request) { $result = []; $access_level = $this->_determine_access_level($request); $resource = $access_level->get_resource( AAM_Framework_Type_Resource::URL ); foreach($resource->get_permissions() as $url => $permissions) { array_push($result, $this->_prepare_output( $url, $permissions['access'], $resource->is_customized($url) )); } return $result; } /** * Find permission by ID * * @param string $id * @param WP_REST_Request $request * * @return array * @access private * * @version 7.0.0 */ private function _find_permission_by_id($id, $request) { $permissions = array_filter( $this->_get_permissions($request), function($p) use ($id) { return $p['id'] === $id; } ); if (empty($permissions)) { throw new OutOfRangeException('Permission does not exist'); } return array_shift($permissions); } /** * Validate custom message * * @param string $value * @param WP_REST_Request $request * * @return boolean|WP_Error * @access private * * @version 7.0.6 */ private function _validate_message($value, $request) { $response = true; $redirect = $request->get_param('redirect'); $rule_type = !empty($redirect['type']) ? $redirect['type'] : null; $message = esc_js(trim($value)); if ($rule_type === 'custom_message' && strlen($message) === 0) { $response = new WP_Error( 'rest_invalid_param', 'The custom_message cannot be empty or be unsafe', [ 'status' => 400 ] ); } return $response; } /** * Validate redirect page ID * * @param int $value * @param WP_REST_Request $request * * @return boolean|WP_Error * @access private * * @version 7.0.6 */ private function _validate_redirect_page_id($value, $request) { $response = true; $redirect = $request->get_param('redirect'); $rule_type = !empty($redirect['type']) ? $redirect['type'] : null; $page_id = intval($value); if ($rule_type === 'page_redirect') { if ($page_id === 0 || get_post($page_id) === null) { $response = new WP_Error( 'rest_invalid_param', 'The redirect_page_id refers to non-existing page', [ 'status' => 400 ] ); } } return $response; } /** * Validate redirect URL * * @param string $value * @param WP_REST_Request $request * * @return boolean|WP_Error * @access private * * @version 7.0.6 */ private function _validate_redirect_url($value, $request) { $response = true; $redirect = $request->get_param('redirect'); $rule_type = !empty($redirect['type']) ? $redirect['type'] : null; $url = AAM::api()->misc->sanitize_url($value); if ($rule_type === 'url_redirect' && empty($url)) { $response = new WP_Error( 'rest_invalid_param', 'The redirect_url is not valid URL', array('status' => 400) ); } return $response; } /** * Validate the callback value * * @param string $value * @param WP_REST_Request $request * * @return boolean|WP_Error * @access private * * @version 7.0.6 */ private function _validate_callback($value, $request) { $response = true; $redirect = $request->get_param('redirect'); $rule_type = !empty($redirect['type']) ? $redirect['type'] : null; if ($rule_type === 'trigger_callback' && is_callable($value, true) === false ) { $response = new WP_Error( 'rest_invalid_param', 'The callback is not valid PHP callback', [ 'status' => 400 ] ); } return $response; } /** * Prepare the URL permission model * * This method prepares the URL model so it can be effectively used by RESTful * API * * @param string $url_schema * @param array $permission * @param bool $is_customized * * @return array * @access private * * @version 7.0.0 */ private function _prepare_output($url_schema, $permission, $is_customized) { return array_merge([ 'id' => base64_encode($url_schema), 'url_schema' => $url_schema, 'is_customized' => $is_customized ], $permission); } /** * Get service * * @param WP_REST_Request $request * * @return AAM_Framework_Service_Urls * @access private * * @version 7.0.0 */ private function _get_service(WP_REST_Request $request) { return AAM::api()->urls( $this->_determine_access_level($request), [ 'error_handling' => 'exception' ] ); } }