diff options
-rw-r--r-- | core/command/integrity/signapp.php | 25 | ||||
-rw-r--r-- | core/register_command.php | 3 | ||||
-rw-r--r-- | lib/private/integritycheck/checker.php | 11 | ||||
-rw-r--r-- | tests/lib/command/integrity/SignAppTest.php | 32 | ||||
-rw-r--r-- | tests/lib/integritycheck/checkertest.php | 9 |
5 files changed, 47 insertions, 33 deletions
diff --git a/core/command/integrity/signapp.php b/core/command/integrity/signapp.php index a203b9ad1da..53df9619c6d 100644 --- a/core/command/integrity/signapp.php +++ b/core/command/integrity/signapp.php @@ -23,6 +23,7 @@ namespace OC\Core\Command\Integrity; use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\FileAccessHelper; +use OCP\IURLGenerator; use phpseclib\Crypt\RSA; use phpseclib\File\X509; use Symfony\Component\Console\Command\Command; @@ -40,23 +41,28 @@ class SignApp extends Command { private $checker; /** @var FileAccessHelper */ private $fileAccessHelper; + /** @var IURLGenerator */ + private $urlGenerator; /** * @param Checker $checker * @param FileAccessHelper $fileAccessHelper + * @param IURLGenerator $urlGenerator */ public function __construct(Checker $checker, - FileAccessHelper $fileAccessHelper) { + FileAccessHelper $fileAccessHelper, + IURLGenerator $urlGenerator) { parent::__construct(null); $this->checker = $checker; $this->fileAccessHelper = $fileAccessHelper; + $this->urlGenerator = $urlGenerator; } protected function configure() { $this ->setName('integrity:sign-app') - ->setDescription('Sign app using a private key.') - ->addOption('appId', null, InputOption::VALUE_REQUIRED, 'Application to sign') + ->setDescription('Signs an app using a private key.') + ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Application to sign') ->addOption('privateKey', null, InputOption::VALUE_REQUIRED, 'Path to private key to use for signing') ->addOption('certificate', null, InputOption::VALUE_REQUIRED, 'Path to certificate to use for signing'); } @@ -65,11 +71,14 @@ class SignApp extends Command { * {@inheritdoc } */ protected function execute(InputInterface $input, OutputInterface $output) { - $appId = $input->getOption('appId'); + $path = $input->getOption('path'); $privateKeyPath = $input->getOption('privateKey'); $keyBundlePath = $input->getOption('certificate'); - if(is_null($appId) || is_null($privateKeyPath) || is_null($keyBundlePath)) { - $output->writeln('--appId, --privateKey and --certificate are required.'); + if(is_null($path) || is_null($privateKeyPath) || is_null($keyBundlePath)) { + $documentationUrl = $this->urlGenerator->linkToDocs('developer-code-integrity'); + $output->writeln('This command requires the --path, --privateKey and --certificate.'); + $output->writeln('Example: ./occ integrity:sign-app --path="/Users/lukasreschke/Programming/myapp/" --privateKey="/Users/lukasreschke/private/myapp.key" --certificate="/Users/lukasreschke/public/mycert.crt"'); + $output->writeln('For more information please consult the documentation: '. $documentationUrl); return null; } @@ -91,8 +100,8 @@ class SignApp extends Command { $x509 = new X509(); $x509->loadX509($keyBundle); $x509->setPrivateKey($rsa); - $this->checker->writeAppSignature($appId, $x509, $rsa); + $this->checker->writeAppSignature($path, $x509, $rsa); - $output->writeln('Successfully signed "'.$appId.'"'); + $output->writeln('Successfully signed "'.$path.'"'); } } diff --git a/core/register_command.php b/core/register_command.php index e43994530b9..5f9a2675873 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -36,7 +36,8 @@ $application->add(new OC\Core\Command\App\CheckCode($infoParser)); $application->add(new OC\Core\Command\L10n\CreateJs()); $application->add(new \OC\Core\Command\Integrity\SignApp( \OC::$server->getIntegrityCodeChecker(), - new \OC\IntegrityCheck\Helpers\FileAccessHelper() + new \OC\IntegrityCheck\Helpers\FileAccessHelper(), + \OC::$server->getURLGenerator() )); $application->add(new \OC\Core\Command\Integrity\SignCore( \OC::$server->getIntegrityCodeChecker(), diff --git a/lib/private/integritycheck/checker.php b/lib/private/integritycheck/checker.php index 0cd01df7fe1..926a7725ff3 100644 --- a/lib/private/integritycheck/checker.php +++ b/lib/private/integritycheck/checker.php @@ -114,6 +114,7 @@ class Checker { * * @param string $folderToIterate * @return \RecursiveIteratorIterator + * @throws \Exception */ private function getFolderIterator($folderToIterate) { $dirItr = new \RecursiveDirectoryIterator( @@ -189,17 +190,19 @@ class Checker { } /** - * Write the signature of the specified app + * Write the signature of the app in the specified folder * - * @param string $appId + * @param string $path * @param X509 $certificate * @param RSA $privateKey * @throws \Exception */ - public function writeAppSignature($appId, + public function writeAppSignature($path, X509 $certificate, RSA $privateKey) { - $path = $this->appLocator->getAppPath($appId); + if(!is_dir($path)) { + throw new \Exception('Directory does not exist.'); + } $iterator = $this->getFolderIterator($path); $hashes = $this->generateHashes($iterator, $path); $signature = $this->createSignatureData($hashes, $certificate, $privateKey); diff --git a/tests/lib/command/integrity/SignAppTest.php b/tests/lib/command/integrity/SignAppTest.php index b7c34585c5c..44a644c45df 100644 --- a/tests/lib/command/integrity/SignAppTest.php +++ b/tests/lib/command/integrity/SignAppTest.php @@ -23,6 +23,7 @@ namespace Test\Command\Integrity; use OC\Core\Command\Integrity\SignApp; use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\FileAccessHelper; +use OCP\IURLGenerator; use Test\TestCase; class SignAppTest extends TestCase { @@ -32,6 +33,8 @@ class SignAppTest extends TestCase { private $signApp; /** @var FileAccessHelper */ private $fileAccessHelper; + /** @var IURLGenerator */ + private $urlGenerator; public function setUp() { parent::setUp(); @@ -39,20 +42,23 @@ class SignAppTest extends TestCase { ->disableOriginalConstructor()->getMock(); $this->fileAccessHelper = $this->getMockBuilder('\OC\IntegrityCheck\Helpers\FileAccessHelper') ->disableOriginalConstructor()->getMock(); + $this->urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator') + ->disableOriginalConstructor()->getMock(); $this->signApp = new SignApp( $this->checker, - $this->fileAccessHelper + $this->fileAccessHelper, + $this->urlGenerator ); } - public function testExecuteWithMissingAppId() { + public function testExecuteWithMissingPath() { $inputInterface = $this->getMock('\Symfony\Component\Console\Input\InputInterface'); $outputInterface = $this->getMock('\Symfony\Component\Console\Output\OutputInterface'); $inputInterface ->expects($this->at(0)) ->method('getOption') - ->with('appId') + ->with('path') ->will($this->returnValue(null)); $inputInterface ->expects($this->at(1)) @@ -68,7 +74,7 @@ class SignAppTest extends TestCase { $outputInterface ->expects($this->at(0)) ->method('writeln') - ->with('--appId, --privateKey and --certificate are required.'); + ->with('This command requires the --path, --privateKey and --certificate.'); $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]); } @@ -80,7 +86,7 @@ class SignAppTest extends TestCase { $inputInterface ->expects($this->at(0)) ->method('getOption') - ->with('appId') + ->with('path') ->will($this->returnValue('AppId')); $inputInterface ->expects($this->at(1)) @@ -94,9 +100,9 @@ class SignAppTest extends TestCase { ->will($this->returnValue('Certificate')); $outputInterface - ->expects($this->at(0)) - ->method('writeln') - ->with('--appId, --privateKey and --certificate are required.'); + ->expects($this->at(0)) + ->method('writeln') + ->with('This command requires the --path, --privateKey and --certificate.'); $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]); } @@ -108,7 +114,7 @@ class SignAppTest extends TestCase { $inputInterface ->expects($this->at(0)) ->method('getOption') - ->with('appId') + ->with('path') ->will($this->returnValue('AppId')); $inputInterface ->expects($this->at(1)) @@ -124,7 +130,7 @@ class SignAppTest extends TestCase { $outputInterface ->expects($this->at(0)) ->method('writeln') - ->with('--appId, --privateKey and --certificate are required.'); + ->with('This command requires the --path, --privateKey and --certificate.'); $this->invokePrivate($this->signApp, 'execute', [$inputInterface, $outputInterface]); } @@ -136,7 +142,7 @@ class SignAppTest extends TestCase { $inputInterface ->expects($this->at(0)) ->method('getOption') - ->with('appId') + ->with('path') ->will($this->returnValue('AppId')); $inputInterface ->expects($this->at(1)) @@ -170,7 +176,7 @@ class SignAppTest extends TestCase { $inputInterface ->expects($this->at(0)) ->method('getOption') - ->with('appId') + ->with('path') ->will($this->returnValue('AppId')); $inputInterface ->expects($this->at(1)) @@ -209,7 +215,7 @@ class SignAppTest extends TestCase { $inputInterface ->expects($this->at(0)) ->method('getOption') - ->with('appId') + ->with('path') ->will($this->returnValue('AppId')); $inputInterface ->expects($this->at(1)) diff --git a/tests/lib/integritycheck/checkertest.php b/tests/lib/integritycheck/checkertest.php index eee9299e6af..c4b952da924 100644 --- a/tests/lib/integritycheck/checkertest.php +++ b/tests/lib/integritycheck/checkertest.php @@ -77,7 +77,7 @@ class CheckerTest extends TestCase { /** * @expectedException \Exception - * @expectedExceptionMessage Directory name must not be empty. + * @expectedExceptionMessage Directory does not exist. */ public function testWriteAppSignatureOfNotExistingApp() { $keyBundle = file_get_contents(__DIR__ .'/../../data/integritycheck/SomeApp.crt'); @@ -98,11 +98,6 @@ class CheckerTest extends TestCase { "signature": "Y5yvXvcGHVPuRRatKVDUONWq1FpLXugZd6Km\/+aEHsQj7coVl9FeMj9OsWamBf7yRIw3dtNLguTLlAA9QAv\/b0uHN3JnbNZN+dwFOve4NMtqXfSDlWftqKN00VS+RJXpG1S2IIx9Poyp2NoghL\/5AuTv4GHiNb7zU\/DT\/kt71pUGPgPR6IIFaE+zHOD96vjYkrH+GfWZzKR0FCdLib9yyNvk+EGrcjKM6qjs2GKfS\/XFjj\/\/neDnh\/0kcPuKE3ZbofnI4TIDTv0CGqvOp7PtqVNc3Vy\/UKa7uF1PT0MAUKMww6EiMUSFZdUVP4WWF0Y72W53Qdtf1hrAZa2kfKyoK5kd7sQmCSKUPSU8978AUVZlBtTRlyT803IKwMV0iHMkw+xYB1sN2FlHup\/DESADqxhdgYuK35bCPvgkb4SBe4B8Voz\/izTvcP7VT5UvkYdAO+05\/jzdaHEmzmsD92CFfvX0q8O\/Y\/29ubftUJsqcHeMDKgcR4eZOE8+\/QVc\/89QO6WnKNuNuV+5bybO6g6PAdC9ZPsCvnihS61O2mwRXHLR3jv2UleFWm+lZEquPKtkhi6SLtDiijA4GV6dmS+dzujSLb7hGeD5o1plZcZ94uhWljl+QIp82+zU\/lYB1Zfr4Mb4e+V7r2gv7Fbv7y6YtjE2GIQwRhC5jq56bD0ZB+I=", "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEwTCCAqmgAwIBAgIUWv0iujufs5lUr0svCf\/qTQvoyKAwDQYJKoZIhvcNAQEF\r\nBQAwIzEhMB8GA1UECgwYb3duQ2xvdWQgQ29kZSBTaWduaW5nIENBMB4XDTE1MTEw\r\nMzIyNDk1M1oXDTE2MTEwMzIyNDk1M1owEjEQMA4GA1UEAwwHU29tZUFwcDCCAiIw\r\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8q0x62agGSRBqeWsaeEwFfepMk\r\nF8cAobMMi50qHCv9IrOn\/ZH9l52xBrbIkErVmRjmly0d4JhD8Ymhidsh9ONKYl\/j\r\n+ishsZDM8eNNdp3Ew+fEYVvY1W7mR1qU24NWj0bzVsClI7hvPVIuw7AjfBDq1C5+\r\nA+ZSLSXYvOK2cEWjdxQfuNZwEZSjmA63DUllBIrm35IaTvfuyhU6BW9yHZxmb8+M\r\nw0xDv30D5UkE\/2N7Pa\/HQJLxCR+3zKibRK3nUyRDLSXxMkU9PnFNaPNX59VPgyj4\r\nGB1CFSToldJVPF4pzh7p36uGXZVxs8m3LFD4Ol8mhi7jkxDZjqFN46gzR0r23Py6\r\ndol9vfawGIoUwp9LvL0S7MvdRY0oazLXwClLP4OQ17zpSMAiCj7fgNT661JamPGj\r\nt5O7Zn2wA7I4ddDS\/HDTWCu98Zwc9fHIpsJPgCZ9awoqxi4Mnf7Pk9g5nnXhszGC\r\ncxxIASQKM+GhdzoRxKknax2RzUCwCzcPRtCj8AQT\/x\/mqN3PfRmlnFBNACUw9bpZ\r\nSOoNq2pCF9igftDWpSIXQ38pVpKLWowjjg3DVRmVKBgivHnUnVLyzYBahHPj0vaz\r\ntFtUFRaqXDnt+4qyUGyrT5h5pjZaTcHIcSB4PiarYwdVvgslgwnQzOUcGAzRWBD4\r\n6jV2brP5vFY3g6iPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACTY3CCHC+Z28gCf\r\nFWGKQ3wAKs+k4+0yoti0qm2EKX7rSGQ0PHSas6uW79WstC4Rj+DYkDtIhGMSg8FS\r\nHVGZHGBCc0HwdX+BOAt3zi4p7Sf3oQef70\/4imPoKxbAVCpd\/cveVcFyDC19j1yB\r\nBapwu87oh+muoeaZxOlqQI4UxjBlR\/uRSMhOn2UGauIr3dWJgAF4pGt7TtIzt+1v\r\n0uA6FtN1Y4R5O8AaJPh1bIG0CVvFBE58esGzjEYLhOydgKFnEP94kVPgJD5ds9C3\r\npPhEpo1dRpiXaF7WGIV1X6DI\/ipWvfrF7CEy6I\/kP1InY\/vMDjQjeDnJ\/VrXIWXO\r\nyZvHXVaN\/m+1RlETsH7YO\/QmxRue9ZHN3gvvWtmpCeA95sfpepOk7UcHxHZYyQbF\r\n49\/au8j+5tsr4A83xzsT1JbcKRxkAaQ7WDJpOnE5O1+H0fB+BaLakTg6XX9d4Fo7\r\n7Gin7hVWX7pL+JIyxMzME3LhfI61+CRcqZQIrpyaafUziPQbWIPfEs7h8tCOWyvW\r\nUO8ZLervYCB3j44ivkrxPlcBklDCqqKKBzDP9dYOtS\/P4RB1NkHA9+NTvmBpTonS\r\nSFXdg9fFMD7VfjDE3Vnk+8DWkVH5wBYowTAD7w9Wuzr7DumiAULexnP\/Y7xwxLv7\r\n4B+pXTAcRK0zECDEaX3npS8xWzrB\r\n-----END CERTIFICATE-----" }'; - $this->appLocator - ->expects($this->once()) - ->method('getAppPath') - ->with('SomeExistingApp') - ->will($this->returnValue(\OC::$SERVERROOT . '/tests/data/integritycheck/app/')); $this->fileAccessHelper ->expects($this->once()) ->method('file_put_contents') @@ -117,7 +112,7 @@ class CheckerTest extends TestCase { $rsa->loadKey($rsaPrivateKey); $x509 = new X509(); $x509->loadX509($keyBundle); - $this->checker->writeAppSignature('SomeExistingApp', $x509, $rsa); + $this->checker->writeAppSignature(\OC::$SERVERROOT . '/tests/data/integritycheck/app/', $x509, $rsa); } public function testVerifyAppSignatureWithoutSignatureData() { |