From 482cc4dfca3cf414587a9a1a70683caafe3bfa79 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Thu, 11 Dec 2025 16:32:31 -0500 Subject: [PATCH 01/18] wip --- resources/lib/UnityHTTPD.php | 2 +- resources/lib/UnityMailer.php | 2 -- resources/lib/UnityWebhook.php | 5 ----- resources/lib/utils.php | 5 +++++ resources/mail/footer.php | 2 +- resources/mail/group_created.php | 2 +- resources/mail/group_request_admin.php | 2 +- resources/mail/group_user_added.php | 2 +- resources/mail/group_user_request_owner.php | 2 +- resources/mail/user_loginshell.php | 2 +- resources/mail/user_qualified.php | 2 +- resources/mail/user_sshkey.php | 2 +- resources/templates/footer.php | 10 ++++----- resources/templates/header.php | 23 ++++++++------------- webroot/admin/pi-mgmt.php | 2 +- webroot/admin/user-mgmt.php | 2 +- webroot/panel/account.php | 2 +- webroot/panel/groups.php | 8 +++---- webroot/panel/modal/new_key.php | 12 +++++++---- webroot/panel/modal/new_pi.php | 2 +- webroot/panel/new_account.php | 2 +- webroot/panel/pi.php | 2 +- 22 files changed, 46 insertions(+), 49 deletions(-) diff --git a/resources/lib/UnityHTTPD.php b/resources/lib/UnityHTTPD.php index 7952a176..f434c808 100644 --- a/resources/lib/UnityHTTPD.php +++ b/resources/lib/UnityHTTPD.php @@ -42,7 +42,7 @@ public static function die(mixed $x = null, bool $show_user = false): never */ public static function redirect(?string $dest = null): never { - $dest ??= pathJoin(CONFIG["site"]["prefix"], $_SERVER["REQUEST_URI"]); + $dest ??= getURL($_SERVER["REQUEST_URI"]); $dest = htmlspecialchars($dest); header("Location: $dest"); http_response_code(302); diff --git a/resources/lib/UnityMailer.php b/resources/lib/UnityMailer.php index 51a1aeba..da5b85ef 100644 --- a/resources/lib/UnityMailer.php +++ b/resources/lib/UnityMailer.php @@ -13,7 +13,6 @@ class UnityMailer extends PHPMailer private string $template_dir = __DIR__ . "/../mail"; // location of all email templates private string $override_template_dir = __DIR__ . "/../../deployment/mail_overrides"; - private string $MSG_LINKREF; private string $MSG_SENDER_EMAIL; private string $MSG_SENDER_NAME; private string $MSG_SUPPORT_EMAIL; @@ -28,7 +27,6 @@ public function __construct() parent::__construct(); $this->isSMTP(); - $this->MSG_LINKREF = CONFIG["site"]["url"] . CONFIG["site"]["prefix"]; $this->MSG_SENDER_EMAIL = CONFIG["mail"]["sender"]; $this->MSG_SENDER_NAME = CONFIG["mail"]["sender_name"]; $this->MSG_SUPPORT_EMAIL = CONFIG["mail"]["support"]; diff --git a/resources/lib/UnityWebhook.php b/resources/lib/UnityWebhook.php index 80203762..522b644a 100644 --- a/resources/lib/UnityWebhook.php +++ b/resources/lib/UnityWebhook.php @@ -7,13 +7,8 @@ class UnityWebhook private string $template_dir = __DIR__ . "/../mail"; private string $override_template_dir = __DIR__ . "/../../deployment/mail_overrides"; private string $url = CONFIG["webhook"]["url"]; - private string $MSG_LINKREF; private string $Subject; // set by template - public function __construct() - { - $this->MSG_LINKREF = CONFIG["site"]["url"] . CONFIG["site"]["prefix"]; - } public function htmlToMarkdown(string $html): string { // Define regex patterns for each markdown format diff --git a/resources/lib/utils.php b/resources/lib/utils.php index a9a04aa8..e3270e51 100644 --- a/resources/lib/utils.php +++ b/resources/lib/utils.php @@ -82,3 +82,8 @@ function pathJoin() } return preg_replace("#/+#", "/", join("/", $paths)); } + +function getURL(...$args) +{ + return pathJoin([CONFIG["site"]["url"], CONFIG["site"]["prefix"], ...$args]); +} diff --git a/resources/mail/footer.php b/resources/mail/footer.php index 9e6a712b..5b133d07 100644 --- a/resources/mail/footer.php +++ b/resources/mail/footer.php @@ -3,7 +3,7 @@ > You are receiving this email because you have an account - on the Unity Cluster. + on the Unity Cluster. If you would like to stop receiving these emails, you may request to close your account by replying to this email. diff --git a/resources/mail/group_created.php b/resources/mail/group_created.php index 618ef57f..b4c64481 100644 --- a/resources/mail/group_created.php +++ b/resources/mail/group_created.php @@ -8,7 +8,7 @@

Your request for a PI account on the Unity cluster has been approved. You can access the management page for your group -on this page. +">on this page.

Do not hesitate to reply if you have any questions!

diff --git a/resources/mail/group_request_admin.php b/resources/mail/group_request_admin.php index 8fe51027..96fefac4 100644 --- a/resources/mail/group_request_admin.php +++ b/resources/mail/group_request_admin.php @@ -19,6 +19,6 @@

You can approve this account -here +">here .

diff --git a/resources/mail/group_user_added.php b/resources/mail/group_user_added.php index 9c42b8cc..379ae751 100644 --- a/resources/mail/group_user_added.php +++ b/resources/mail/group_user_added.php @@ -6,7 +6,7 @@

Hello,

You have been approved to join the PI group . -Navigate to the my groups +Navigate to the ">my groups page to see your PI groups.

If you believe this to be a mistake, please reply to this email as soon as possible.

diff --git a/resources/mail/group_user_request_owner.php b/resources/mail/group_user_request_owner.php index 9ad4db55..9c32b1e4 100644 --- a/resources/mail/group_user_request_owner.php +++ b/resources/mail/group_user_request_owner.php @@ -22,4 +22,4 @@

You can approve or deny this user on the - my users page

+ ">my users page

diff --git a/resources/mail/user_loginshell.php b/resources/mail/user_loginshell.php index c21337dd..4197b9e1 100644 --- a/resources/mail/user_loginshell.php +++ b/resources/mail/user_loginshell.php @@ -7,6 +7,6 @@

You have updated your login shell on the Unity cluster to . You can view the login shell settings on the -account settings page

+">account settings page

If you believe this to be a mistake, please reply to this email as soon as possible.

diff --git a/resources/mail/user_qualified.php b/resources/mail/user_qualified.php index 512930c3..4241bf28 100644 --- a/resources/mail/user_qualified.php +++ b/resources/mail/user_qualified.php @@ -15,6 +15,6 @@

Please login to the web portal to access Unity. If you need console access, you will need to set your SSH keys in the - account settings page.

+ ">account settings page.

If you believe this to be a mistake, please reply to this email as soon as possible.

diff --git a/resources/mail/user_sshkey.php b/resources/mail/user_sshkey.php index 5a4a8076..20619c63 100644 --- a/resources/mail/user_sshkey.php +++ b/resources/mail/user_sshkey.php @@ -15,7 +15,7 @@

You can view the SSH public keys attached to your account on the -account settings +">account settings page.

diff --git a/resources/templates/footer.php b/resources/templates/footer.php index e5cd3d2c..66d1254d 100644 --- a/resources/templates/footer.php +++ b/resources/templates/footer.php @@ -10,7 +10,7 @@ for ($i = 0; $i < count($footer_logos); $i++) { echo " - "; } ?> @@ -30,9 +30,9 @@ - - - - + + + + diff --git a/resources/templates/header.php b/resources/templates/header.php index 3ab4d742..3e165f50 100644 --- a/resources/templates/header.php +++ b/resources/templates/header.php @@ -10,7 +10,7 @@ && ($_POST["form_type"] ?? null) == "clearView" ) { unset($_SESSION["viewUser"]); - UnityHTTPD::redirect(CONFIG["site"]["prefix"] . "/admin/user-mgmt.php"); + UnityHTTPD::redirect(getURL("/admin/user-mgmt.php")); } // Webroot files need to handle their own POSTs before loading the header // so that they can do UnityHTTPD::badRequest before anything else has been printed. @@ -26,7 +26,7 @@ !$_SESSION["user_exists"] && !str_ends_with($_SERVER['PHP_SELF'], "/panel/new_account.php") ) { - UnityHTTPD::redirect(CONFIG["site"]["prefix"] . "/panel/new_account.php"); + UnityHTTPD::redirect(getURL("/panel/new_account.php")); } } @@ -51,15 +51,10 @@ - - - - - - "; + foreach (["global", "navbar", "tables", "filters", "messages"] as $x) { + $url = getURL("css/$x.css"); + echo ""; + } ?> @@ -72,11 +67,11 @@
/assets/"> + src=""> @@ -138,7 +133,7 @@
- +
diff --git a/webroot/admin/pi-mgmt.php b/webroot/admin/pi-mgmt.php index b4e82554..45b5c6a4 100644 --- a/webroot/admin/pi-mgmt.php +++ b/webroot/admin/pi-mgmt.php @@ -146,7 +146,7 @@ class="filterSearch" } }); - var ajax_url = "/admin/ajax/get_group_members.php?gid="; + var ajax_url = "?gid="; You are curently a qualified user on the Unity Cluster

