Loading restrict_route_by_ip.services.yml +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ services: - '@current_route_match' - '@entity_type.manager' - '@router.route_provider' - '@messenger' restrict_route_by_ip.route_subscriber: class: Drupal\restrict_route_by_ip\Routing\RouteSubscriber Loading src/Routing/RouteSubscriber.php +8 −4 Original line number Diff line number Diff line Loading @@ -33,14 +33,18 @@ class RouteSubscriber extends RouteSubscriberBase { */ protected function alterRoutes(RouteCollection $collection) { $routes = $this->restrictRouteService->getAllRestrictedRoutes(); $route_names = array_column($routes, 'route_names'); $route_names = array_reduce($route_names, 'array_merge', array()); // Restrict asset on all routes from configurations. foreach($routes as $route_name) { if (!empty($route_names)) { foreach($route_names as $route_name) { if ($route = $collection->get($route_name)) { $route->setRequirement('_custom_access', 'restrict_route_by_ip.services_access_checker::access'); $route->setOption('no_cache', TRUE); } } } } } src/Service/RestrictIpInterface.php +16 −1 Original line number Diff line number Diff line Loading @@ -37,8 +37,23 @@ interface RestrictIpInterface { * Get all enabled restricted routes. * * @return array * List of all routes. * List of all routes. (route example : * [ * 'restricted_route_id' => $entity->id(), * 'route_names' => $this->getRouteNames($path_or_route_name) * ] */ public function getAllRestrictedRoutes(): array; /** * Get a restricted route by route name. * * @param string $route_name * Route name to search a restricted route. * * @return string * The restricted route id or NULLa */ public function getRestrictedRouteId(string $route_name); } src/Service/RestrictIpService.php +105 −17 Original line number Diff line number Diff line Loading @@ -5,10 +5,12 @@ namespace Drupal\restrict_route_by_ip\Service; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\PageCache\ResponsePolicy\KillSwitch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteProvider; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\restrict_route_by_ip\Entity\RestrictRouteByIp; use Symfony\Component\HttpFoundation\RequestStack; Loading Loading @@ -66,6 +68,20 @@ class RestrictIpService implements RestrictIpInterface { */ protected $routeProvider; /** * Drupal Messenger service. * * @var \Drupal\Core\Messenger\MessengerInterface */ protected $messenger; /** * All definied routes. * * @var array */ protected $allRoutes; /** * Constructor. * Loading @@ -83,6 +99,8 @@ class RestrictIpService implements RestrictIpInterface { * Drupal EntityTypeManager service. * @param \Drupal\Core\Routing\RouteProvider $route_provider * Drupal RouteProvider service. * @param \Drupal\Core\Messenger\MessengerInterface $messenger * Drupal RouteProvider service. */ public function __construct( ConfigFactory $config, Loading @@ -91,7 +109,8 @@ class RestrictIpService implements RestrictIpInterface { LoggerChannelFactoryInterface $logger_factory, RouteMatchInterface $current_route_match, EntityTypeManagerInterface $entity_type_manager, RouteProvider $route_provider) { RouteProvider $route_provider, MessengerInterface $messenger) { $this->configManager = $config; $this->currentRequest = $request_stack_service->getCurrentRequest(); $this->pageCacheKillSwitch = $page_cache_kill_switch; Loading @@ -99,8 +118,11 @@ class RestrictIpService implements RestrictIpInterface { $this->routeMatch = $current_route_match; $this->restrictRouteStorage = $entity_type_manager->getStorage('restrict_route'); $this->routeProvider = $route_provider; $this->messenger = $messenger; } use StringTranslationTrait; /** * {@inheritdoc} */ Loading Loading @@ -144,10 +166,7 @@ class RestrictIpService implements RestrictIpInterface { */ public function userIpIsRestricted(AccountInterface $account): bool { $current_route_name = $this->routeMatch->getRouteName(); $routes = $this->getAllRestrictedRoutes(); // Searching for restricted route name. $restricted_route_id = array_search($current_route_name, $routes); $restricted_route_id = $this->getRestrictedRouteId($current_route_name); $restricted = FALSE; if ($restricted_route_id) { // Load the current restricted route entity. Loading Loading @@ -177,6 +196,20 @@ class RestrictIpService implements RestrictIpInterface { return $restricted; } /** * {@inheritdoc} */ public function getRestrictedRouteId(string $route_name) { $restricted_route_id = NULL; $all_restricted_routes = $this->getAllRestrictedRoutes(); foreach($all_restricted_routes as $route) { if (array_search($route_name, $route['route_names']) !== FALSE) { $restricted_route_id = $route['restricted_route_id']; } } return $restricted_route_id; } /** * {@inheritdoc} */ Loading @@ -189,8 +222,11 @@ class RestrictIpService implements RestrictIpInterface { /** @var \Drupal\restrict_route_by_ip\Entity\RestrictRouteInterface $entity */ foreach($entities as $entity) { $route = $entity->getRoute(); $routes[$entity->id()] = $this->getRouteName($route); $restricted_route_name = $entity->getRoute(); $routes[] = [ 'restricted_route_id' => $entity->id(), 'route_names' => $this->getRouteNames($restricted_route_name) ]; } return $routes; } Loading @@ -198,22 +234,74 @@ class RestrictIpService implements RestrictIpInterface { /** * Get the route name if route is a path. * * @param string $route * A route name or a path. * @param string $restricted_route_name * A route name or a path or a regular expression. * * @return string * A route name. */ protected function getRouteName(string $route): string { $route_name = $route; if (strpos($route, '/') !== FALSE) { $route_collection = $this->routeProvider->getRoutesByPattern($route); $routes = $route_collection->all(); if (!empty($routes) && count($routes) > 0) { $route_name = key($routes); protected function getRouteNames(string $restricted_route_name): array { $route_names = []; $regex = ''; // If the restricted route is a regex. if (substr($restricted_route_name, 0, 1) === '#' && substr($restricted_route_name, -1, 1) === '#') { $regex = $restricted_route_name; } // A path is defined, so check path by regex. if (empty($regex) && strpos($restricted_route_name, '/') !== FALSE) { $regex = $this->getRegularExpressionFromPath($restricted_route_name); } // Use regex to define impacted route names. if (!empty($regex)) { if (empty($this->allRoutes)) { $this->allRoutes = $this->routeProvider->getAllRoutes(); } foreach($this->allRoutes as $route_name => $route) { $route_path = $route->getPath(); $route_path = preg_replace('#(\{[_\-0-9a-zA-Z]+\})#', 'rrbip_replaced', $route_path); $match = []; $check_expression = @preg_match($regex, $route_path, $match); if ($check_expression === FALSE) { $this->messenger->addWarning($this->t('Invalid regular expression: @regex', [ '@regex' => $regex ])); break; } if ($check_expression) { $route_names[] = $route_name; } } } else { // if it's not a regex or a path, set the route name directly in array. $route_names[] = $restricted_route_name; } return $route_names; } /** * Use a path to define a regex applicable on routes. * * @param string $path * A path. * * @return string * A regex */ protected function getRegularExpressionFromPath(string $path): string { $regex = $path; // If there is a Wildcard "%" in path, replace by ".+" if (strpos($regex, '%') !== FALSE) { $regex = str_replace('%', '.+', $regex); } return $route_name; return '#'.$regex.'#'; } } Loading
restrict_route_by_ip.services.yml +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ services: - '@current_route_match' - '@entity_type.manager' - '@router.route_provider' - '@messenger' restrict_route_by_ip.route_subscriber: class: Drupal\restrict_route_by_ip\Routing\RouteSubscriber Loading
src/Routing/RouteSubscriber.php +8 −4 Original line number Diff line number Diff line Loading @@ -33,14 +33,18 @@ class RouteSubscriber extends RouteSubscriberBase { */ protected function alterRoutes(RouteCollection $collection) { $routes = $this->restrictRouteService->getAllRestrictedRoutes(); $route_names = array_column($routes, 'route_names'); $route_names = array_reduce($route_names, 'array_merge', array()); // Restrict asset on all routes from configurations. foreach($routes as $route_name) { if (!empty($route_names)) { foreach($route_names as $route_name) { if ($route = $collection->get($route_name)) { $route->setRequirement('_custom_access', 'restrict_route_by_ip.services_access_checker::access'); $route->setOption('no_cache', TRUE); } } } } }
src/Service/RestrictIpInterface.php +16 −1 Original line number Diff line number Diff line Loading @@ -37,8 +37,23 @@ interface RestrictIpInterface { * Get all enabled restricted routes. * * @return array * List of all routes. * List of all routes. (route example : * [ * 'restricted_route_id' => $entity->id(), * 'route_names' => $this->getRouteNames($path_or_route_name) * ] */ public function getAllRestrictedRoutes(): array; /** * Get a restricted route by route name. * * @param string $route_name * Route name to search a restricted route. * * @return string * The restricted route id or NULLa */ public function getRestrictedRouteId(string $route_name); }
src/Service/RestrictIpService.php +105 −17 Original line number Diff line number Diff line Loading @@ -5,10 +5,12 @@ namespace Drupal\restrict_route_by_ip\Service; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\PageCache\ResponsePolicy\KillSwitch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteProvider; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\restrict_route_by_ip\Entity\RestrictRouteByIp; use Symfony\Component\HttpFoundation\RequestStack; Loading Loading @@ -66,6 +68,20 @@ class RestrictIpService implements RestrictIpInterface { */ protected $routeProvider; /** * Drupal Messenger service. * * @var \Drupal\Core\Messenger\MessengerInterface */ protected $messenger; /** * All definied routes. * * @var array */ protected $allRoutes; /** * Constructor. * Loading @@ -83,6 +99,8 @@ class RestrictIpService implements RestrictIpInterface { * Drupal EntityTypeManager service. * @param \Drupal\Core\Routing\RouteProvider $route_provider * Drupal RouteProvider service. * @param \Drupal\Core\Messenger\MessengerInterface $messenger * Drupal RouteProvider service. */ public function __construct( ConfigFactory $config, Loading @@ -91,7 +109,8 @@ class RestrictIpService implements RestrictIpInterface { LoggerChannelFactoryInterface $logger_factory, RouteMatchInterface $current_route_match, EntityTypeManagerInterface $entity_type_manager, RouteProvider $route_provider) { RouteProvider $route_provider, MessengerInterface $messenger) { $this->configManager = $config; $this->currentRequest = $request_stack_service->getCurrentRequest(); $this->pageCacheKillSwitch = $page_cache_kill_switch; Loading @@ -99,8 +118,11 @@ class RestrictIpService implements RestrictIpInterface { $this->routeMatch = $current_route_match; $this->restrictRouteStorage = $entity_type_manager->getStorage('restrict_route'); $this->routeProvider = $route_provider; $this->messenger = $messenger; } use StringTranslationTrait; /** * {@inheritdoc} */ Loading Loading @@ -144,10 +166,7 @@ class RestrictIpService implements RestrictIpInterface { */ public function userIpIsRestricted(AccountInterface $account): bool { $current_route_name = $this->routeMatch->getRouteName(); $routes = $this->getAllRestrictedRoutes(); // Searching for restricted route name. $restricted_route_id = array_search($current_route_name, $routes); $restricted_route_id = $this->getRestrictedRouteId($current_route_name); $restricted = FALSE; if ($restricted_route_id) { // Load the current restricted route entity. Loading Loading @@ -177,6 +196,20 @@ class RestrictIpService implements RestrictIpInterface { return $restricted; } /** * {@inheritdoc} */ public function getRestrictedRouteId(string $route_name) { $restricted_route_id = NULL; $all_restricted_routes = $this->getAllRestrictedRoutes(); foreach($all_restricted_routes as $route) { if (array_search($route_name, $route['route_names']) !== FALSE) { $restricted_route_id = $route['restricted_route_id']; } } return $restricted_route_id; } /** * {@inheritdoc} */ Loading @@ -189,8 +222,11 @@ class RestrictIpService implements RestrictIpInterface { /** @var \Drupal\restrict_route_by_ip\Entity\RestrictRouteInterface $entity */ foreach($entities as $entity) { $route = $entity->getRoute(); $routes[$entity->id()] = $this->getRouteName($route); $restricted_route_name = $entity->getRoute(); $routes[] = [ 'restricted_route_id' => $entity->id(), 'route_names' => $this->getRouteNames($restricted_route_name) ]; } return $routes; } Loading @@ -198,22 +234,74 @@ class RestrictIpService implements RestrictIpInterface { /** * Get the route name if route is a path. * * @param string $route * A route name or a path. * @param string $restricted_route_name * A route name or a path or a regular expression. * * @return string * A route name. */ protected function getRouteName(string $route): string { $route_name = $route; if (strpos($route, '/') !== FALSE) { $route_collection = $this->routeProvider->getRoutesByPattern($route); $routes = $route_collection->all(); if (!empty($routes) && count($routes) > 0) { $route_name = key($routes); protected function getRouteNames(string $restricted_route_name): array { $route_names = []; $regex = ''; // If the restricted route is a regex. if (substr($restricted_route_name, 0, 1) === '#' && substr($restricted_route_name, -1, 1) === '#') { $regex = $restricted_route_name; } // A path is defined, so check path by regex. if (empty($regex) && strpos($restricted_route_name, '/') !== FALSE) { $regex = $this->getRegularExpressionFromPath($restricted_route_name); } // Use regex to define impacted route names. if (!empty($regex)) { if (empty($this->allRoutes)) { $this->allRoutes = $this->routeProvider->getAllRoutes(); } foreach($this->allRoutes as $route_name => $route) { $route_path = $route->getPath(); $route_path = preg_replace('#(\{[_\-0-9a-zA-Z]+\})#', 'rrbip_replaced', $route_path); $match = []; $check_expression = @preg_match($regex, $route_path, $match); if ($check_expression === FALSE) { $this->messenger->addWarning($this->t('Invalid regular expression: @regex', [ '@regex' => $regex ])); break; } if ($check_expression) { $route_names[] = $route_name; } } } else { // if it's not a regex or a path, set the route name directly in array. $route_names[] = $restricted_route_name; } return $route_names; } /** * Use a path to define a regex applicable on routes. * * @param string $path * A path. * * @return string * A regex */ protected function getRegularExpressionFromPath(string $path): string { $regex = $path; // If there is a Wildcard "%" in path, replace by ".+" if (strpos($regex, '%') !== FALSE) { $regex = str_replace('%', '.+', $regex); } return $route_name; return '#'.$regex.'#'; } }