summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/ajax/update.php7
-rw-r--r--core/command/integrity/signapp.php98
-rw-r--r--core/command/integrity/signcore.php98
-rw-r--r--core/command/upgrade.php10
-rw-r--r--core/js/integritycheck-failed-notification.js38
-rw-r--r--core/js/setupchecks.js14
-rw-r--r--core/js/tests/specs/setupchecksSpec.js7
-rw-r--r--core/register_command.php8
8 files changed, 277 insertions, 3 deletions
diff --git a/core/ajax/update.php b/core/ajax/update.php
index 7da9b71b751..a5c1f79e3ea 100644
--- a/core/ajax/update.php
+++ b/core/ajax/update.php
@@ -47,6 +47,7 @@ if (OC::checkUpgrade(false)) {
$updater = new \OC\Updater(
\OC::$server->getHTTPHelper(),
$config,
+ \OC::$server->getIntegrityCodeChecker(),
$logger
);
$incompatibleApps = [];
@@ -108,6 +109,12 @@ if (OC::checkUpgrade(false)) {
$updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($eventSource, $l) {
$eventSource->send('success', (string)$l->t('Reset log level to "%s"', [ $logLevelName ]));
});
+ $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($eventSource, $l) {
+ $eventSource->send('success', (string)$l->t('Starting code integrity check'));
+ });
+ $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($eventSource, $l) {
+ $eventSource->send('success', (string)$l->t('Finished code integrity check'));
+ });
try {
$updater->upgrade();
diff --git a/core/command/integrity/signapp.php b/core/command/integrity/signapp.php
new file mode 100644
index 00000000000..83a7972068f
--- /dev/null
+++ b/core/command/integrity/signapp.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Integrity;
+
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use phpseclib\Crypt\RSA;
+use phpseclib\File\X509;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class SignApp
+ *
+ * @package OC\Core\Command\Integrity
+ */
+class SignApp extends Command {
+ /** @var Checker */
+ private $checker;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+
+ /**
+ * @param Checker $checker
+ * @param FileAccessHelper $fileAccessHelper
+ */
+ public function __construct(Checker $checker,
+ FileAccessHelper $fileAccessHelper) {
+ parent::__construct(null);
+ $this->checker = $checker;
+ $this->fileAccessHelper = $fileAccessHelper;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('integrity:sign-app')
+ ->setDescription('Sign app using a private key.')
+ ->addOption('appId', 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');
+ }
+
+ /**
+ * {@inheritdoc }
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $appId = $input->getOption('appId');
+ $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.');
+ return null;
+ }
+
+ $privateKey = $this->fileAccessHelper->file_get_contents($privateKeyPath);
+ $keyBundle = $this->fileAccessHelper->file_get_contents($keyBundlePath);
+
+ if($privateKey === false) {
+ $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath));
+ return null;
+ }
+
+ if($keyBundle === false) {
+ $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath));
+ return null;
+ }
+
+ $rsa = new RSA();
+ $rsa->loadKey($privateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $x509->setPrivateKey($rsa);
+ $this->checker->writeAppSignature($appId, $x509, $rsa);
+
+ $output->writeln('Successfully signed "'.$appId.'"');
+ }
+}
diff --git a/core/command/integrity/signcore.php b/core/command/integrity/signcore.php
new file mode 100644
index 00000000000..4d097ad4f96
--- /dev/null
+++ b/core/command/integrity/signcore.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Integrity;
+
+use OC\IntegrityCheck\Checker;
+use OC\IntegrityCheck\Helpers\EnvironmentHelper;
+use OC\IntegrityCheck\Helpers\FileAccessHelper;
+use phpseclib\Crypt\RSA;
+use phpseclib\File\X509;
+use Symfony\Component\Console\Command\Command;
+use OCP\IConfig;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class SignCore
+ *
+ * @package OC\Core\Command\Integrity
+ */
+class SignCore extends Command {
+ /** @var Checker */
+ private $checker;
+ /** @var FileAccessHelper */
+ private $fileAccessHelper;
+
+ /**
+ * @param Checker $checker
+ * @param FileAccessHelper $fileAccessHelper
+ */
+ public function __construct(Checker $checker,
+ FileAccessHelper $fileAccessHelper) {
+ parent::__construct(null);
+ $this->checker = $checker;
+ $this->fileAccessHelper = $fileAccessHelper;
+ }
+
+ protected function configure() {
+ $this
+ ->setName('integrity:sign-core')
+ ->setDescription('Sign core using a private key.')
+ ->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');
+ }
+
+ /**
+ * {@inheritdoc }
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $privateKeyPath = $input->getOption('privateKey');
+ $keyBundlePath = $input->getOption('certificate');
+ if(is_null($privateKeyPath) || is_null($keyBundlePath)) {
+ $output->writeln('--privateKey and --certificate are required.');
+ return null;
+ }
+
+ $privateKey = $this->fileAccessHelper->file_get_contents($privateKeyPath);
+ $keyBundle = $this->fileAccessHelper->file_get_contents($keyBundlePath);
+
+ if($privateKey === false) {
+ $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath));
+ return null;
+ }
+
+ if($keyBundle === false) {
+ $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath));
+ return null;
+ }
+
+ $rsa = new RSA();
+ $rsa->loadKey($privateKey);
+ $x509 = new X509();
+ $x509->loadX509($keyBundle);
+ $x509->setPrivateKey($rsa);
+ $this->checker->writeCoreSignature($x509, $rsa);
+
+ $output->writeln('Successfully signed "core"');
+ }
+}
diff --git a/core/command/upgrade.php b/core/command/upgrade.php
index d1a7c09c30c..9031e284f85 100644
--- a/core/command/upgrade.php
+++ b/core/command/upgrade.php
@@ -53,6 +53,7 @@ class Upgrade extends Command {
/**
* @param IConfig $config
+ * @param ILogger $logger
*/
public function __construct(IConfig $config, ILogger $logger) {
parent::__construct();
@@ -122,9 +123,12 @@ class Upgrade extends Command {
}
$self = $this;
- $updater = new Updater(\OC::$server->getHTTPHelper(),
- $this->config,
- $this->logger);
+ $updater = new Updater(
+ \OC::$server->getHTTPHelper(),
+ $this->config,
+ \OC::$server->getIntegrityCodeChecker(),
+ $this->logger
+ );
$updater->setSimulateStepEnabled($simulateStepEnabled);
$updater->setUpdateStepEnabled($updateStepEnabled);
diff --git a/core/js/integritycheck-failed-notification.js b/core/js/integritycheck-failed-notification.js
new file mode 100644
index 00000000000..5bc758d54cb
--- /dev/null
+++ b/core/js/integritycheck-failed-notification.js
@@ -0,0 +1,38 @@
+/**
+ * @author Lukas Reschke
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * This gets only loaded if the integrity check has failed and then shows a notification
+ */
+$(document).ready(function(){
+ var text = t(
+ 'core',
+ '<a href="{docUrl}">There were problems with the code integrity check. More information…</a>',
+ {
+ docUrl: OC.generateUrl('/settings/admin#security-warning')
+ }
+ );
+
+ OC.Notification.showHtml(
+ text,
+ {
+ isHTML: true
+ }
+ );
+});
+
diff --git a/core/js/setupchecks.js b/core/js/setupchecks.js
index 6e2058d54fc..5ac1945da73 100644
--- a/core/js/setupchecks.js
+++ b/core/js/setupchecks.js
@@ -104,6 +104,20 @@
type: OC.SetupChecks.MESSAGE_TYPE_WARNING
});
}
+ if(!data.hasPassedCodeIntegrityCheck) {
+ messages.push({
+ msg: t(
+ 'core',
+ 'Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a href="{docLink}">documentation</a>. (<a href="{codeIntegrityDownloadEndpoint}">List of invalid files…</a> / <a href="{rescanEndpoint}">Rescan…</a>)',
+ {
+ docLink: data.codeIntegrityCheckerDocumentation,
+ codeIntegrityDownloadEndpoint: OC.generateUrl('/settings/integrity/failed'),
+ rescanEndpoint: OC.generateUrl('/settings/integrity/rescan?requesttoken={requesttoken}', {'requesttoken': OC.requestToken})
+ }
+ ),
+ type: OC.SetupChecks.MESSAGE_TYPE_ERROR
+ });
+ }
} else {
messages.push({
msg: t('core', 'Error occurred while checking server setup'),
diff --git a/core/js/tests/specs/setupchecksSpec.js b/core/js/tests/specs/setupchecksSpec.js
index 8dd2214621a..4bad893cf37 100644
--- a/core/js/tests/specs/setupchecksSpec.js
+++ b/core/js/tests/specs/setupchecksSpec.js
@@ -75,6 +75,7 @@ describe('OC.SetupChecks tests', function() {
memcacheDocs: 'https://doc.owncloud.org/server/go.php?to=admin-performance',
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -109,6 +110,7 @@ describe('OC.SetupChecks tests', function() {
memcacheDocs: 'https://doc.owncloud.org/server/go.php?to=admin-performance',
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -145,6 +147,7 @@ describe('OC.SetupChecks tests', function() {
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -178,6 +181,7 @@ describe('OC.SetupChecks tests', function() {
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -206,6 +210,7 @@ describe('OC.SetupChecks tests', function() {
isMemcacheConfigured: true,
forwardedForHeadersWorking: true,
isCorrectMemcachedPHPModuleInstalled: false,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -234,6 +239,7 @@ describe('OC.SetupChecks tests', function() {
forwardedForHeadersWorking: false,
reverseProxyDocs: 'https://docs.owncloud.org/foo/bar.html',
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
@@ -283,6 +289,7 @@ describe('OC.SetupChecks tests', function() {
forwardedForHeadersWorking: true,
phpSupported: {eol: true, version: '5.4.0'},
isCorrectMemcachedPHPModuleInstalled: true,
+ hasPassedCodeIntegrityCheck: true,
})
);
diff --git a/core/register_command.php b/core/register_command.php
index 4044d2d200c..16dda55878e 100644
--- a/core/register_command.php
+++ b/core/register_command.php
@@ -32,6 +32,14 @@ $application->add(new OC\Core\Command\Check(\OC::$server->getConfig()));
$infoParser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
$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()
+));
+$application->add(new \OC\Core\Command\Integrity\SignCore(
+ \OC::$server->getIntegrityCodeChecker(),
+ new \OC\IntegrityCheck\Helpers\FileAccessHelper()
+));
if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
$application->add(new OC\Core\Command\App\Disable());