From 7cb8a56b6a6c9f928c7a0e7f00e719770af1b823 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Fri, 9 May 2025 12:23:25 +0200 Subject: [PATCH 1/3] Don't access APP:$observer directly in core Introduce helper functions to access the various fields of the xchan stored in `App::$observer'. This removes direct access to the attribute from core, with the aim of allowing further refactoring later. We can not yet make the `App::$observer` attribute private, though, as it is also accessed directly by some addons. --- boot.php | 39 ++++++++++++++++++++++++++++-- include/security.php | 8 +++--- tests/unit/Module/MagicTest.php | 8 +++--- tests/unit/includes/BBCodeTest.php | 7 +++--- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/boot.php b/boot.php index 41a3ed855..e2751ec2d 100644 --- a/boot.php +++ b/boot.php @@ -2151,11 +2151,12 @@ function dba_timer() { } /** - * @brief Returns xchan_hash from the observer. + * Get the unique hash identifying the current observer. * * Observer can be a local or remote channel. * - * @return string xchan_hash from observer, otherwise empty string if no observer + * @return string Unique hash of observer, otherwise empty string if no + * observer */ function get_observer_hash() { $observer = App::get_observer(); @@ -2166,6 +2167,40 @@ function get_observer_hash() { return ''; } +/** + * Get the guid of the current observer. + * + * Observer can be a local or remote channel. + * + * @return string The GUID of the observer, otherwise empty string if no + * observer + */ +function get_observer_guid() { + $observer = App::get_observer(); + if (is_array($observer)) { + return $observer['xchan_guid']; + } + + return ''; +} + +/** + * Get the name of the current observer. + * + * Observer can be a local or remote channel. + * + * @return string The name of the observer, otherwise empty string if no + * observer + */ +function get_observer_name() { + $observer = App::get_observer(); + if (is_array($observer)) { + return $observer['xchan_name']; + } + + return ''; +} + /** * @brief Returns the complete URL of the current page, e.g.: http(s)://something.com/network * diff --git a/include/security.php b/include/security.php index 2e0497498..de85f45f6 100644 --- a/include/security.php +++ b/include/security.php @@ -607,7 +607,7 @@ function public_permissions_sql($observer_hash) { function get_form_security_token($typename = '') { $timestamp = time(); - $guid = App::$observer['xchan_guid'] ?? ''; + $guid = get_observer_guid(); $sec_hash = hash('whirlpool', $guid . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $timestamp . $typename); return $timestamp . '.' . $sec_hash; @@ -623,7 +623,7 @@ function check_form_security_token($typename = '', $formname = 'form_security_to if (time() > (IntVal($x[0]) + $max_livetime)) return false; - $sec_hash = hash('whirlpool', App::$observer['xchan_guid'] . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $x[0] . $typename); + $sec_hash = hash('whirlpool', get_observer_guid() . ((local_channel()) ? App::$channel['channel_prvkey'] : '') . session_id() . $x[0] . $typename); return ($sec_hash == $x[1]); } @@ -635,7 +635,7 @@ function check_form_security_std_err_msg() { function check_form_security_token_redirectOnErr($err_redirect, $typename = '', $formname = 'form_security_token') { if (!check_form_security_token($typename, $formname)) { - logger('check_form_security_token failed: user ' . App::$observer['xchan_name'] . ' - form element ' . $typename); + logger('check_form_security_token failed: user ' . get_observer_name() . ' - form element ' . $typename); logger('check_form_security_token failed: _REQUEST data: ' . print_r($_REQUEST, true), LOGGER_DATA); notice(check_form_security_std_err_msg()); goaway(z_root() . $err_redirect); @@ -644,7 +644,7 @@ function check_form_security_token_redirectOnErr($err_redirect, $typename = '', function check_form_security_token_ForbiddenOnErr($typename = '', $formname = 'form_security_token') { if (!check_form_security_token($typename, $formname)) { - logger('check_form_security_token failed: user ' . App::$observer['xchan_name'] . ' - form element ' . $typename); + logger('check_form_security_token failed: user ' . get_observer_name() . ' - form element ' . $typename); logger('check_form_security_token failed: _REQUEST data: ' . print_r($_REQUEST, true), LOGGER_DATA); header('HTTP/1.1 403 Forbidden'); killme(); diff --git a/tests/unit/Module/MagicTest.php b/tests/unit/Module/MagicTest.php index 4a03d9d57..2c426bf76 100644 --- a/tests/unit/Module/MagicTest.php +++ b/tests/unit/Module/MagicTest.php @@ -46,9 +46,9 @@ class MagicTest extends TestCase { App::set_baseurl($baseurl); - App::$observer = [ + App::set_observer([ 'xchan_hash' => 'the hash', - ]; + ]); // We pass a local URL, and have a valid observer, but as the // delegate param is not passed, nothing will be done except @@ -72,9 +72,9 @@ class MagicTest extends TestCase { App::$timezone = 'UTC'; // Simulate a foreign (to this hub) observer, - App::$observer = [ + App::set_observer([ 'xchan_hash' => 'foreign hash', - ]; + ]); // Create the channel the foreign observer wants to access $result = create_identity([ diff --git a/tests/unit/includes/BBCodeTest.php b/tests/unit/includes/BBCodeTest.php index 136fc6e0e..50475efea 100644 --- a/tests/unit/includes/BBCodeTest.php +++ b/tests/unit/includes/BBCodeTest.php @@ -23,6 +23,7 @@ namespace Zotlabs\Tests\Unit\includes; +use App; use Zotlabs\Tests\Unit\UnitTestCase; class BBCodeTest extends UnitTestCase { @@ -42,7 +43,7 @@ class BBCodeTest extends UnitTestCase { */ public function test_bbcode_observer(string $src, bool $logged_in, string $lang, string $expected): void { if ($logged_in) { - \App::$observer = [ + App::set_observer([ 'xchan_addr' => '', 'xchan_name' => '', 'xchan_connurl' => '', @@ -50,9 +51,9 @@ class BBCodeTest extends UnitTestCase { // port required in xchan url due to bug in get_rpost_path 'xchan_url' => 'https://example.com:666', - ]; + ]); } else { - \App::$observer = null; + App::set_observer(null); } \App::$language = $lang; From e70870ce4ef49e21c50fb9c05b97411222bd43d8 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Fri, 9 May 2025 13:41:45 +0200 Subject: [PATCH 2/3] Move observer helper functions to separate source The main goal was to move the functions out of the already overcrowded `boot.php`. While I would ideally have liked to move them properly under a namespace under `Zotlabs\`, that would break too much existing code at this point. Thus leaving it in include and under the global namespace for now. --- boot.php | 52 +------------------------------------- include/observer.php | 60 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 51 deletions(-) create mode 100644 include/observer.php diff --git a/boot.php b/boot.php index e2751ec2d..e88e2960c 100644 --- a/boot.php +++ b/boot.php @@ -49,6 +49,7 @@ require_once('include/text.php'); require_once('include/datetime.php'); require_once('include/language.php'); require_once('include/nav.php'); +require_once('include/observer.php'); require_once('include/permissions.php'); require_once('include/features.php'); require_once('include/taxonomy.php'); @@ -2150,57 +2151,6 @@ function dba_timer() { return microtime(true); } -/** - * Get the unique hash identifying the current observer. - * - * Observer can be a local or remote channel. - * - * @return string Unique hash of observer, otherwise empty string if no - * observer - */ -function get_observer_hash() { - $observer = App::get_observer(); - if (is_array($observer)) { - return $observer['xchan_hash']; - } - - return ''; -} - -/** - * Get the guid of the current observer. - * - * Observer can be a local or remote channel. - * - * @return string The GUID of the observer, otherwise empty string if no - * observer - */ -function get_observer_guid() { - $observer = App::get_observer(); - if (is_array($observer)) { - return $observer['xchan_guid']; - } - - return ''; -} - -/** - * Get the name of the current observer. - * - * Observer can be a local or remote channel. - * - * @return string The name of the observer, otherwise empty string if no - * observer - */ -function get_observer_name() { - $observer = App::get_observer(); - if (is_array($observer)) { - return $observer['xchan_name']; - } - - return ''; -} - /** * @brief Returns the complete URL of the current page, e.g.: http(s)://something.com/network * diff --git a/include/observer.php b/include/observer.php new file mode 100644 index 000000000..98c5002f7 --- /dev/null +++ b/include/observer.php @@ -0,0 +1,60 @@ + + * + * SPDX-License-Identifier: MIT + */ + +/** + * Get the unique hash identifying the current observer. + * + * Observer can be a local or remote channel. + * + * @return string Unique hash of observer, otherwise empty string if no + * observer + */ +function get_observer_hash() { + $observer = App::get_observer(); + if (is_array($observer)) { + return $observer['xchan_hash']; + } + + return ''; +} + +/** + * Get the guid of the current observer. + * + * Observer can be a local or remote channel. + * + * @return string The GUID of the observer, otherwise empty string if no + * observer + */ +function get_observer_guid() { + $observer = App::get_observer(); + if (is_array($observer)) { + return $observer['xchan_guid']; + } + + return ''; +} + +/** + * Get the name of the current observer. + * + * Observer can be a local or remote channel. + * + * @return string The name of the observer, otherwise empty string if no + * observer + */ +function get_observer_name() { + $observer = App::get_observer(); + if (is_array($observer)) { + return $observer['xchan_name']; + } + + return ''; +} From 8141ef95118bc17eff6bb580a232c59a3bea8125 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Fri, 9 May 2025 15:12:50 +0200 Subject: [PATCH 3/3] Add some API docs for the observer file --- include/observer.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/observer.php b/include/observer.php index 98c5002f7..4483e1d8b 100644 --- a/include/observer.php +++ b/include/observer.php @@ -6,6 +6,14 @@ * SPDX-FileContributor: Harald Eilertsen * * SPDX-License-Identifier: MIT + * + * The _observer_ in Hubzilla is the channel visiting the site in the current + * session. This could be a local channel, or a remote channel logged in via + * OpenWebAuth. + * + * If the observer is not set, or empty, this indicates an unauthenticated + * visitor, which may mean a visitor from another site that don't support, or + * has not enabled OpenWebAuth. */ /**