From a9f71315757a4c48f84cf5928022fa2fa105fad9 Mon Sep 17 00:00:00 2001 From: Côme Chilliet Date: Thu, 16 May 2024 17:25:13 +0200 Subject: fix: Move OC_EventSource to OC namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/composer/composer/autoload_classmap.php | 2 +- lib/composer/composer/autoload_static.php | 2 +- lib/private/EventSource.php | 138 ++++++++++++++++++++++++++++ lib/private/EventSourceFactory.php | 16 +--- lib/private/legacy/OC_EventSource.php | 134 --------------------------- 5 files changed, 144 insertions(+), 148 deletions(-) create mode 100644 lib/private/EventSource.php delete mode 100644 lib/private/legacy/OC_EventSource.php (limited to 'lib') diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index cb57d44ea60..8e1408e121e 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1382,6 +1382,7 @@ return array( 'OC\\Encryption\\Util' => $baseDir . '/lib/private/Encryption/Util.php', 'OC\\EventDispatcher\\EventDispatcher' => $baseDir . '/lib/private/EventDispatcher/EventDispatcher.php', 'OC\\EventDispatcher\\ServiceEventListener' => $baseDir . '/lib/private/EventDispatcher/ServiceEventListener.php', + 'OC\\EventSource' => $baseDir . '/lib/private/EventSource.php', 'OC\\EventSourceFactory' => $baseDir . '/lib/private/EventSourceFactory.php', 'OC\\Federation\\CloudFederationFactory' => $baseDir . '/lib/private/Federation/CloudFederationFactory.php', 'OC\\Federation\\CloudFederationNotification' => $baseDir . '/lib/private/Federation/CloudFederationNotification.php', @@ -1905,7 +1906,6 @@ return array( 'OC_API' => $baseDir . '/lib/private/legacy/OC_API.php', 'OC_App' => $baseDir . '/lib/private/legacy/OC_App.php', 'OC_Defaults' => $baseDir . '/lib/private/legacy/OC_Defaults.php', - 'OC_EventSource' => $baseDir . '/lib/private/legacy/OC_EventSource.php', 'OC_FileChunking' => $baseDir . '/lib/private/legacy/OC_FileChunking.php', 'OC_Files' => $baseDir . '/lib/private/legacy/OC_Files.php', 'OC_Helper' => $baseDir . '/lib/private/legacy/OC_Helper.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 0a4e9571049..d6939ae36ce 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1423,6 +1423,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Encryption\\Util' => __DIR__ . '/../../..' . '/lib/private/Encryption/Util.php', 'OC\\EventDispatcher\\EventDispatcher' => __DIR__ . '/../../..' . '/lib/private/EventDispatcher/EventDispatcher.php', 'OC\\EventDispatcher\\ServiceEventListener' => __DIR__ . '/../../..' . '/lib/private/EventDispatcher/ServiceEventListener.php', + 'OC\\EventSource' => __DIR__ . '/../../..' . '/lib/private/EventSource.php', 'OC\\EventSourceFactory' => __DIR__ . '/../../..' . '/lib/private/EventSourceFactory.php', 'OC\\Federation\\CloudFederationFactory' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudFederationFactory.php', 'OC\\Federation\\CloudFederationNotification' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudFederationNotification.php', @@ -1946,7 +1947,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC_API' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_API.php', 'OC_App' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_App.php', 'OC_Defaults' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_Defaults.php', - 'OC_EventSource' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_EventSource.php', 'OC_FileChunking' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_FileChunking.php', 'OC_Files' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_Files.php', 'OC_Helper' => __DIR__ . '/../../..' . '/lib/private/legacy/OC_Helper.php', diff --git a/lib/private/EventSource.php b/lib/private/EventSource.php new file mode 100644 index 00000000000..9a62d13a938 --- /dev/null +++ b/lib/private/EventSource.php @@ -0,0 +1,138 @@ + + * @author Christian Oliff + * @author Christoph Wurst + * @author Felix Moeller + * @author Lukas Reschke + * @author Morris Jobke + * @author Robin Appelman + * @author Thomas Müller + * + * @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 + * + */ + +namespace OC; + +use OCP\IEventSource; +use OCP\IRequest; + +class EventSource implements IEventSource { + /** + * @var bool + */ + private $fallback; + + /** + * @var int + */ + private $fallBackId = 0; + + /** + * @var bool + */ + private $started = false; + + private IRequest $request; + + public function __construct(IRequest $request) { + $this->request = $request; + } + + protected function init() { + if ($this->started) { + return; + } + $this->started = true; + + // prevent php output buffering, caching and nginx buffering + \OC_Util::obEnd(); + header('Cache-Control: no-cache'); + header('X-Accel-Buffering: no'); + $this->fallback = isset($_GET['fallback']) and $_GET['fallback'] == 'true'; + if ($this->fallback) { + $this->fallBackId = (int)$_GET['fallback_id']; + /** + * FIXME: The default content-security-policy of ownCloud forbids inline + * JavaScript for security reasons. IE starting on Windows 10 will + * however also obey the CSP which will break the event source fallback. + * + * As a workaround thus we set a custom policy which allows the execution + * of inline JavaScript. + * + * @link https://github.com/owncloud/core/issues/14286 + */ + header("Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'"); + header("Content-Type: text/html"); + echo str_repeat('' . PHP_EOL, 10); //dummy data to keep IE happy + } else { + header("Content-Type: text/event-stream"); + } + if (!$this->request->passesStrictCookieCheck()) { + header('Location: '.\OC::$WEBROOT); + exit(); + } + if (!$this->request->passesCSRFCheck()) { + $this->send('error', 'Possible CSRF attack. Connection will be closed.'); + $this->close(); + exit(); + } + flush(); + } + + /** + * send a message to the client + * + * @param string $type + * @param mixed $data + * + * @throws \BadMethodCallException + * if only one parameter is given, a typeless message will be send with that parameter as data + * @suppress PhanDeprecatedFunction + */ + public function send($type, $data = null) { + if ($data and !preg_match('/^[A-Za-z0-9_]+$/', $type)) { + throw new BadMethodCallException('Type needs to be alphanumeric ('. $type .')'); + } + $this->init(); + if (is_null($data)) { + $data = $type; + $type = null; + } + if ($this->fallback) { + $response = '' . PHP_EOL; + echo $response; + } else { + if ($type) { + echo 'event: ' . $type . PHP_EOL; + } + echo 'data: ' . json_encode($data, JSON_HEX_TAG) . PHP_EOL; + } + echo PHP_EOL; + flush(); + } + + /** + * close the connection of the event source + */ + public function close() { + $this->send('__internal__', 'close'); //server side closing can be an issue, let the client do it + } +} diff --git a/lib/private/EventSourceFactory.php b/lib/private/EventSourceFactory.php index 197c8bf9e6c..2fff93f7176 100644 --- a/lib/private/EventSourceFactory.php +++ b/lib/private/EventSourceFactory.php @@ -27,20 +27,12 @@ use OCP\IEventSourceFactory; use OCP\IRequest; class EventSourceFactory implements IEventSourceFactory { - private IRequest $request; - - - public function __construct(IRequest $request) { - $this->request = $request; + public function __construct( + private IRequest $request, + ) { } - /** - * Create a new event source - * - * @return IEventSource - * @since 28.0.0 - */ public function create(): IEventSource { - return new \OC_EventSource($this->request); + return new EventSource($this->request); } } diff --git a/lib/private/legacy/OC_EventSource.php b/lib/private/legacy/OC_EventSource.php deleted file mode 100644 index 49fde4a214f..00000000000 --- a/lib/private/legacy/OC_EventSource.php +++ /dev/null @@ -1,134 +0,0 @@ - - * @author Christian Oliff - * @author Christoph Wurst - * @author Felix Moeller - * @author Lukas Reschke - * @author Morris Jobke - * @author Robin Appelman - * @author Thomas Müller - * - * @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 - * - */ -class OC_EventSource implements \OCP\IEventSource { - /** - * @var bool - */ - private $fallback; - - /** - * @var int - */ - private $fallBackId = 0; - - /** - * @var bool - */ - private $started = false; - - private IRequest $request; - - public function __construct(IRequest $request) { - $this->request = $request; - } - - protected function init() { - if ($this->started) { - return; - } - $this->started = true; - - // prevent php output buffering, caching and nginx buffering - OC_Util::obEnd(); - header('Cache-Control: no-cache'); - header('X-Accel-Buffering: no'); - $this->fallback = isset($_GET['fallback']) and $_GET['fallback'] == 'true'; - if ($this->fallback) { - $this->fallBackId = (int)$_GET['fallback_id']; - /** - * FIXME: The default content-security-policy of ownCloud forbids inline - * JavaScript for security reasons. IE starting on Windows 10 will - * however also obey the CSP which will break the event source fallback. - * - * As a workaround thus we set a custom policy which allows the execution - * of inline JavaScript. - * - * @link https://github.com/owncloud/core/issues/14286 - */ - header("Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'"); - header("Content-Type: text/html"); - echo str_repeat('' . PHP_EOL, 10); //dummy data to keep IE happy - } else { - header("Content-Type: text/event-stream"); - } - if (!$this->request->passesStrictCookieCheck()) { - header('Location: '.\OC::$WEBROOT); - exit(); - } - if (!$this->request->passesCSRFCheck()) { - $this->send('error', 'Possible CSRF attack. Connection will be closed.'); - $this->close(); - exit(); - } - flush(); - } - - /** - * send a message to the client - * - * @param string $type - * @param mixed $data - * - * @throws \BadMethodCallException - * if only one parameter is given, a typeless message will be send with that parameter as data - * @suppress PhanDeprecatedFunction - */ - public function send($type, $data = null) { - if ($data and !preg_match('/^[A-Za-z0-9_]+$/', $type)) { - throw new BadMethodCallException('Type needs to be alphanumeric ('. $type .')'); - } - $this->init(); - if (is_null($data)) { - $data = $type; - $type = null; - } - if ($this->fallback) { - $response = '' . PHP_EOL; - echo $response; - } else { - if ($type) { - echo 'event: ' . $type . PHP_EOL; - } - echo 'data: ' . json_encode($data, JSON_HEX_TAG) . PHP_EOL; - } - echo PHP_EOL; - flush(); - } - - /** - * close the connection of the event source - */ - public function close() { - $this->send('__internal__', 'close'); //server side closing can be an issue, let the client do it - } -} -- cgit v1.2.3 From d7ed056160a4f32e9e536bea0d934bbf97354ea4 Mon Sep 17 00:00:00 2001 From: Côme Chilliet Date: Thu, 16 May 2024 17:33:30 +0200 Subject: fix: Improve code quality in EventSource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/private/EventSource.php | 30 ++++++++++-------------------- lib/private/EventSourceFactory.php | 3 +++ lib/public/IEventSource.php | 2 ++ 3 files changed, 15 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/private/EventSource.php b/lib/private/EventSource.php index 9a62d13a938..b5ab22d026e 100644 --- a/lib/private/EventSource.php +++ b/lib/private/EventSource.php @@ -1,5 +1,7 @@ request = $request; + public function __construct( + private IRequest $request, + ) { } - protected function init() { + protected function init(): void { if ($this->started) { return; } @@ -108,7 +98,7 @@ class EventSource implements IEventSource { */ public function send($type, $data = null) { if ($data and !preg_match('/^[A-Za-z0-9_]+$/', $type)) { - throw new BadMethodCallException('Type needs to be alphanumeric ('. $type .')'); + throw new \BadMethodCallException('Type needs to be alphanumeric ('. $type .')'); } $this->init(); if (is_null($data)) { diff --git a/lib/private/EventSourceFactory.php b/lib/private/EventSourceFactory.php index 2fff93f7176..52ed0749692 100644 --- a/lib/private/EventSourceFactory.php +++ b/lib/private/EventSourceFactory.php @@ -1,4 +1,7 @@ * diff --git a/lib/public/IEventSource.php b/lib/public/IEventSource.php index 879b365cc77..f24c0311f24 100644 --- a/lib/public/IEventSource.php +++ b/lib/public/IEventSource.php @@ -37,6 +37,7 @@ interface IEventSource { * * @param string $type One of success, notice, error, failure and done. Used in core/js/update.js * @param mixed $data + * @return void * * if only one parameter is given, a typeless message will be send with that parameter as data * @since 8.0.0 @@ -45,6 +46,7 @@ interface IEventSource { /** * close the connection of the event source + * @return void * @since 8.0.0 */ public function close(); -- cgit v1.2.3