Permalink
Browse files

added initial code

  • Loading branch information...
0 parents commit e9a1e92b9772a2eecc8d1b87afff542989ee1bde @fabpot fabpot committed Feb 1, 2013
Showing with 219 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +19 −0 LICENSE
  3. +19 −0 README.md
  4. +65 −0 SensioLabs/Security/Command/SecurityCheckerCommand.php
  5. +80 −0 SensioLabs/Security/SecurityChecker.php
  6. +12 −0 checker
  7. +22 −0 composer.json
@@ -0,0 +1,2 @@
+composer.lock
+/vendor/
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
@@ -0,0 +1,19 @@
+SensioLabs Security Checker
+===========================
+
+The SensioLabs Security Checker is a command line tool that checks if your
+application use dependencies with known security vulnerabilities. It uses the
+[SensioLabs Security Check Web service][1] and the [Security Advisories Database][2]
+behind the scene:
+
+ $ php checker security:check /path/to/composer.lock
+
+You can also integrate the checker in your own application/project
+
+ * by using the `SecurityCheckerCommand` class into your Symfony Console
+ application.
+
+ * by using the `SecurityChecker` class directly into your own code.
+
+[1]: http://security.sensiolabs.org/
+[2]: https://github.com/sensiolabs/security-advisories
@@ -0,0 +1,65 @@
+<?php
+
+namespace SensioLabs\Security\Command;
+
+use SensioLabs\Security\SecurityChecker;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+
+class SecurityCheckerCommand extends Command
+{
+ private $checker;
+
+ public function __construct(SecurityChecker $checker)
+ {
+ $this->checker = $checker;
+
+ parent::__construct();
+ }
+
+ /**
+ * @see Command
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('security:check')
+ ->setDefinition(array(
+ new InputArgument('lock', InputArgument::REQUIRED, 'The path to the composer.lock file'),
+ new InputOption('format', '', InputOption::VALUE_REQUIRED, 'The output format', 'text'),
+ ))
+ ->setDescription('Checks security issues in your project dependencies')
+ ->setHelp(<<<EOF
+The <info>%command.name%</info> command checks a <info>composer.lock</info>
+file for security issues in the project dependencies:
+
+<info>php %command.full_name% security:check /path/to/composer.lock</info>
+
+By default, the command displays the result in plain text, but you can also
+configure it to output JSON instead by using the <info>--format</info> option:
+
+<info>php %command.full_name% security:check /path/to/composer.lock --format=json</info>
+EOF
+ );
+ }
+
+ /**
+ * @see Command
+ * @see SecurityChecker
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ try {
+ $data = $this->checker->check($input->getArgument('lock'), $input->getOption('format'));
+ } catch (\Exception $e) {
+ $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error', true));
+
+ return 1;
+ }
+
+ $output->write($data);
+ }
+}
@@ -0,0 +1,80 @@
+<?php
+
+namespace SensioLabs\Security;
+
+class SecurityChecker
+{
+ /**
+ * Checks a composer.lock file.
+ *
+ * @param string $lock The path to the composer.lock file
+ * @param string $format The return format
+ *
+ * @return mixed The vulnerabilities
+ *
+ * @throws \InvalidArgumentException When the output format is unsupported
+ * @throws \RuntimeException When the lock file does not exist
+ * @throws \RuntimeException When curl does not work or is unavailable
+ */
+ public function check($lock, $format = 'text')
+ {
+ if (!function_exists('curl_init')) {
+ throw new \RuntimeException('Curl is required to use this command.');
+ }
+
+ if (false === $curl = curl_init()) {
+ throw new \RuntimeException('Unable to create a new curl handle.');
+ }
+
+ if (is_dir($lock) && file_exists($lock.'/composer.lock')) {
+ $lock = $lock.'/composer.lock';
+ }
+
+ if (!is_file($lock)) {
+ throw new \RuntimeException('Lock file does not exist.');
+ }
+
+ switch ($format) {
+ case 'text':
+ $format = 'text/plain';
+ break;
+ case 'json':
+ $format = 'application/json';
+ break;
+ default:
+ throw new \InvalidArgumentException(sprintf('Unsupported format "%s".', $format));
+ }
+
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_HEADER, false);
+ curl_setopt($curl, CURLOPT_URL, 'https://security.sensiolabs.org/check_lock');
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: '.$format));
+ curl_setopt($curl, CURLOPT_POSTFIELDS, array('lock' => '@'.$lock));
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
+ curl_setopt($curl, CURLOPT_TIMEOUT, 10);
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($curl, CURLOPT_MAXREDIRS, 3);
+ curl_setopt($curl, CURLOPT_FAILONERROR, false);
+
+ $data = curl_exec($curl);
+
+ if (false === $data) {
+ $error = curl_error($curl);
+ curl_close($curl);
+
+ throw new \RuntimeException(sprintf('An error occured: %s.', $error));
+ }
+
+ if (400 == curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
+ throw new \InvalidArgumentException(sprintf('The web service failed with the following error: %s.', $data['error']));
@schmittjoh

schmittjoh Feb 19, 2013

Contributor

There is something wrong here, $data is always a string at this point. I guess there is a json_decode missing although I don't know if the server always returns json for error responses even if text/plain was requested?

+ }
+
+ if (200 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
+ throw new \RuntimeException('The web service failed for an unknown reason.');
+ }
+
+ curl_close($curl);
+
+ return $data;
+ }
+}
12 checker
@@ -0,0 +1,12 @@
+#!/usr/bin/env php
+<?php
+
+require_once __DIR__.'/vendor/autoload.php';
+
+use Symfony\Component\Console\Application;
+use SensioLabs\Security\Command\SecurityCheckerCommand;
+use SensioLabs\Security\SecurityChecker;
+
+$console = new Application('SensioLabs Security Checker', '1.0');
+$console->add(new SecurityCheckerCommand(new SecurityChecker()));
+$console->run();
@@ -0,0 +1,22 @@
+{
+ "name": "sensiolabs/security-checker",
+ "description": "A security checker for your composer.lock",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien.potencier@gmail.com"
+ }
+ ],
+ "require": {
+ "symfony/console": "~2.0"
+ },
+ "bin": ["checker"],
+ "autoload": {
+ "psr-0": { "SensioLabs\\Security": "" }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ }
+}

0 comments on commit e9a1e92

Please sign in to comment.