diff options
author | sualko <klaus@jsxc.org> | 2022-01-04 17:04:18 +0300 |
---|---|---|
committer | sualko <klaus@jsxc.org> | 2022-01-04 17:04:18 +0300 |
commit | 92a94f7703abc5af1567186e676cb18a1ee55289 (patch) | |
tree | e96926e8dad914e03c9fe0830b624af111e9c5d1 | |
parent | 05381e2bedb51b212c0280fc09279e37ccc7d198 (diff) |
fix: remove deprecated app.php
-rwxr-xr-x | appinfo/app.php | 98 | ||||
-rwxr-xr-x | appinfo/info.xml | 5 | ||||
-rw-r--r-- | lib/AppInfo/Application.php | 155 | ||||
-rw-r--r-- | lib/Controller/ManagedServerController.php | 4 | ||||
-rw-r--r-- | lib/Listener/AddFeaturePolicyListener.php | 26 | ||||
-rw-r--r-- | lib/Migration/InitApiSecret.php | 62 |
6 files changed, 224 insertions, 126 deletions
diff --git a/appinfo/app.php b/appinfo/app.php deleted file mode 100755 index b97b168..0000000 --- a/appinfo/app.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php - -use OCA\OJSXC\AppInfo\Application; -use OCA\OJSXC\Hooks; -use OCA\OJSXC\Config; - -$config = \OC::$server->getConfig(); -$versionHashSuffix = ''; - -if (!$config->getSystemValue('debug', false)) { - $appVersion = $config->getAppValue('ojsxc', 'installed_version'); - $versionHashSuffix = '?v=' . substr(md5($appVersion), 0, 8); -} - -function addScript($src) { - // use addHeader instead of addScript, because addScript adds js suffix to every src - \OCP\Util::addHeader( 'script', [ - 'src' => $src, - 'nonce' => \OC::$server->getContentSecurityPolicyNonceManager()->getNonce(), - ], '' - ); -} - -$urlGenerator = \OC::$server->getURLGenerator(); - -addScript($urlGenerator->linkToRoute('ojsxc.javascript.generalConfig')); -addScript($urlGenerator->linkTo('ojsxc', 'js/libsignal/libsignal-protocol.js') . $versionHashSuffix); -addScript($urlGenerator->linkTo('ojsxc', 'js/jsxc/jsxc.bundle.js') . $versionHashSuffix); -addScript($urlGenerator->linkTo('ojsxc', 'js/bundle.js') . $versionHashSuffix); - -// workaround to overwrite localStorage.clear -\OCP\Util::addScript( 'ojsxc', 'overwriteClearStorage', true ); - -\OCP\Util::addStyle ( 'ojsxc', '../js/jsxc/styles/jsxc.bundle' ); -\OCP\Util::addStyle ( 'ojsxc', 'bundle' ); - -$dispatcher = \OC::$server->getEventDispatcher(); -$dispatcher->addListener(\OCP\Security\FeaturePolicy\AddFeaturePolicyEvent::class, function (\OCP\Security\FeaturePolicy\AddFeaturePolicyEvent $e) { - $fp = new \OCP\AppFramework\Http\EmptyFeaturePolicy(); - - $fp->addAllowedGeoLocationDomain('\'self\''); - $fp->addAllowedCameraDomain('\'self\''); - $fp->addAllowedFullScreenDomain('\'self\''); - $fp->addAllowedMicrophoneDomain('\'self\''); - - $e->addPolicy($fp); -}); - -if(class_exists('\\OCP\\AppFramework\\Http\\EmptyContentSecurityPolicy')) { - $manager = \OC::$server->getContentSecurityPolicyManager(); - $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy(); - - $policy->addAllowedStyleDomain('\'self\''); - $policy->addAllowedStyleDomain('\'unsafe-inline\''); - - $policy->addAllowedScriptDomain('\'self\''); - - if ($config->getSystemValue('jsxc.environment', 'production') === 'development') { - // required for source maps - $policy->addAllowedScriptDomain('\'unsafe-eval\''); - } - - $policy->addAllowedImageDomain('\'self\''); - $policy->addAllowedImageDomain('data:'); - $policy->addAllowedImageDomain('blob:'); - - $policy->addAllowedMediaDomain('\'self\''); - $policy->addAllowedMediaDomain('blob:'); - - $policy->addAllowedChildSrcDomain('\'self\''); - - $policy->addAllowedConnectDomain('\'self\''); - - $boshUrl = \OC::$server->getConfig()->getAppValue('ojsxc', Config::XMPP_URL); - - if(preg_match('#^(https?:)?//([a-z0-9][a-z0-9\-.]*[a-z0-9](:[0-9]+)?)/#i', $boshUrl, $matches)) { - $boshDomain = $matches[2]; - - $policy->addAllowedConnectDomain($boshDomain); - } - - $externalServices = \OC::$server->getConfig()->getAppValue('ojsxc', Config::EXTERNAL_SERVICES); - $externalServices = explode("|", $externalServices); - - foreach($externalServices as $es) { - $policy->addAllowedConnectDomain($es); - } - - $manager->addDefaultPolicy($policy); -} - -$apiSecret = $config->getAppValue('ojsxc', Config::API_SECRET); -if(!$apiSecret) { - $apiSecret = \OC::$server->getSecureRandom()->generate(23); - $config->setAppValue('ojsxc', Config::API_SECRET, $apiSecret); -} - -?> diff --git a/appinfo/info.xml b/appinfo/info.xml index d30eef4..b4fbf82 100755 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -46,10 +46,13 @@ <lib>xmlreader</lib> <lib>xmlwriter</lib> <lib>dom</lib> - <nextcloud min-version="19" max-version="21"/> + <nextcloud min-version="20" max-version="21"/> </dependencies> <repair-steps> + <install> + <step>OCA\OJSXC\Migration\InitApiSecret</step> + </install> <post-migration> <step>OCA\OJSXC\Migration\MigrateConfig</step> </post-migration> diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 92d890b..911cb71 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -2,57 +2,158 @@ namespace OCA\OJSXC\AppInfo; +use OC\Security\CSP\ContentSecurityPolicyManager; use OCA\OJSXC\Controller\ManagedServerController; use OCA\OJSXC\Middleware\ExternalApiMiddleware; use OCA\OJSXC\Config; +use OCA\OJSXC\Listener\AddFeaturePolicyListener; use OCP\IContainer; -use OCP\IRequest; use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootContext; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\IConfig; +use OCP\IServerContainer; +use OCP\IURLGenerator; +use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; -class Application extends App +class Application extends App implements IBootstrap { const NOT_CONFIGURED = 'not-configured'; const INTERNAL = 'internal'; const EXTERNAL = 'external'; const MANAGED = 'managed'; - private static $config = []; - public function __construct(array $urlParams = []) { parent::__construct('ojsxc', $urlParams); - $container = $this->getContainer(); - - /** @var $config \OCP\IConfig */ - $configManager = $container->query(\OCP\IConfig::class); - + } - $container->registerService('ManagedServerController', function (IContainer $c) { + public function register(IRegistrationContext $context): void + { + $context->registerService('ManagedServerController', function (ContainerInterface $c) { return new ManagedServerController( - $c->query('AppName'), - $c->query('Request'), - $c->query(\OCP\IURLGenerator::class), - $c->query(Config::class), - $c->query(\OCP\IUserSession::class), - $c->query(\OCP\ILogger::class), - $c->query('DataRetriever'), - $c->query(\OCP\Security\ISecureRandom::class), - $c->query(\OCP\App\IAppManager::class), + $c->get('AppName'), + $c->get('Request'), + $c->get(\OCP\IURLGenerator::class), + $c->get(Config::class), + $c->get(\OCP\IUserSession::class), + $c->get(LoggerInterface::class), + $c->get('DataRetriever'), + $c->get(\OCP\Security\ISecureRandom::class), + $c->get(\OCP\App\IAppManager::class), 'https://xmpp.jsxc.ch/registration' ); }); - /** - * Middleware - */ - $container->registerService('ExternalApiMiddleware', function (IContainer $c) { + $context->registerService('ExternalApiMiddleware', function (ContainerInterface $c) { return new ExternalApiMiddleware( - $c->query('Request'), - $c->query(\OCP\IConfig::class), - $c->query('RawRequest') + $c->get('Request'), + $c->get(\OCP\IConfig::class), + $c->get('RawRequest') ); }); - $container->registerMiddleware('ExternalApiMiddleware'); + + $context->registerMiddleware('ExternalApiMiddleware'); + + $context->registerEventListener(AddFeaturePolicyEvent::class, AddFeaturePolicyListener::class); + } + + public function boot(IBootContext $context): void + { + $this->adjustContentSecurityPolicy($context->getServerContainer()); + $this->injectFiles($context->getServerContainer()); + } + + private function adjustContentSecurityPolicy(IServerContainer $container) + { + /** @var IConfig */ + $config = $container->get(IConfig::class); + + /** @var ContentSecurityPolicyManager */ + $manager = $container->get(ContentSecurityPolicyManager::class); + + $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy(); + + $policy->addAllowedStyleDomain('\'self\''); + $policy->addAllowedStyleDomain('\'unsafe-inline\''); + + $policy->addAllowedScriptDomain('\'self\''); + + if ($config->getSystemValue('jsxc.environment', 'production') === 'development') { + // required for source maps + $policy->addAllowedScriptDomain('\'unsafe-eval\''); + } + + $policy->addAllowedImageDomain('\'self\''); + $policy->addAllowedImageDomain('data:'); + $policy->addAllowedImageDomain('blob:'); + + $policy->addAllowedMediaDomain('\'self\''); + $policy->addAllowedMediaDomain('blob:'); + + $policy->addAllowedWorkerSrcDomain('\'self\''); + + $policy->addAllowedConnectDomain('\'self\''); + + $boshUrl = $config->getAppValue('ojsxc', Config::XMPP_URL); + + if (preg_match('#^(https?:)?//([a-z0-9][a-z0-9\-.]*[a-z0-9](:[0-9]+)?)/#i', $boshUrl, $matches)) { + $boshDomain = $matches[2]; + + $policy->addAllowedConnectDomain($boshDomain); + } + + $externalServices = \OC::$server->getConfig()->getAppValue('ojsxc', Config::EXTERNAL_SERVICES); + $externalServices = explode("|", $externalServices); + + foreach ($externalServices as $es) { + $policy->addAllowedConnectDomain($es); + } + + $manager->addDefaultPolicy($policy); + } + + private function injectFiles(IServerContainer $container) + { + /** @var IURLGenerator */ + $urlGenerator = $container->get(IURLGenerator::class); + + /** @var IConfig */ + $config = $container->get(IConfig::class); + + $versionHashSuffix = ''; + + if (!$config->getSystemValue('debug', false)) { + $appVersion = $config->getAppValue('ojsxc', 'installed_version'); + $versionHashSuffix = '?v=' . substr(md5($appVersion), 0, 8); + } + + $this->addScript($urlGenerator->linkToRoute('ojsxc.javascript.generalConfig')); + $this->addScript($urlGenerator->linkTo('ojsxc', 'js/libsignal/libsignal-protocol.js') . $versionHashSuffix); + $this->addScript($urlGenerator->linkTo('ojsxc', 'js/jsxc/jsxc.bundle.js') . $versionHashSuffix); + $this->addScript($urlGenerator->linkTo('ojsxc', 'js/bundle.js') . $versionHashSuffix); + + // workaround to overwrite localStorage.clear + \OCP\Util::addScript('ojsxc', 'overwriteClearStorage', true); + + \OCP\Util::addStyle('ojsxc', '../js/jsxc/styles/jsxc.bundle'); + \OCP\Util::addStyle('ojsxc', 'bundle'); + } + + private function addScript(string $src) + { + // use addHeader instead of addScript, because addScript adds js suffix to every src + \OCP\Util::addHeader( + 'script', + [ + 'src' => $src, + 'nonce' => \OC::$server->getContentSecurityPolicyNonceManager()->getNonce(), + ], + '' + ); } public static function getServerType() diff --git a/lib/Controller/ManagedServerController.php b/lib/Controller/ManagedServerController.php index 878fac6..5b93743 100644 --- a/lib/Controller/ManagedServerController.php +++ b/lib/Controller/ManagedServerController.php @@ -89,6 +89,10 @@ class ManagedServerController extends Controller $userId = $this->userSession->getUser()->getUID(); $appVersion = $this->appManager->getAppVersion('ojsxc'); + if (!$apiSecret) { + throw new Exception('API secret not available'); + } + $data = [ 'apiUrl' => $apiUrl, 'apiSecret' => $apiSecret, diff --git a/lib/Listener/AddFeaturePolicyListener.php b/lib/Listener/AddFeaturePolicyListener.php new file mode 100644 index 0000000..54ba996 --- /dev/null +++ b/lib/Listener/AddFeaturePolicyListener.php @@ -0,0 +1,26 @@ +<?php + +namespace OCA\OJSXC\Listener; + +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; + +class AddFeaturePolicyListener implements IEventListener +{ + public function handle(Event $event): void + { + if (!($event instanceof AddFeaturePolicyEvent)) { + return; + } + + $policy = new \OCP\AppFramework\Http\EmptyFeaturePolicy(); + + $policy->addAllowedGeoLocationDomain('\'self\''); + $policy->addAllowedCameraDomain('\'self\''); + $policy->addAllowedFullScreenDomain('\'self\''); + $policy->addAllowedMicrophoneDomain('\'self\''); + + $event->addPolicy($policy); + } +} diff --git a/lib/Migration/InitApiSecret.php b/lib/Migration/InitApiSecret.php new file mode 100644 index 0000000..b3f3133 --- /dev/null +++ b/lib/Migration/InitApiSecret.php @@ -0,0 +1,62 @@ +<?php + +namespace OCA\OJSXC\Migration; + +use OCA\OJSXC\Config; +use OCP\ILogger; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use OCP\Security\ISecureRandom; + +class InitApiSecret implements IRepairStep +{ + /** + * @var Config + */ + private $config; + + /** + * @var ISecureRandom + */ + private $secureRandom; + + /** + * @param Config $config + * @param ILogger $logger + */ + public function __construct(Config $config, ISecureRandom $secureRandom) + { + $this->config = $config; + $this->secureRandom = $secureRandom; + } + + /** + * Returns the step's name + * + * @return string + */ + public function getName() + { + return "Initialize API secret"; + } + + /** + * Run repair step. + * Must throw exception on error. + * + * @param IOutput $output + * @throws \Exception in case of failure + */ + public function run(IOutput $output) + { + $apiSecret = $this->config->getAppValue(Config::API_SECRET); + + if (!$apiSecret) { + $apiSecret = $this->secureRandom->generate(23); + + $this->config->setAppValue(Config::API_SECRET, $apiSecret); + + $output->info("API secret initialized"); + } + } +} |