diff --git a/deployment/config.base.ini b/deployment/config.base.ini
index 4fad60ad2..cf60d2f5a 100644
--- a/deployment/config.base.ini
+++ b/deployment/config.base.ini
@@ -1,6 +1,6 @@
; DO NOT EDIT THIS FILE. Copy this file to `config.ini` and edit that file.
[upstream]
-version = "1.7.4" ; Current upstream version of the account portal
+version = "1.7.6" ; Current upstream version of the account portal
repo = "https://github.com/UnityHPC/account-portal" ; Upstream URL for the account portal
[site]
diff --git a/resources/lib/UnityHTTPD.php b/resources/lib/UnityHTTPD.php
index 95dad81e6..b4e7b7e21 100644
--- a/resources/lib/UnityHTTPD.php
+++ b/resources/lib/UnityHTTPD.php
@@ -33,17 +33,24 @@ public static function die(?string $x = null): never
}
}
+ public static function redirectOverrideMethodGet(?string $dest = null): never
+ {
+ self::redirect(dest: $dest, preserve_request_method: false);
+ }
+
/*
send HTTP header, set HTTP response code,
print a message just in case the browser fails to redirect if PHP is not being run from the CLI,
and then die
*/
- public static function redirect(?string $dest = null): never
- {
+ public static function redirect(
+ ?string $dest = null,
+ bool $preserve_request_method = true,
+ ): never {
$dest ??= getRelativeURL($_SERVER["REQUEST_URI"]);
// TODO check $_SERVER["REDIRECT_STATUS"]?
header("Location: $dest");
- http_response_code(302);
+ http_response_code($preserve_request_method ? 307 : 303);
if (CONFIG["site"]["enable_redirect_message"]) {
echo "If you're reading this message, then your browser has failed to redirect you " .
"to the proper destination. click here to continue.";
@@ -81,10 +88,11 @@ public static function gracefulDie(
self::errorLog($log_title, $log_message, data: $data, error: $error, errorid: $errorid);
if (
($_SERVER["REQUEST_METHOD"] ?? "") == "POST" &&
- !str_starts_with($_SERVER["REQUEST_URI"], "/lan/api/")
+ !str_starts_with($_SERVER["REQUEST_URI"], "/lan/api/") &&
+ !str_starts_with($_SERVER["REQUEST_URI"], "/panel/ajax/")
) {
self::messageError($title, implode("\n", $body_paragraphs));
- self::redirect();
+ self::redirectOverrideMethodGet();
} else {
if (!headers_sent()) {
http_response_code($http_response_code);
@@ -239,10 +247,21 @@ public static function errorHandler(
return false;
}
+ public static function assertRequestMethod(string $expected): void
+ {
+ if (($found = $_SERVER["REQUEST_METHOD"] ?? "") != $expected) {
+ UnityHTTPD::badRequest(
+ "expected request method '$expected', got '$found'",
+ "invalid request method",
+ );
+ }
+ }
+
public static function getPostData(string $key): string
{
+ self::assertRequestMethod("POST");
if (!array_key_exists($key, $_POST)) {
- self::badRequest("\$_POST has no array key '$key'");
+ self::badRequest("\$_POST has no array key '$key'", data: ['$_POST' => $_POST]);
}
return $_POST[$key];
}
@@ -254,7 +273,7 @@ public static function getQueryParameter(string $key, bool $die_if_not_found = t
{
if (!array_key_exists($key, $_GET)) {
if ($die_if_not_found) {
- self::badRequest("\$_GET has no array key '$key'");
+ self::badRequest("\$_GET has no array key '$key'", data: ['$_GET' => $_GET]);
} else {
return null;
}
@@ -417,7 +436,7 @@ public static function validatePostCSRFToken(): void
"Invalid Session Token",
"This can happen if you leave your browser open for too long. Error ID: $errorid",
);
- self::redirect();
+ self::redirectOverrideMethodGet();
}
}
diff --git a/resources/templates/header.html.twig b/resources/templates/header.html.twig
index f4013b5e5..df35c2cdf 100644
--- a/resources/templates/header.html.twig
+++ b/resources/templates/header.html.twig
@@ -101,9 +101,7 @@
- {% if messages|length >= 3 %}
-
- {% endif %}
+
{% set level_enum = enum('UnityWebPortal\\lib\\UnityHTTPDMessageLevel') %}
{% for message in messages|reverse %}
{% set title = message[0] %}
diff --git a/resources/templates/header.php b/resources/templates/header.php
index 3f2f4be8b..36d33858f 100644
--- a/resources/templates/header.php
+++ b/resources/templates/header.php
@@ -11,7 +11,7 @@
&& ($_POST["form_type"] ?? null) == "clearView"
) {
unset($_SESSION["viewUser"]);
- UnityHTTPD::redirect(getRelativeURL("admin/user-mgmt.php"));
+ UnityHTTPD::redirectOverrideMethodGet(getRelativeURL("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.
@@ -19,7 +19,7 @@
// header also needs to handle POST data. So this header does the PRG redirect
// for all pages.
unset($_POST); // unset ensures that header must not come before POST handling
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
if (isset($SSO)) {
diff --git a/webroot/admin/pi-mgmt.php b/webroot/admin/pi-mgmt.php
index 18b1fb479..a86c1fd82 100644
--- a/webroot/admin/pi-mgmt.php
+++ b/webroot/admin/pi-mgmt.php
@@ -49,7 +49,7 @@
$group = new UnityGroup(UnityHTTPD::getPostData("pi"), $LDAP, $SQL, $MAILER);
if ($group->getIsDisabled()) {
UnityHTTPD::messageError("Cannot Disable PI Group", "Group is already disabled");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
$group->disable();
UnityHTTPD::messageSuccess("Group Disabled", $group->gid);
diff --git a/webroot/admin/user-mgmt.php b/webroot/admin/user-mgmt.php
index 098ccb8be..181155774 100644
--- a/webroot/admin/user-mgmt.php
+++ b/webroot/admin/user-mgmt.php
@@ -14,7 +14,7 @@
switch ($_POST["form_type"]) {
case "viewAsUser":
$_SESSION["viewUser"] = $_POST["uid"];
- UnityHTTPD::redirect(getRelativeURL("panel/account.php"));
+ UnityHTTPD::redirectOverrideMethodGet(getRelativeURL("panel/account.php"));
break; /** @phpstan-ignore deadCode.unreachable */
}
}
diff --git a/webroot/js/messages.js b/webroot/js/messages.js
index 36eeead33..1f885aecd 100644
--- a/webroot/js/messages.js
+++ b/webroot/js/messages.js
@@ -1,15 +1,18 @@
-function hideClearAllMessagesButtonIfAllMessagesAlreadyCleared() {
+function updateClearMessagesButtonVisibility(minMessageCount = 3) {
var visibleMessages = $('#messages .message:visible').length;
- if (visibleMessages === 0) {
+ if (visibleMessages >= minMessageCount) {
+ $('#clear_all_messages_button').show();
+ } else {
$('#clear_all_messages_button').hide();
}
}
$(document).ready(function () {
+ updateClearMessagesButtonVisibility();
+
$('#messages').on('click', '.message button', function () {
var button = $(this);
var message = button.parent();
- message.hide();
$.ajax({
url: '/panel/ajax/delete_message.php',
method: 'POST',
@@ -18,14 +21,27 @@ $(document).ready(function () {
'title': button.data('title'),
'body': button.data('body')
},
+ success: function () {
+ message.hide();
+ updateClearMessagesButtonVisibility();
+ },
error: function (result) {
$("#messages").append(result.responseText);
}
});
- hideClearAllMessagesButtonIfAllMessagesAlreadyCleared();
});
$('#clear_all_messages_button').on('click', function () {
- $('#messages .message:visible button').click();
+ $.ajax({
+ url: '/panel/ajax/clear_messages.php',
+ method: 'POST',
+ success: function () {
+ $('#messages .message').hide();
+ $('#clear_all_messages_button').hide();
+ },
+ error: function (result) {
+ $("#messages").append(result.responseText);
+ }
+ });
});
});
diff --git a/webroot/lan/api/bump-last-login.php b/webroot/lan/api/bump-last-login.php
index de377c1c7..49d469248 100644
--- a/webroot/lan/api/bump-last-login.php
+++ b/webroot/lan/api/bump-last-login.php
@@ -4,9 +4,7 @@
use UnityWebPortal\lib\UnityHTTPD;
-if ($_SERVER["REQUEST_METHOD"] !== "POST") {
- UnityHTTPD::badRequest("invalid request method {$_SERVER['REQUEST_METHOD']}");
-}
+UnityHTTPD::assertRequestMethod("POST");
UnityHTTPD::validateAPIKey();
$uid = UnityHTTPD::getQueryParameter("uid");
$SQL->updateUserLastLogin($uid);
diff --git a/webroot/panel/account.php b/webroot/panel/account.php
index 468c6a11d..a78a0a8b2 100644
--- a/webroot/panel/account.php
+++ b/webroot/panel/account.php
@@ -26,7 +26,7 @@
} catch (EncodingUnknownException | EncodingConversionException $e) {
UnityHTTPD::errorLog("uploaded key has bad encoding", "", error: $e);
UnityHTTPD::messageError("SSH Key Not Added: Invalid Encoding", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
break;
case "generate":
@@ -40,7 +40,7 @@
"No Keys Added",
"No keys found associated with GitHub account."
);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
break;
default:
@@ -77,7 +77,7 @@
$stub_fingprint = substr($sha256_fingerprint, 0, 6);
UnityHTTPD::messageSuccess("SSH Key Added", "Fingerprint: $stub_fingprint");
}
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "delKey":
$key = _base64_decode(UnityHTTPD::getPostData("delKey"));
@@ -86,10 +86,10 @@
$USER->removeSSHKey($key);
} catch (ArrayKeyException) {
UnityHTTPD::messageError("Cannot Remove SSH Key", "Key not found");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
UnityHTTPD::messageSuccess("SSH Key Removed", "$key_short");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "loginshell":
$shell = UnityHTTPD::getPostData("shellSelect");
@@ -98,32 +98,32 @@
}
$USER->setLoginShell($shell);
UnityHTTPD::messageSuccess("Login Shell Changed", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "pi_request":
if ($USER->isPI()) {
UnityHTTPD::messageError("Cannot Submit PI Request", "Already a PI");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
if ($SQL->requestExists($USER->uid, UnitySQL::REQUEST_BECOME_PI)) {
UnityHTTPD::messageError("Cannot Submit PI Request", "This request already exists");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
if ($_POST["tos"] != "agree") {
UnityHTTPD::badRequest("user did not agree to terms of service");
}
$USER->getPIGroup()->requestGroup();
UnityHTTPD::messageSuccess("PI Group Requested", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "cancel_pi_request":
if (!$SQL->requestExists($USER->uid, UnitySQL::REQUEST_BECOME_PI)) {
UnityHTTPD::messageError("Cannot Cancel PI Request", "No PI request found");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
$USER->getPIGroup()->cancelGroupRequest();
UnityHTTPD::messageSuccess("PI Request Cancelled", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "disable":
if ($hasGroups) {
@@ -131,14 +131,14 @@
"Cannot Disable",
"You are a PI or you are a member of at least one PI group"
);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
if ($USER->getFlag(UserFlag::DISABLED)) {
UnityHTTPD::badRequest("user is already disabled", "");
}
$USER->disable(UnityUserDisabledReason::DisabledSelf);
UnityHTTPD::messageSuccess("Account Disabled", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
}
}
diff --git a/webroot/panel/ajax/clear_messages.php b/webroot/panel/ajax/clear_messages.php
new file mode 100644
index 000000000..5bd52af6f
--- /dev/null
+++ b/webroot/panel/ajax/clear_messages.php
@@ -0,0 +1,9 @@
+reEnable();
UnityHTTPD::messageSuccess("Account Re-Enabled", "");
- UnityHTTPD::redirect(getRelativeURL("panel/account.php"));
+ UnityHTTPD::redirectOverrideMethodGet(getRelativeURL("panel/account.php"));
}
}
require getTemplatePath("header.php");
diff --git a/webroot/panel/groups.php b/webroot/panel/groups.php
index cd7f8533d..0af20e478 100644
--- a/webroot/panel/groups.php
+++ b/webroot/panel/groups.php
@@ -12,7 +12,7 @@
$pi_group = new UnityGroup($gid, $LDAP, $SQL, $MAILER);
if (!$pi_group->exists()) {
UnityHTTPD::messageError("This PI Doesn't Exist", $gid);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
return $pi_group;
};
@@ -32,28 +32,28 @@
"Invalid Group Membership Request",
"You've already requested this"
);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
if ($pi_account->memberUIDExists($USER->uid)) {
UnityHTTPD::messageError(
"Invalid Group Membership Request",
"You're already in this PI group"
);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
}
$pi_account->newUserRequest($USER);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "removePIForm":
$pi_account = $getPIGroupFromPost();
$pi_account->removeUser($USER, UnityGroupUserRemovedReason::RemovedSelf);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
case "cancelPIForm":
$pi_account = $getPIGroupFromPost();
$pi_account->cancelGroupJoinRequest($USER);
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
break; /** @phpstan-ignore deadCode.unreachable */
}
}
diff --git a/webroot/panel/new_account.php b/webroot/panel/new_account.php
index ec2f2b8e4..4ec9b2741 100644
--- a/webroot/panel/new_account.php
+++ b/webroot/panel/new_account.php
@@ -11,7 +11,7 @@
if (UnityHTTPD::getPostData("form_type") === "register") {
UnityHTTPD::validatePostCSRFToken();
$USER->init($SSO["firstname"], $SSO["lastname"], $SSO["mail"], $SSO["org"]);
- UnityHTTPD::redirect(getRelativeURL("panel/account.php"));
+ UnityHTTPD::redirectOverrideMethodGet(getRelativeURL("panel/account.php"));
}
}
require getTemplatePath("header.php");
diff --git a/webroot/panel/pi.php b/webroot/panel/pi.php
index 7043b71da..e6ca7f351 100644
--- a/webroot/panel/pi.php
+++ b/webroot/panel/pi.php
@@ -41,11 +41,11 @@
if ($_POST["action"] == "Approve") {
$group->approveUser($form_user);
UnityHTTPD::messageSuccess("User Approved", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
} elseif ($_POST["action"] == "Deny") {
$group->denyUser($form_user);
UnityHTTPD::messageSuccess("User Denied", "");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
} else {
UnityHTTPD::badRequest(sprintf("unrecognized action: '%s'", $_POST["action"]), "");
}
@@ -57,9 +57,9 @@
UnityHTTPD::messageSuccess("User Removed", "");
// group manager removed themself
if ($USER->uid === $form_user->uid) {
- UnityHTTPD::redirect("/panel/groups.php");
+ UnityHTTPD::redirectOverrideMethodGet("/panel/groups.php");
} else {
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
break; /** @phpstan-ignore deadCode.unreachable */
case "disable":
@@ -68,15 +68,15 @@
}
if (count($group->getMemberUIDs()) > 1) {
UnityHTTPD::messageError("Cannot Disable PI Group", "Group still has members");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
if ($group->getIsDisabled()) {
UnityHTTPD::messageError("Cannot Disable PI Group", "Group is already disabled");
- UnityHTTPD::redirect();
+ UnityHTTPD::redirectOverrideMethodGet();
}
$group->disable();
UnityHTTPD::messageSuccess("Group Disabled", "");
- UnityHTTPD::redirect(getRelativeURL("panel/account.php"));
+ UnityHTTPD::redirectOverrideMethodGet(getRelativeURL("panel/account.php"));
break; /** @phpstan-ignore deadCode.unreachable */
}
}