feat: move ssoenabled to a boolean flag rather than ids

This commit is contained in:
Eli Bosley
2025-01-21 11:13:08 -05:00
parent 428ad15ec7
commit 6f5edb2406
8 changed files with 67 additions and 43 deletions

View File

@@ -18,5 +18,5 @@ echo $wcExtractor->getScriptTagHtml();
?> ?>
<unraid-i18n-host> <unraid-i18n-host>
<unraid-sso-button subids="<?= $serverState->ssoSubIds ?>"></unraid-sso-button> <unraid-sso-button ssoenabled="<?= $serverState->ssoEnabled ?>"></unraid-sso-button>
</unraid-i18n-host> </unraid-i18n-host>

View File

@@ -8,6 +8,7 @@
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
*/ */
/** /**
* @todo refactor globals currently if you try to use $GLOBALS the class will break. * @todo refactor globals currently if you try to use $GLOBALS the class will break.
*/ */
@@ -56,7 +57,7 @@ class ServerState
/** /**
* SSO Sub IDs from the my servers config file. * SSO Sub IDs from the my servers config file.
*/ */
public $ssoSubIds = ''; public $ssoEnabled = false;
private $osVersion; private $osVersion;
private $osVersionBranch; private $osVersionBranch;
private $rebootDetails; private $rebootDetails;
@@ -71,7 +72,7 @@ class ServerState
public $myServersMemoryCfg = []; public $myServersMemoryCfg = [];
public $host = 'unknown'; public $host = 'unknown';
public $combinedKnownOrigins = []; public $combinedKnownOrigins = [];
public $nginxCfg = []; public $nginxCfg = [];
public $flashbackupStatus = []; public $flashbackupStatus = [];
public $registered = false; public $registered = false;
@@ -90,7 +91,7 @@ class ServerState
* @see - getWebguiGlobal() for usage * @see - getWebguiGlobal() for usage
* */ * */
global $webguiGlobals; global $webguiGlobals;
$this->webguiGlobals =& $webguiGlobals; $this->webguiGlobals = &$webguiGlobals;
// echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>"; // echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>";
$this->var = (array)parse_ini_file('state/var.ini'); $this->var = (array)parse_ini_file('state/var.ini');
@@ -123,7 +124,8 @@ class ServerState
/** /**
* Retrieve the value of a webgui global setting. * Retrieve the value of a webgui global setting.
*/ */
public function getWebguiGlobal(string $key, string $subkey = null) { public function getWebguiGlobal(string $key, string $subkey = null)
{
if (!$subkey) { if (!$subkey) {
return _var($this->webguiGlobals, $key, ''); return _var($this->webguiGlobals, $key, '');
} }
@@ -131,7 +133,8 @@ class ServerState
return _var($keyArray, $subkey, ''); return _var($keyArray, $subkey, '');
} }
private function setConnectValues() { private function setConnectValues()
{
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) { if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) {
$this->connectPluginInstalled = 'dynamix.unraid.net.plg'; $this->connectPluginInstalled = 'dynamix.unraid.net.plg';
} }
@@ -158,13 +161,15 @@ class ServerState
$this->getFlashBackupStatus(); $this->getFlashBackupStatus();
} }
private function getFlashBackupStatus() { private function getFlashBackupStatus()
{
$flashbackupCfg = '/var/local/emhttp/flashbackup.ini'; $flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
$this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : []; $this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : [];
$this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true'; $this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true';
} }
private function getMyServersCfgValues() { private function getMyServersCfgValues()
{
/** /**
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg… * @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg'; * - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
@@ -197,10 +202,11 @@ class ServerState
$this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled; $this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled;
$this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? ''; $this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? '';
$this->username = $this->myServersFlashCfg['remote']['username'] ?? ''; $this->username = $this->myServersFlashCfg['remote']['username'] ?? '';
$this->ssoSubIds = $this->myServersFlashCfg['remote']['ssoSubIds'] ?? ''; $this->ssoEnabled = $this->myServersFlashCfg['remote']['ssoSubIds'] !== '';
} }
private function getConnectKnownOrigins() { private function getConnectKnownOrigins()
{
/** /**
* Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins. * Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins.
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost. * Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
@@ -208,7 +214,7 @@ class ServerState
$this->host = $_SERVER['HTTP_HOST'] ?? "unknown"; $this->host = $_SERVER['HTTP_HOST'] ?? "unknown";
$memoryCfgPath = '/var/local/emhttp/myservers.cfg'; $memoryCfgPath = '/var/local/emhttp/myservers.cfg';
$this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : []; $this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : [];
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph']??'') === 'CONNECTED'); $this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph'] ?? '') === 'CONNECTED');
$allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? ""; $allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? "";
$extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? ""; $extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? "";
@@ -224,8 +230,8 @@ class ServerState
$this->combinedKnownOrigins = explode(",", $combinedOrigins); $this->combinedKnownOrigins = explode(",", $combinedOrigins);
if ($this->combinedKnownOrigins) { if ($this->combinedKnownOrigins) {
foreach($this->combinedKnownOrigins as $key => $origin) { foreach ($this->combinedKnownOrigins as $key => $origin) {
if ( (strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false) ) { if ((strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false)) {
// clean up $this->combinedKnownOrigins, only display warning if origins still remain to display // clean up $this->combinedKnownOrigins, only display warning if origins still remain to display
unset($this->combinedKnownOrigins[$key]); unset($this->combinedKnownOrigins[$key]);
} }
@@ -238,7 +244,8 @@ class ServerState
} }
} }
private function detectActivationCode() { private function detectActivationCode()
{
// Fresh server and we're not loading with a callback param to install // Fresh server and we're not loading with a callback param to install
if ($this->state !== 'ENOKEYFILE' || !empty($_GET['c'])) { if ($this->state !== 'ENOKEYFILE' || !empty($_GET['c'])) {
return; return;
@@ -312,6 +319,7 @@ class ServerState
"registered" => $this->registered, "registered" => $this->registered,
"registeredTime" => $this->registeredTime, "registeredTime" => $this->registeredTime,
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'), "site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
"ssoEnabled" => $this->ssoEnabled,
"state" => $this->state, "state" => $this->state,
"theme" => [ "theme" => [
"banner" => !empty($this->getWebguiGlobal('display', 'banner')), "banner" => !empty($this->getWebguiGlobal('display', 'banner')),
@@ -326,7 +334,6 @@ class ServerState
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))), "uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
"username" => $this->username, "username" => $this->username,
"wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '', "wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '',
"ssoSubIds" => $this->ssoSubIds
]; ];
if ($this->combinedKnownOrigins) { if ($this->combinedKnownOrigins) {
@@ -357,7 +364,8 @@ class ServerState
* *
* @return string * @return string
*/ */
public function getServerStateJson() { public function getServerStateJson()
{
return json_encode($this->getServerState()); return json_encode($this->getServerState());
} }
@@ -366,7 +374,8 @@ class ServerState
* *
* @return string * @return string
*/ */
public function getServerStateJsonForHtmlAttr() { public function getServerStateJsonForHtmlAttr()
{
$json = json_encode($this->getServerState()); $json = json_encode($this->getServerState());
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8'); return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
} }

View File

@@ -181,7 +181,7 @@ export const serverState: Server = {
regExp, regExp,
regGuid, regGuid,
site: 'http://localhost:4321', site: 'http://localhost:4321',
ssoSubIds: '1234567890,0987654321,297294e2-b31c-4bcc-a441-88aee0ad609f', ssoEnabled: true,
state, state,
theme: { theme: {
banner: false, banner: false,

View File

@@ -3,7 +3,7 @@ import Button from '~/components/Brand/Button.vue';
import { ACCOUNT } from '~/helpers/urls'; import { ACCOUNT } from '~/helpers/urls';
export interface Props { export interface Props {
subids?: string; ssoenabled?: boolean;
} }
const props = defineProps<Props>(); const props = defineProps<Props>();
@@ -34,25 +34,39 @@ const generateStateToken = (): string => {
return state; return state;
}; };
onMounted(() => { onMounted(async () => {
const search = new URLSearchParams(window.location.search); try {
const token = search.get('token') ?? ''; const search = new URLSearchParams(window.location.search);
const state = search.get('state') ?? ''; const code = search.get('code') ?? '';
const sessionState = getStateToken(); const state = search.get('state') ?? '';
if (token && state === sessionState) { const sessionState = getStateToken();
enterCallbackTokenIntoField(token);
// Clear the token from the URL if (code && state === sessionState) {
window.history.replaceState({}, document.title, window.location.pathname); const token = await fetch(new URL('token', ACCOUNT), {
window.location.search = ''; method: 'POST',
body: new URLSearchParams({
code,
clientId: 'CONNECT_SERVER_SSO',
grant_type: 'authorization_code',
}),
});
if (token.ok) {
const tokenBody = await token.json();
enterCallbackTokenIntoField(tokenBody.access_token);
if (window.location.search) {
window.history.replaceState({}, document.title, window.location.pathname);
window.location.search = '';
}
}
}
} catch (err) {
console.error('Error fetching token', err);
} finally {
} }
}); });
const externalSSOUrl = computed<string>(() => { const externalSSOUrl = computed<string>(() => {
if (props.subids === undefined) {
return '';
}
const url = new URL('sso', ACCOUNT); const url = new URL('sso', ACCOUNT);
url.searchParams.append('uids', props.subids);
const callbackUrlLogin = new URL('login', window.location.origin); const callbackUrlLogin = new URL('login', window.location.origin);
const state = generateStateToken(); const state = generateStateToken();
callbackUrlLogin.searchParams.append('state', state); callbackUrlLogin.searchParams.append('state', state);
@@ -63,7 +77,7 @@ const externalSSOUrl = computed<string>(() => {
</script> </script>
<template> <template>
<template v-if="props.subids"> <template v-if="props.ssoenabled === true">
<Button target="_blank" :href="externalSSOUrl">Sign In With Unraid.net Account</Button> <Button target="_blank" :href="externalSSOUrl">Sign In With Unraid.net Account</Button>
</template> </template>
</template> </template>

View File

@@ -156,7 +156,7 @@ onMounted(() => {
<div class="bg-background"> <div class="bg-background">
<hr class="border-black dark:border-white" /> <hr class="border-black dark:border-white" />
<h2 class="text-xl font-semibold font-mono">SSO Button Component</h2> <h2 class="text-xl font-semibold font-mono">SSO Button Component</h2>
<SsoButtonCe :subids="serverState.ssoSubIds" /> <SsoButtonCe :ssoEnabled="serverState.ssoEnabled" />
</div> </div>
</div> </div>
</client-only> </client-only>

View File

@@ -80,7 +80,7 @@ onBeforeMount(() => {
<h3 class="text-lg font-semibold font-mono"> <h3 class="text-lg font-semibold font-mono">
SSOSignInButtonCe SSOSignInButtonCe
</h3> </h3>
<unraid-sso-button :subids="serverState.ssoSubIds" /> <unraid-sso-button :ssoEnabled="serverState.ssoEnabled" />
</unraid-i18n-host> </unraid-i18n-host>
</client-only> </client-only>
</template> </template>

View File

@@ -155,7 +155,7 @@ export const useServerStore = defineStore("server", () => {
return today.isAfter(parsedUpdateExpirationDate, "day"); return today.isAfter(parsedUpdateExpirationDate, "day");
}); });
const site = ref<string>(""); const site = ref<string>("");
const ssoSubIds = ref<string>(""); const ssoEnabled = ref<boolean>(false);
const state = ref<ServerState>(); const state = ref<ServerState>();
const theme = ref<Theme>(); const theme = ref<Theme>();
watch(theme, (newVal) => { watch(theme, (newVal) => {
@@ -1209,8 +1209,8 @@ export const useServerStore = defineStore("server", () => {
if (typeof data?.regTo !== "undefined") { if (typeof data?.regTo !== "undefined") {
regTo.value = data.regTo; regTo.value = data.regTo;
} }
if (typeof data?.ssoSubIds !== "undefined") { if (typeof data?.ssoEnabled !== "undefined") {
ssoSubIds.value = data.ssoSubIds; ssoEnabled.value = Boolean(data.ssoEnabled);
} }
if (typeof data.activationCodeData !== "undefined") { if (typeof data.activationCodeData !== "undefined") {
@@ -1478,7 +1478,7 @@ export const useServerStore = defineStore("server", () => {
parsedRegExp, parsedRegExp,
regUpdatesExpired, regUpdatesExpired,
site, site,
ssoSubIds, ssoEnabled,
state, state,
theme, theme,
updateOsIgnoredReleases, updateOsIgnoredReleases,

View File

@@ -1,7 +1,8 @@
import type { Config, PartialCloudFragment } from '~/composables/gql/graphql'; import type { Config, PartialCloudFragment } from '~/composables/gql/graphql';
import type { ActivationCodeData } from '~/store/activationCode';
import type { Theme } from '~/store/theme'; import type { Theme } from '~/store/theme';
import type { UserProfileLink } from '~/types/userProfile'; import type { UserProfileLink } from '~/types/userProfile';
import type { ActivationCodeData } from '~/store/activationCode';
export type ServerState = 'BASIC' export type ServerState = 'BASIC'
| 'PLUS' | 'PLUS'
@@ -108,6 +109,7 @@ export interface Server {
regExp?: number; regExp?: number;
regUpdatesExpired?: boolean; regUpdatesExpired?: boolean;
site?: string; site?: string;
ssoEnabled?: boolean;
state?: ServerState; state?: ServerState;
theme?: Theme | undefined; theme?: Theme | undefined;
updateOsIgnoredReleases?: string[]; updateOsIgnoredReleases?: string[];
@@ -117,7 +119,6 @@ export interface Server {
username?: string; username?: string;
wanFQDN?: string; wanFQDN?: string;
wanIp?: string; wanIp?: string;
ssoSubIds?: string;
} }
export interface ServerAccountCallbackSendPayload { export interface ServerAccountCallbackSendPayload {
@@ -196,4 +197,4 @@ export interface ServerStateData {
message: string; message: string;
error?: ServerStateDataError | boolean; error?: ServerStateDataError | boolean;
withKey?: boolean; // @todo potentially remove withKey?: boolean; // @todo potentially remove
} }