Skip to content

Commit

Permalink
Adding detailed mode to occ security:routes
Browse files Browse the repository at this point in the history
  • Loading branch information
DeepDiver1975 committed Sep 11, 2017
1 parent 2d0c2d0 commit 2fe7c7d
Showing 1 changed file with 138 additions and 21 deletions.
159 changes: 138 additions & 21 deletions core/Command/Security/ListRoutes.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@

namespace OC\Core\Command\Security;

use OC\AppFramework\App;
use OC\Core\Command\Base;
use OC\Route\Route;
use OC\Route\Router;
use OCP\ICertificate;
use OCP\Route\IRouter;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class ListRoutes extends Base {
Expand All @@ -44,7 +46,8 @@ public function __construct(IRouter $router) {
protected function configure() {
$this
->setName('security:routes')
->setDescription('list used routes');
->setDescription('list used routes')
->addOption('with-details', 'd', InputOption::VALUE_NONE);
parent::configure();
}

Expand All @@ -56,40 +59,154 @@ protected function execute(InputInterface $input, OutputInterface $output) {

$rows = [];

foreach ($this->router->getCollections() as $routeCollection) {
foreach ($routeCollection as $route) {
$path = $route->getPath();
if (isset($rows[$path])) {
$rows[$path]['methods'] = array_unique(array_merge($rows[$path]['methods'], $route->getMethods()));
} else {
$rows[$path] = [
'path' => $path,
'methods' => $route->getMethods()
];
if ($input->getOption('with-details')) {
$headers = [
'Path',
'Methods',
'Controller',
'Annotations',
];
/** @var Route[] $collections */
$collections = [];
foreach ($this->router->getCollections() as $c) {
$new = $c->all();
$collections = $collections + $new;
}

foreach ($collections as $name => $route) {
$c = $this->buildController($name);
$rows[] = array_merge([
'path' => $route->getPath(),
'methods' => $route->getMethods()
], $c);
}
} else {
$headers = [
'Path',
'Methods'
];
foreach ($this->router->getCollections() as $routeCollection) {
foreach ($routeCollection as $route) {
$path = $route->getPath();
if (isset($rows[$path])) {
$rows[$path]['methods'] = array_unique(array_merge($rows[$path]['methods'], $route->getMethods()));
} else {
$rows[$path] = [
'path' => $path,
'methods' => $route->getMethods()
];
}
sort ($rows[$path]['methods']);
}
sort ($rows[$path]['methods']);
}
}

usort($rows, function ($a, $b) {
return strcmp($a['path'], $b['path']);
});
$rows = array_map(function($row) {
$row['methods'] = implode(',', $row['methods']);
return $row;
}, $rows);

if ($outputType === self::OUTPUT_FORMAT_JSON ) {
$output->write(json_encode($rows));
} else if ($outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
$output->writeln(json_encode($rows, JSON_PRETTY_PRINT));
} else {
$table = new Table($output);
$table->setHeaders([
'Path',
'Methods',
]);
$table->setHeaders($headers);

foreach ($rows as $row) {
$table->addRow([$row['path'], join(',', $row['methods'])]);
}
$table->addRows($rows);
$table->render();
}
}

private function buildController($name) {
$parts = explode('.', $name);
if (count($parts) === 4 && $parts[0] === 'ocs') {
array_shift($parts);
}
if (count($parts) !== 3) {
return [
'controllerClass' => '*** not controller based ***'
];
}
$appName = $parts[0];
$controllerName = $parts[1];
$method = $parts[2];
$reflection = $this->buildReflection($appName, $controllerName, $method);
if ($reflection === null) {
return [
'controllerClass' => '*** controller not resolvable ***'
];
}
$docs = $reflection->getDocComment();

// extract everything prefixed by @ and first letter uppercase
preg_match_all('/@([A-Z]\w+)/', $docs, $matches);
$annotations = $matches[1];

return [
'controllerClass' => $reflection->getDeclaringClass()->getName() . '::' . $reflection->getName(),
'annotations' => implode(',', $annotations),
];
}

/**
* @param string $appName
* @param string $controllerName
* @param string $method
* @return null|\ReflectionMethod
*/
private function buildReflection($appName, $controllerName, $method) {
foreach ($this->listControllerNames($appName, $controllerName) as $controllerName) {
foreach ($this->listMethodNames($method) as $m) {
try {
$reflection = new \ReflectionMethod($controllerName, $m);
return $reflection;
} catch (\ReflectionException $ex) {
}
}
}
return null;
}

/**
* @param string $appName
* @param string $controllerName
* @return \Generator | string[]
*/
private function listControllerNames($appName, $controllerName) {
foreach ([App::buildAppNamespace($appName), App::buildAppNamespace($appName, 'OC\\')] as $appNameSpace) {
foreach (['\\Controller\\', '\\Controllers\\'] as $namespace) {
yield $appNameSpace . $namespace . $controllerName;
yield $appNameSpace . $namespace . ucfirst(strtolower($controllerName));
yield $appNameSpace . $namespace . $controllerName . 'Controller';
yield $appNameSpace . $namespace . ucfirst(strtolower($controllerName)) . 'Controller';
$controllerName = implode('', array_map(function ($word) {
return ucfirst($word);
}, explode('_', $controllerName)));
yield $appNameSpace . $namespace . $controllerName;
yield $appNameSpace . $namespace . ucfirst(strtolower($controllerName));
yield $appNameSpace . $namespace . $controllerName . 'Controller';
yield $appNameSpace . $namespace . ucfirst(strtolower($controllerName)) . 'Controller';
}
}
}

/**
* @param string $method
* @return \Generator | string[]
*/
private function listMethodNames($method) {
yield $method;
yield implode('', explode('_', $method));
foreach (['post', 'put'] as $verb) {
if (substr( $method, -strlen($verb)) == $verb) {
yield substr($method, 0, -strlen($verb));
yield implode('', explode('_', substr($method, 0, -strlen($verb))));
}
}
}

}

0 comments on commit 2fe7c7d

Please sign in to comment.