"; } else { $tos_url = CONFIG["site"]["terms_of_service_url"]; - $sitePrefix = CONFIG["site"]["prefix"]; + $sitePrefix = substr(getURL(""), strlen(CONFIG["site"]["url"]), -1); echo "

You are currently an unqualified user, and will be diff --git a/webroot/panel/groups.php b/webroot/panel/groups.php index 1cf7b8f7..8601a240 100644 --- a/webroot/panel/groups.php +++ b/webroot/panel/groups.php @@ -126,14 +126,14 @@ echo " You are only a member of your own PI group. Navigate to the - my users + my users page to see your group. "; } if (count($PIGroupGIDs) == 0) { echo "You are not a member of any groups. Request to join a PI using the button below, - or request your own PI account on the account settings page"; } @@ -185,11 +185,11 @@ "; } From e4b8fc93e58588fbd51d273004a4ab073ef469f0 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 08:53:15 -0500 Subject: [PATCH 10/18] dev environment does not have https --- defaults/config.ini.default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defaults/config.ini.default b/defaults/config.ini.default index 11d6140b..443111cc 100644 --- a/defaults/config.ini.default +++ b/defaults/config.ini.default @@ -8,7 +8,7 @@ repo = "https://github.com/UnityHPC/unity-web-portal" ; Upstream URL for the we [site] prefix = "" ; prefix of website, no ending / should be included name = "Unity Cluster" ; Name of the website -url = "https://127.0.0.1:8000/" ; URL of the website +url = "http://127.0.0.1:8000/" ; URL of the website description = "The Unity Web Portal is a lightweight HPC cluster front-end" ; Description of the website logo = "logo.png" ; path to logo file, in the webroot/assets/branding folder terms_of_service_url = "https://github.com" ; this can be external or a portal page created with "content management" From bec6b1ead3f0c685d462c6246d583a9ecda70ecf Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 08:53:26 -0500 Subject: [PATCH 11/18] respect URL scheme in pathJoin --- resources/lib/utils.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/resources/lib/utils.php b/resources/lib/utils.php index 65f14d04..b396c2e7 100644 --- a/resources/lib/utils.php +++ b/resources/lib/utils.php @@ -72,15 +72,22 @@ function mbDetectEncoding(string $string, ?array $encodings = null, mixed $_ = n } /* https://stackoverflow.com/a/15575293/18696276 */ -function pathJoin() +function pathNormalize(string $path) { - $paths = []; - foreach (func_get_args() as $arg) { - if ($arg !== "") { - $paths[] = $arg; - } + return preg_replace("#/+#", "/", $path); +} + +function pathJoin(...$path_components) +{ + $path = join("/", $path_components); + // if URL starts with a "scheme" like "https://", do not try to alter the slashes in the scheme + if (preg_match("#^\w+://#", $path)) { + $matches = []; + preg_match("#(^\w+://)(.*)#", $path, $matches); + return $matches[1] . pathNormalize($matches[2]); + } else { + return pathNormalize($path); } - return preg_replace("#/+#", "/", join("/", $paths)); } function getURL(...$path_components) From 3cebda2648537d5f0e622a314be9484dc6980216 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 09:15:10 -0500 Subject: [PATCH 12/18] rename --- resources/lib/utils.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/lib/utils.php b/resources/lib/utils.php index b396c2e7..14a23e06 100644 --- a/resources/lib/utils.php +++ b/resources/lib/utils.php @@ -90,15 +90,15 @@ function pathJoin(...$path_components) } } -function getURL(...$path_components) +function getURL(...$url_components) { - return pathJoin(CONFIG["site"]["url"], CONFIG["site"]["prefix"], ...$path_components); + return pathJoin(CONFIG["site"]["url"], CONFIG["site"]["prefix"], ...$url_components); } -function getHyperlink($text, ...$path_components) +function getHyperlink($text, ...$url_components) { $text = htmlspecialchars($text); - $path_components = array_map("htmlspecialchars", $path_components); - $url = getURL(...$path_components); + $url_components = array_map("htmlspecialchars", $url_components); + $url = getURL(...$url_components); return "$text"; } From 6a83ea55c364eb884d30cd2e19ac42fbe255362f Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 09:17:47 -0500 Subject: [PATCH 13/18] refactor --- resources/lib/utils.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/resources/lib/utils.php b/resources/lib/utils.php index 14a23e06..bcb5d816 100644 --- a/resources/lib/utils.php +++ b/resources/lib/utils.php @@ -77,24 +77,23 @@ function pathNormalize(string $path) return preg_replace("#/+#", "/", $path); } -function pathJoin(...$path_components) +function getURL(...$relative_url_components) { - $path = join("/", $path_components); + $url_components = array_merge( + [CONFIG["site"]["url"], CONFIG["site"]["prefix"]], + $relative_url_components, + ); + $url = join("/", $url_components); // if URL starts with a "scheme" like "https://", do not try to alter the slashes in the scheme - if (preg_match("#^\w+://#", $path)) { + if (preg_match("#^\w+://#", $url)) { $matches = []; - preg_match("#(^\w+://)(.*)#", $path, $matches); + preg_match("#(^\w+://)(.*)#", $url, $matches); return $matches[1] . pathNormalize($matches[2]); } else { - return pathNormalize($path); + return pathNormalize($url); } } -function getURL(...$url_components) -{ - return pathJoin(CONFIG["site"]["url"], CONFIG["site"]["prefix"], ...$url_components); -} - function getHyperlink($text, ...$url_components) { $text = htmlspecialchars($text); From 63b375aa59db97b2abeaaf3590582850c3ad7611 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 09:25:58 -0500 Subject: [PATCH 14/18] add unit tests --- test/unit/UtilsTest.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/unit/UtilsTest.php b/test/unit/UtilsTest.php index f5ee8ba8..0ccf76f0 100644 --- a/test/unit/UtilsTest.php +++ b/test/unit/UtilsTest.php @@ -79,4 +79,29 @@ public function testTestValidSSHKey(bool $expected, string $key) { $this->assertEquals($expected, testValidSSHKey($key)); } + + public static function URLComponentProvider() + { + if (CONFIG["site"]["prefix"] != "http://127.0.0.1:8000") { + throw new RuntimeException("site prefix has changed!"); + } + return [ + [["", ""], "http://127.0.0.1:8000"], + [["", "/"], "http://127.0.0.1:8000/"], + [["/", "a"], "http://127.0.0.1:8000/a"], + [["/", "/a"], "http://127.0.0.1:8000/a"], + [["abc", "def"], "http://127.0.0.1:8000/abc/def"], + [["abc", "/def"], "http://127.0.0.1:8000/abc/def"], + [["/abc", "def"], "http://127.0.0.1:8000/abc/def"], + [["/abc", "def///"], "http://127.0.0.1:8000/abc/def/"], + [["", "foo.jpg"], "http://127.0.0.1:8000/foo.jpg"], + [["dir", "0", "a.jpg"], "http://127.0.0.1:8000/dir/0/a.jpg"], + ]; + } + + #[DataProvider("URLComponentProvider")] + public function testGetURL(array $relative_url_components, string $expected) + { + $this->assertEquals($expected, getURL(...$relative_url_components)); + } } From 1495c4c9bec3ecbe3c68466162b1a2d2dffcae09 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 09:40:02 -0500 Subject: [PATCH 15/18] rewrite getURL --- resources/lib/utils.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/resources/lib/utils.php b/resources/lib/utils.php index bcb5d816..4250cfd6 100644 --- a/resources/lib/utils.php +++ b/resources/lib/utils.php @@ -79,19 +79,15 @@ function pathNormalize(string $path) function getURL(...$relative_url_components) { - $url_components = array_merge( - [CONFIG["site"]["url"], CONFIG["site"]["prefix"]], - $relative_url_components, - ); - $url = join("/", $url_components); - // if URL starts with a "scheme" like "https://", do not try to alter the slashes in the scheme - if (preg_match("#^\w+://#", $url)) { - $matches = []; - preg_match("#(^\w+://)(.*)#", $url, $matches); - return $matches[1] . pathNormalize($matches[2]); - } else { - return pathNormalize($url); + if (!preg_match("#^\w+://#", CONFIG["site"]["url"])) { + throw new RuntimeException('CONFIG[site][url] does not have a scheme! (ex: "https://")'); } + $matches = []; + preg_match("#(^\w+://)(.*)#", CONFIG["site"]["url"], $matches); + [$_, $site_url_scheme, $site_url_noscheme] = $matches; + $path = join("/", [$site_url_noscheme, CONFIG["site"]["prefix"], ...$relative_url_components]); + $path_normalized = pathNormalize($path); + return $site_url_scheme . $path_normalized; } function getHyperlink($text, ...$url_components) From 08cf60b594aacd85f085cffacd0ddc7a85dbcb4e Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Fri, 12 Dec 2025 09:41:46 -0500 Subject: [PATCH 16/18] fix test --- test/unit/UtilsTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/UtilsTest.php b/test/unit/UtilsTest.php index 0ccf76f0..3fd04c33 100644 --- a/test/unit/UtilsTest.php +++ b/test/unit/UtilsTest.php @@ -82,11 +82,11 @@ public function testTestValidSSHKey(bool $expected, string $key) public static function URLComponentProvider() { - if (CONFIG["site"]["prefix"] != "http://127.0.0.1:8000") { - throw new RuntimeException("site prefix has changed!"); + if (CONFIG["site"]["url"] != "http://127.0.0.1:8000/") { + throw new RuntimeException("site url has changed!"); } return [ - [["", ""], "http://127.0.0.1:8000"], + [["", ""], "http://127.0.0.1:8000/"], [["", "/"], "http://127.0.0.1:8000/"], [["/", "a"], "http://127.0.0.1:8000/a"], [["/", "/a"], "http://127.0.0.1:8000/a"], From cbdbbbfba9d0012f461c93f741d1f4617357ffc1 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Mon, 15 Dec 2025 10:06:57 -0500 Subject: [PATCH 17/18] remove htmlspecialchars --- resources/lib/UnityHTTPD.php | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/lib/UnityHTTPD.php b/resources/lib/UnityHTTPD.php index f434c808..77e9bc7c 100644 --- a/resources/lib/UnityHTTPD.php +++ b/resources/lib/UnityHTTPD.php @@ -43,7 +43,6 @@ public static function die(mixed $x = null, bool $show_user = false): never public static function redirect(?string $dest = null): never { $dest ??= getURL($_SERVER["REQUEST_URI"]); - $dest = htmlspecialchars($dest); header("Location: $dest"); http_response_code(302); if (CONFIG["site"]["enable_redirect_message"]) { From 430aeea35310ce7b7b96e5b43bb086bc13c9d397 Mon Sep 17 00:00:00 2001 From: Simon Leary Date: Mon, 15 Dec 2025 11:19:51 -0500 Subject: [PATCH 18/18] remove htmlspecialchars --- resources/lib/utils.php | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/lib/utils.php b/resources/lib/utils.php index 4250cfd6..9c281145 100644 --- a/resources/lib/utils.php +++ b/resources/lib/utils.php @@ -93,7 +93,6 @@ function getURL(...$relative_url_components) function getHyperlink($text, ...$url_components) { $text = htmlspecialchars($text); - $url_components = array_map("htmlspecialchars", $url_components); $url = getURL(...$url_components); return "$text"; }