diff --git a/appinfo/info.xml b/appinfo/info.xml index 246a322c..52baab1a 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -23,7 +23,7 @@ https://github.com/ChristophWurst/nextcloud_sentry - + OCA\Sentry\Command\Test diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 903dda6d..d5d2d1e1 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -1,4 +1,5 @@ getContainer(); + public function __construct() { + parent::__construct(self::APP_ID, []); + } - /* @var $config IConfig */ - $config = $container->query(IConfig::class); - $publicDsn = $config->getSystemValueString('sentry.public-dsn', ''); - $dsn = $config->getSystemValue('sentry.dsn', $publicDsn); - $reportUrl = $config->getSystemValue('sentry.csp-report-url', null); + public function register(IRegistrationContext $context): void { + $context->registerCrashReporter(RecursionAwareReporter::class); - if ($dsn !== '') { - $this->registerClient($dsn); - } - $this->setInitialState($publicDsn); + $context->registerService(RecursionAwareReporter::class, function (IContainer $c) { + /** @var SentryReporterAdapter $reporter */ + $reporter = $c->query(SentryReporterAdapter::class); - /** @var IEventDispatcher $dispatcher */ - $dispatcher = $container->query(IEventDispatcher::class); - $dispatcher->addListener(AddContentSecurityPolicyEvent::class, function (AddContentSecurityPolicyEvent $event) use ($reportUrl, $publicDsn) { - $event->addPolicy($this->createCsp($publicDsn, $reportUrl)); + return new RecursionAwareReporter($reporter); }); } - /** - * @param string $dsn - */ - private function registerClient(string $dsn): void { - $container = $this->getContainer(); - /* @var $config IConfig */ - $config = $container->query(IConfig::class); - - initSentry([ - 'dsn' => $dsn, - 'release' => $config->getSystemValue('version', '0.0.0'), - ]); - - /* @var $registry IRegistry */ - $registry = $container->query(IRegistry::class); - $reporter = $container->query(SentryReporterAdapter::class); - $registry->register(new RecursionAwareReporter($reporter)); + public function boot(IBootContext $context): void { + $this->initSentry( + $context->getAppContainer()->query(IConfig::class), + $context->getAppContainer()->query(Config::class) + ); + $this->setInitialState( + $context->getAppContainer()->query(IInitialStateService::class), + $context->getAppContainer()->query(Config::class) + ); } - private function createCsp(?string $publicDsn, ?string $reportUrl): ContentSecurityPolicy { - $csp = new ContentSecurityPolicy(); - if ($publicDsn === null && $reportUrl === null) { - // Don't add any custom CSP - return $csp; - } - - if ($publicDsn !== null) { - $parsedUrl = parse_url($publicDsn); - if (isset($parsedUrl['scheme'], $parsedUrl['host'])) { - $domain = $parsedUrl['scheme'] . '://' . $parsedUrl['host']; - $csp->addAllowedConnectDomain($domain); - } - } - if ($reportUrl !== null) { - $csp->addReportTo($reportUrl); - } - return $csp; + private function setInitialState(IInitialStateService $stateService, + Config $config): void { + $stateService->provideLazyInitialState('sentry', 'dsn', function () use ($config) { + return [ + 'dsn' => $config->getDsn(), + ]; + }); } - private function setInitialState(string $dsn): void { - $container = $this->getContainer(); + private function initSentry(IConfig $sysConfig, + Config $config) { + $dsn = $config->getDsn(); - /** @var IInitialStateService $stateService */ - $stateService = $container->query(IInitialStateService::class); + if ($dsn === null) { + return; + } - $stateService->provideLazyInitialState('sentry', 'dsn', function () use ($dsn) { - return [ - 'dsn' => $dsn === '' ? null : $dsn, - ]; - }); + initSentry([ + 'dsn' => $dsn, + 'release' => $sysConfig->getSystemValue('version', '0.0.0'), + ]); } } diff --git a/lib/Config.php b/lib/Config.php new file mode 100644 index 00000000..4824d8e2 --- /dev/null +++ b/lib/Config.php @@ -0,0 +1,53 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + */ + +namespace OCA\Sentry; + +use OCP\IConfig; + +class Config { + + /** @var IConfig */ + private $config; + + public function __construct(IConfig $config) { + $this->config = $config; + } + + public function getDsn(): ?string { + $dsn = $this->config->getSystemValue('sentry.dsn', $this->getPublicDsn()); + return $dsn === '' ? null : $dsn; + } + + public function getPublicDsn(): ?string { + $publicDsn = $this->config->getSystemValueString('sentry.public-dsn'); + return $publicDsn === '' ? null : $publicDsn; + } + + public function getReportUrl(): ?string { + return $this->config->getSystemValue('sentry.csp-report-url', null); + } + +} diff --git a/lib/Listener/AddSentryCspListener.php b/lib/Listener/AddSentryCspListener.php new file mode 100644 index 00000000..b05759e8 --- /dev/null +++ b/lib/Listener/AddSentryCspListener.php @@ -0,0 +1,76 @@ + + * + * @author 2020 Christoph Wurst + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + */ + +namespace OCA\Sentry\Listener; + +use OCA\Sentry\Config; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Security\CSP\AddContentSecurityPolicyEvent; +use function parse_url; + +class AddSentryCspListener implements IEventListener { + + /** @var Config */ + private $config; + + public function __construct(Config $config) { + $this->config = $config; + } + + public function handle(Event $event): void { + if (!($event instanceof AddContentSecurityPolicyEvent)) { + return; + } + + $event->addPolicy( + $this->createCsp( + $this->config->getPublicDsn(), + $this->config->getReportUrl() + ) + ); + } + + private function createCsp(?string $publicDsn, ?string $reportUrl): ContentSecurityPolicy { + $csp = new ContentSecurityPolicy(); + if ($publicDsn === null && $reportUrl === null) { + // Don't add any custom CSP + return $csp; + } + + if ($publicDsn !== null) { + $parsedUrl = parse_url($publicDsn); + if (isset($parsedUrl['scheme'], $parsedUrl['host'])) { + $domain = $parsedUrl['scheme'] . '://' . $parsedUrl['host']; + $csp->addAllowedConnectDomain($domain); + } + } + if ($reportUrl !== null) { + $csp->addReportTo($reportUrl); + } + return $csp; + } +}