diff --git a/plugin/plugins/dynamix.unraid.net.plg b/plugin/plugins/dynamix.unraid.net.plg index 0b918ec6e..f3e5a64d3 100755 --- a/plugin/plugins/dynamix.unraid.net.plg +++ b/plugin/plugins/dynamix.unraid.net.plg @@ -165,6 +165,9 @@ version= # shellcheck disable=SC1091 source /etc/unraid-version +# Undo some activation / partner setup +source /usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove + echo echo "⚠️ Do not close this window yet" echo @@ -741,10 +744,6 @@ if [ "${PLGTYPE}" = "production" ] || [ ! -f /boot/config/plugins/dynamix.my.ser echo "env=\"${PLGTYPE}\"">/boot/config/plugins/dynamix.my.servers/env fi -echo -echo "⚠️ Do not close this window yet" -echo - # Use myservers.cfg values to help prevent conflicts when installing CFG=/boot/config/plugins/dynamix.my.servers/myservers.cfg # shellcheck disable=SC1090 @@ -838,9 +837,9 @@ preventDowngradeAction() { } # Extract "ts" values from both files - plgWebComponentPath="/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components" - backupWebComponentPath="/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components-" - plgManifestTs=$(extract_ts "$plgWebComponentPath/manifest.json") +plgWebComponentPath="/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components" +backupWebComponentPath="/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components-" +plgManifestTs=$(extract_ts "$plgWebComponentPath/manifest.json") webguiManifestTs=$(extract_ts "$backupWebComponentPath/manifest.json") # Compare the "ts" values and return the file path of the higher value @@ -854,6 +853,14 @@ if [[ "$webguiManifestTs" -gt "$plgManifestTs" ]]; then echo "♻️ Reverted to stock web component files" fi +echo +echo "⚠️ Do not close this window yet" +echo + +# Activation and partner setup +# - Must come after the web component timestamp check to avoid potentially targeting the wrong JS during this setup +source /usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_setup + # Install the API (previously in rc.d script) echo "Extracting and installing the Unraid API" @@ -885,21 +892,10 @@ ln -sf /usr/local/bin/unraid-api /usr/bin/unraid-api # bail if expected file does not exist [[ ! -f "${api_base_directory}/package.json" ]] && echo "unraid-api install failed" && exit 1 -# Start a background process to wait for /var/local/emhttp/var.ini -( timeout=30 elapsed=0 - while (( elapsed < timeout )); do - if [ -f /var/local/emhttp/var.ini ]; then - logger "Starting flash backup (if enabled)" - echo "/etc/rc.d/rc.flash_backup start" | at -M now &>/dev/null - logger "Starting Unraid API" - ${unraid_binary_path} start - exit 0 - fi - sleep 1 - (( elapsed++ )) - done - echo "Timeout waiting for /var/local/emhttp/var.ini" -) & +logger "Starting flash backup (if enabled)" +echo "/etc/rc.d/rc.flash_backup start" | at -M now &>/dev/null +logger "Starting Unraid API" +${unraid_binary_path} start echo echo "✅ Installation is complete, it is safe to close this window" diff --git a/plugin/scripts/rsync-activation-dir.sh b/plugin/scripts/rsync-activation-dir.sh new file mode 100755 index 000000000..5696eed7f --- /dev/null +++ b/plugin/scripts/rsync-activation-dir.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# Bash script to sync local activation code directory to the correct location on the Unraid server's boot device + +# Usage: ./sync_files.sh --local-directory [--remote-user ] [--remote-host ] [--remote-path ] + +# Example usage 0 +# ./plugin/scripts/rsync-activation-dir.sh --local-directory /Users/zack/Downloads/activation_code_pdfs_12_19_2024_1436 + +# Path to store the last used remote host +state_file="$HOME/.deploy_state" + +# Read the last used remote host from the state file +if [[ -f "$state_file" ]]; then + LAST_REMOTE_HOST=$(cat "$state_file") +else + LAST_REMOTE_HOST="" +fi + +# Default values +REMOTE_USER="root" +REMOTE_PATH="/boot/config/activation" + +# Parse named flag parameters +while [[ $# -gt 0 ]]; do + case $1 in + --local-directory) + LOCAL_DIRECTORY="$2" + shift 2 + ;; + --remote-user) + REMOTE_USER="$2" + shift 2 + ;; + --remote-host) + REMOTE_HOST="$2" + shift 2 + ;; + --remote-path) + REMOTE_PATH="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + echo "Usage: $0 --local-directory [--remote-user ] [--remote-host ] [--remote-path ]" + exit 1 + ;; + esac +done + +# Validate required parameter +if [[ -z "$LOCAL_DIRECTORY" ]]; then + echo "Error: --local-directory is required." + exit 1 +fi + +# Use last remote host if none is provided +REMOTE_HOST=${REMOTE_HOST:-$LAST_REMOTE_HOST} + +# Check if remote host is provided +if [[ -z "$REMOTE_HOST" ]]; then + echo "Please provide the remote host using --remote-host." + exit 1 +fi + +# Save the current remote host to the state file +echo "$REMOTE_HOST" > "$state_file" + +# Check if local directory ends with a slash +if [[ "$LOCAL_DIRECTORY" != */ ]]; then + echo "The local directory does not end with a slash." + read -p "Do you want to append a slash to upload its contents? (y/n): " RESPONSE + if [[ "$RESPONSE" =~ ^[Yy]$ ]]; then + LOCAL_DIRECTORY+="/" + fi +fi + +# Execute the rsync command and capture its output +RSYNC_OUTPUT=$(rsync -av -e ssh "$LOCAL_DIRECTORY" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH" 2>&1) +RSYNC_EXIT_CODE=$? + +# Output the rsync command's output +echo "$RSYNC_OUTPUT" + +# Check if the command was successful +if [ $RSYNC_EXIT_CODE -eq 0 ]; then + echo "Files synchronized successfully!" +else + echo "An error occurred during synchronization." + exit 1 +fi diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/activation-data.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/activation-data.php new file mode 100644 index 000000000..ada94ff77 --- /dev/null +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/activation-data.php @@ -0,0 +1,10 @@ + +
+debug(); ?>
+
diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/server-state.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/server-state.php index 6bcffc5b3..6fd7b7872 100644 --- a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/server-state.php +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/data/server-state.php @@ -1,19 +1,5 @@ data = $this->fetchJsonData(); + } + + /** + * Fetch JSON data from all files matching the pattern. + * + * @return array Array of extracted JSON data. + */ + private function fetchJsonData(): array { + $data = []; + + if (!is_dir(self::DIR)) { + return $data; + } + + $files = scandir(self::DIR); + + if ($files === false || count($files) === 0) { + return $data; + } + + foreach ($files as $file) { + $filePath = self::DIR . DIRECTORY_SEPARATOR . $file; + + if (preg_match(self::FILE_PATTERN, $file, $matches)) { + // $activationCode = $matches[1]; + $fileContent = file_get_contents($filePath); + $jsonData = json_decode($fileContent, true); + + if (json_last_error() === JSON_ERROR_NONE) { + $data = $jsonData; + } else { + $data = ['error' => 'Invalid JSON format']; + } + + break; // Stop after the first match + } + } + + if (isset($data['partnerName'])) { + $this->partnerName = $data['partnerName']; + } + + if (isset($data['partnerUrl'])) { + $this->partnerUrl = $data['partnerUrl']; + } + + /** + * During the plg install, the partner logo asset is copied to the webgui images dir. + */ + $logo = self::DOCROOT . self::WEBGUI_IMAGES_BASE_DIR . '/' . self::PARTNER_LOGO_FILE_NAME; + if (file_exists($logo)) { + $this->partnerLogoPath = $logo; + } + + return $data; + } + + /** + * Get the partner logo path. + * + * @return string + */ + public function getPartnerLogoPath(): string { + return $this->partnerLogoPath; + } + + /** + * Get the extracted data. + * + * @return array + */ + public function getData(): array { + return $this->data; + } + + /** + * Retrieve the activation code data as JSON string with converted special characters to HTML entities + * + * @return string + */ + public function getDataForHtmlAttr(): string { + $json = json_encode($this->getData()); + return htmlspecialchars($json, ENT_QUOTES, 'UTF-8'); + } + + /** + * Get the partner logo render string. + * + * @return string + */ + public function getPartnerLogoRenderString(): string { + if (empty($this->partnerLogoPath)) { // default logo + return file_get_contents(self::DEFAULT_LOGO); + } + + return file_get_contents($this->partnerLogoPath); + } + + /** + * Get the partner name. + * + * @return string + */ + public function getPartnerName(): string { + return $this->partnerName; + } + + /** + * Get the partner URL. + * + * @return string + */ + public function getPartnerUrl(): string { + return $this->partnerUrl; + } + + /** + * Output for debugging + * + * @see https://tower.local/plugins/dynamix.my.servers/data/activation-data.php + * @return void + */ + public function debug(): void { + echo "data: "; var_dump($this->data); + echo "partnerName: "; var_dump($this->partnerName); + echo "partnerUrl: "; var_dump($this->partnerUrl); + echo "partnerLogoPath: "; var_dump($this->partnerLogoPath); + + echo $this->getPartnerLogoRenderString(); + } +} diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/myservers1.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/myservers1.php index c3cf40c1e..b9cfc44ff 100644 --- a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/myservers1.php +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/myservers1.php @@ -36,27 +36,15 @@ a[href="/Tools/Downgrade"] .icon-update:before { display: inline-block; /* required otherwise the rotation won't work */ rotate: 180deg; } +/* overriding #header .logo svg */ +#header .logo .partner-logo svg { + fill: var(--header-text-primary); + width: auto; + height: 28px; +} $value) { - if (strpos($key, $searchText) !== false && isset($value["file"])) { - $fileValue = $value["file"]; - break; - } -} - -if ($fileValue !== null) { - $prefixedPath = '/plugins/dynamix.my.servers/unraid-components/'; - echo ''; -} else { - echo ''; -} +$wcExtractor = new WebComponentsExtractor(); +echo $wcExtractor->getScriptTagHtml(); diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/partner-logo.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/partner-logo.php new file mode 100644 index 000000000..122fcaf12 --- /dev/null +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/partner-logo.php @@ -0,0 +1,14 @@ + + + diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/state.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/state.php index e037067a6..e09f6909d 100644 --- a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/state.php +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/state.php @@ -14,6 +14,7 @@ $webguiGlobals = $GLOBALS; $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp'; +require_once "$docroot/plugins/dynamix.my.servers/include/activation-code-extractor.php"; require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php"; require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php"; /** @@ -72,6 +73,8 @@ class ServerState public $registered = false; public $myServersMiniGraphConnected = false; public $keyfileBase64 = ''; + public $activationCodeData = []; + public $state = 'UNKNOWN'; /** * Constructor to initialize class properties and gather server information. @@ -89,6 +92,7 @@ class ServerState $this->var = (array)parse_ini_file('state/var.ini'); $this->nginxCfg = @parse_ini_file('/var/local/emhttp/nginx.ini') ?? []; + $this->state = strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']); $this->osVersion = $this->var['version']; $this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable'); @@ -109,6 +113,7 @@ class ServerState $this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult(); $this->setConnectValues(); + $this->detectActivationCode(); } /** @@ -228,6 +233,22 @@ class ServerState } } + private function detectActivationCode() { + // Fresh server and we're not loading with a callback param to install + if ($this->state !== 'ENOKEYFILE' || !empty($_GET['c'])) { + return; + } + + $activationCodeData = new ActivationCodeExtractor(); + $data = $activationCodeData->getData(); + + if (empty($data)) { + return; + } + + $this->activationCodeData = $data; + } + /** * Retrieve the server information as an associative array * @@ -286,7 +307,7 @@ class ServerState "registered" => $this->registered, "registeredTime" => $this->registeredTime, "site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'), - "state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']), + "state" => $this->state, "theme" => [ "banner" => !empty($this->getWebguiGlobal('display', 'banner')), "bannerGradient" => $this->getWebguiGlobal('display', 'showBannerGradient') === 'yes' ?? false, @@ -318,6 +339,10 @@ class ServerState $serverState['updateOsResponse'] = $this->updateOsResponse; } + if ($this->activationCodeData) { + $serverState['activationCodeData'] = $this->activationCodeData; + } + return $serverState; } diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/translations.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/translations.php index 3dc1c8f25..d780e2c3c 100644 --- a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/translations.php +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/translations.php @@ -80,6 +80,7 @@ class WebComponentTranslations '

Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.

' => '

' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '

', 'A Trial key provides all the functionality of an Unleashed Registration key' => _('A Trial key provides all the functionality of an Unleashed Registration key'), 'Acklowledge that you have made a Flash Backup to enable this action' => _('Acklowledge that you have made a Flash Backup to enable this action'), + 'Activate Now' => _('Activate Now'), 'ago' => _('ago'), 'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'), 'Attached Storage Devices' => _('Attached Storage Devices'), @@ -117,6 +118,7 @@ class WebComponentTranslations 'Copy Key URL' => _('Copy Key URL'), 'Copy your Key URL: {0}' => sprintf(_('Copy your Key URL: %s'), '{0}'), 'Create Flash Backup' => _('Create Flash Backup'), + 'Create a password' => _('Create a password'), 'Current Version {0}' => sprintf(_('Current Version %s'), '{0}'), 'Current Version: Unraid {0}' => sprintf(_('Current Version: Unraid %s'), '{0}'), 'Customizable Dashboard Tiles' => _('Customizable Dashboard Tiles'), @@ -204,6 +206,7 @@ class WebComponentTranslations 'Learn more and link your key to your account' => _('Learn more and link your key to your account'), 'Learn More' => _('Learn More'), 'Learn more' => _('Learn more'), + 'Let\'s activate your Unraid license!' => _('Let\'s activate your Unraid license!'), 'Let\'s Unleash your Hardware!' => _('Let\'s Unleash your Hardware!'), 'License key actions' => _('License key actions'), 'License key type' => _('License key type'), @@ -218,6 +221,8 @@ class WebComponentTranslations 'minute' => sprintf(_('%s minute'), '{n}') . ' | ' . sprintf(_('%s minutes'), '{n}'), 'Missing key file' => _('Missing key file'), 'month' => sprintf(_('%s month'), '{n}') . ' | ' . sprintf(_('%s months'), '{n}'), + 'More about Unraid.net Accounts' => _('More about Unraid.net Accounts'), + 'More about Unraid.net' => _('More about Unraid.net'), 'More options' => _('More options'), 'Multiple License Keys Present' => _('Multiple License Keys Present'), 'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.' => _('Never ever be left without a backup of your config.') . ' ' . _('If you need to change flash drives, generate a backup from Connect and be up and running in minutes.'), @@ -302,6 +307,7 @@ class WebComponentTranslations 'SSL certificates for unraid.net deprecated' => _('SSL certificates for unraid.net deprecated'), 'Stale Server' => _('Stale Server'), 'Stale' => _('Stale'), + 'Start by creating an Unraid.net account — this will let you manage your license and access support. Once that\'s done, we\'ll guide you through a quick checkout process to register your license and install your key.' => _('Start by creating an Unraid.net account — this will let you manage your license and access support.') . ' ' . _('Once that\'s done, we\'ll guide you through a quick checkout process to register your license and install your key.'), 'Start Free 30 Day Trial' => _('Start Free 30 Day Trial'), 'Starting your free 30 day trial' => _('Starting your free 30 day trial'), 'Success!' => _('Success!'), @@ -372,6 +378,8 @@ class WebComponentTranslations 'View on Docs' => _('View on Docs'), 'View release notes' => _('View release notes'), 'We recommend backing up your USB Flash Boot Device before starting the update.' => _('We recommend backing up your USB Flash Boot Device before starting the update.'), + 'Welcome to your new ${0} system, powered by Unraid!' => _('Welcome to your new ${0} system, powered by Unraid!'), + 'Welcome to Unraid!' => _('Welcome to Unraid!'), 'year' => sprintf(_('%s year'), '{n}') . ' | ' . sprintf(_('%s years'), '{n}'), 'You are still eligible to access OS updates that were published on or before {1}.' => sprintf(_('You are still eligible to access OS updates that were published on or before %s.'), '{1}'), 'You can also manually create a new backup by clicking the Create Flash Backup button.' => _('You can also manually create a new backup by clicking the Create Flash Backup button.'), @@ -380,6 +388,7 @@ class WebComponentTranslations 'You have exceeded the number of devices allowed for your license. Please remove a device before adding another.' => _('You have exceeded the number of devices allowed for your license. Please remove a device before adding another.'), 'You have not activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have not activated the Flash Backup feature via the Unraid Connect plugin.'), 'You may still update to releases dated prior to your update expiration date.' => _('You may still update to releases dated prior to your update expiration date.'), + 'You\'re about to create a password to secure access to your system. This password is essential for managing and configuring your server. You’ll use this password every time you access the Unraid web interface.' => _('You\'re about to create a password to secure access to your system.') . ' ' . _('This password is essential for managing and configuring your server.') . ' ' . _('You’ll use this password every time you access the Unraid web interface.'), 'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'), 'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'), 'Your {0} license included one year of free updates at the time of purchase. You are now eligible to extend your license and access the latest OS updates. You are still eligible to access OS updates that were published on or before {1}.' => sprintf(_('Your %s license included one year of free updates at the time of purchase.'), '{0}') . ' ' . _('You are now eligible to extend your license and access the latest OS updates.') . ' ' . sprintf(_('You are still eligible to access OS updates that were published on or before %s.'), '{1}'), diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/web-components-extractor.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/web-components-extractor.php new file mode 100644 index 000000000..ba513ddab --- /dev/null +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/web-components-extractor.php @@ -0,0 +1,36 @@ + $value) { + if (strpos($key, self::SEARCH_TEXT) !== false && isset($value["file"])) { + $this->jsFileName = $value["file"]; + break; + } + } + } + + public function getJsFileName(): string { + return $this->jsFileName; + } + + public function getJSFileRelativePath(): string { + return self::PREFIXED_PATH . $this->jsFileName; + } + + public function getScriptTagHtml(): string { + if (empty($this->jsFileName)) { + return ''; + } + return ''; + } +} diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/welcome-modal.php b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/welcome-modal.php new file mode 100644 index 000000000..56f9ef3d1 --- /dev/null +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/welcome-modal.php @@ -0,0 +1,22 @@ +getScriptTagHtml(); +?> + + + + + diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove new file mode 100755 index 000000000..627398b88 --- /dev/null +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove @@ -0,0 +1,148 @@ +#!/bin/bash + +# ----------------------------------------------------------------------------- +# Description: +# This script resets the web GUI banners and logos on the system. It performs +# the following actions: +# - Verifies if the setup flag exists before proceeding. +# - Removes the partner logo symbolic link if it exists. +# - Restores the original web GUI banner if it was replaced by a partner banner. +# - Adjusts the display banner configuration if no custom banner is set. +# - Optionally deletes itself and an adjacent file named "activate_code_setup" +# when the "--delete" flag is passed. +# +# Usage: +# 1. Run the script for testing: +# ./usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove +# ./usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove --debug +# +# 2. Run the script with the delete flag to self-delete, should be done in the plugin's removal script: +# ./usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove --delete +# +# 3. Run the script and remove the setup flag after completion for a fresh state: +# ./usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove --debug --remove-setup-flag +# +# Prerequisites: +# - The setup flag file must exist at "/boot/config/activation/.done". +# +# Options: +# --delete Deletes the script itself and related script & php files. +# --debug Enables debug mode to display additional information. +# --remove-setup-flag Removes the setup flag after the script completes. +# +# ----------------------------------------------------------------------------- + +# Default flags +DEBUG_MODE=false +DRY_RUN=false +REMOVE_SETUP_FLAG=false +# Check for flags +for arg in "$@"; do + case $arg in + --debug) + DEBUG_MODE=true + ;; + --dry-run) + DRY_RUN=true + ;; + --remove-setup-flag) + REMOVE_SETUP_FLAG=true + ;; + *) + # You can optionally handle other arguments if needed + ;; + esac +done + +# Debug function +debug_echo() { + if [[ $DEBUG_MODE == true ]]; then + echo "[DEBUG] [activation_code_remove]: $1" + fi +} + +ACTIVATION_DIR="/boot/config/activation" +ACTIVATION_SETUP_FLAG="$ACTIVATION_DIR/.done" + +debug_echo "Checking for setup flag at $ACTIVATION_SETUP_FLAG" + +# only proceed if ACTIVATION_SETUP_FLAG exists +if [[ -f "$ACTIVATION_SETUP_FLAG" ]]; then + debug_echo "Setup flag found, proceeding with removal" + + # Restore the original auth-request and .set-password files modified for the welcome modal + AUTH_REQUEST_FILE="/usr/local/emhttp/auth-request.php" + AUTH_REQUEST_BK_FILE="$AUTH_REQUEST_FILE.bak" + rm -f "$AUTH_REQUEST_FILE" + mv -f "$AUTH_REQUEST_BK_FILE" "$AUTH_REQUEST_FILE" + + WELCOME_MODAL_INJECT_FILE="/usr/local/emhttp/plugins/dynamix/include/.set-password.php" + WELCOME_MODAL_INJECT_BK_FILE="$WELCOME_MODAL_INJECT_FILE.bak" + rm -f "$WELCOME_MODAL_INJECT_FILE" + mv -f "$WELCOME_MODAL_INJECT_BK_FILE" "$WELCOME_MODAL_INJECT_FILE" + + debug_echo "Restored auth-request and .set-password files" + + # Remove the partner logo symbolic link if it exists + WEBGUI_IMAGES_DIR="/usr/local/emhttp/webGui/images" + + PARTNER_LOGO="$WEBGUI_IMAGES_DIR/partner-logo.svg" + debug_echo "Checking for partner logo at $PARTNER_LOGO" + if [[ -L "$PARTNER_LOGO" ]]; then + rm -f "$PARTNER_LOGO" + debug_echo "Partner logo symbolic link removed" + fi + + # restores the original webgui banner if it was replaced by the partner banner + WEBGUI_BANNER_OG="$WEBGUI_IMAGES_DIR/banner.png" + WEBGUI_BANNER_BK="$WEBGUI_BANNER_OG-" + + debug_echo "Checking for original webgui banner backup at $WEBGUI_BANNER_BK" + if [[ -f $WEBGUI_BANNER_BK ]]; then + cp -f "$WEBGUI_BANNER_BK" "$WEBGUI_BANNER_OG" + rm -f "$WEBGUI_BANNER_BK" + debug_echo "Original webgui banner restored" + + # if there's not a custom banner, set display banner to no aka empty string + # otherwise leave this display setting alone to keep the user's custom banner + CUSTOM_BANNER="/boot/config/plugins/dynamix/banner.png" + + if [[ ! -f "$CUSTOM_BANNER" ]]; then + debug_echo "No custom banner found, setting display banner to no" + CONFIG_FILE="/boot/config/plugins/dynamix/dynamix.cfg" + CONFIG_SECTION="display" + CONFIG_KEY="banner" + CONFIG_NEW_VALUE="" + + sed -i -E "/\[$CONFIG_SECTION\]/,/^\[/ s/^($CONFIG_KEY=).*/\1$CONFIG_NEW_VALUE/" "$CONFIG_FILE" + debug_echo "Display banner configuration set to no" + fi + fi + + if [[ $REMOVE_SETUP_FLAG == true ]]; then + debug_echo "Removing setup flag" + rm -f "$ACTIVATION_SETUP_FLAG" + debug_echo "Setup flag removed" + fi + + if [[ $DRY_RUN == false ]]; then + debug_echo "Deleting activation code related setup and php files" + FILES_TO_DELETE=( + "/usr/local/emhttp/plugins/dynamix.my.servers/data/activation-data.php" + "/usr/local/emhttp/plugins/dynamix.my.servers/include/activation-code-extractor.php" + "/usr/local/emhttp/plugins/dynamix.my.servers/include/partner-logo.php" + "/usr/local/emhttp/plugins/dynamix.my.servers/include/welcome-modal.php" + "/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_remove" + "/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_setup" + ) + + for file in "${FILES_TO_DELETE[@]}"; do + rm -f "$file" + debug_echo "Deleted $file" + done + fi + + debug_echo "Removal complete" +else + debug_echo "Setup flag not found, doing nothing" +fi diff --git a/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_setup b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_setup new file mode 100755 index 000000000..15ddf7e32 --- /dev/null +++ b/plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/scripts/activation_code_setup @@ -0,0 +1,403 @@ +#!/bin/bash + +# ----------------------------------------------------------------------------- +# Script Name: activation_code_setup +# +# Description: +# This script sets up the activation environment by performing various tasks, +# such as setting system banners, icons, and metadata based on activation assets +# and configurations. The script ensures that activation settings are applied only +# once by using a setup flag. +# +# Key Features: +# - Verifies if the activation directory and setup flag exist before proceeding. +# - Updates partner logos, banners, and other visual assets in the system. +# - Configures system display settings (e.g., theme, colors) based on activation JSON. +# - Sets server identification (name, model, and description) if not already configured. +# - Creates a setup flag to prevent re-execution of tasks. +# +# Prerequisites: +# - Ensure that the activation directory exists at "/boot/config/activation". +# - The script requires `jq` for JSON parsing. Install it if not already available. +# +# Usage: +# 1. Run the script normally: +# ./activation_code_setup +# +# 2. Run the script with debug statements: +# ./activation_code_setup --debug +# +# Options: +# --debug Enables debug mode to display additional information. +# +# Files Used: +# - Activation JSON: A configuration file with `.activationcode` extension, located in +# the activation directory. +# - Partner assets: Logo, banner, and case model located in the "assets" subdirectory +# of the activation directory. +# - System configuration files such as: +# - `/boot/config/plugins/dynamix/dynamix.cfg` +# - `/boot/config/plugins/dynamix/case-model.cfg` +# - `/boot/config/ident.cfg` +# - System state file: `/usr/local/emhttp/state/var.ini` +# +# Notes: +# - Existing configurations will not be overwritten unless required (e.g., no backup exists). +# - Any errors during setup will print warnings but allow the script to continue. +# +# ----------------------------------------------------------------------------- + +# Default flags +DEBUG_MODE=false +# Check for flags +for arg in "$@"; do + case $arg in + --debug) + DEBUG_MODE=true + ;; + *) + # You can optionally handle other arguments if needed + ;; + esac +done + +# Debug function +debug_echo() { + if [[ $DEBUG_MODE == true ]]; then + echo "[DEBUG] [activation_code_setup]: $1" + fi +} + +ACTIVATION_DIR="/boot/config/activation" + +debug_echo "Checking for activation directory at $ACTIVATION_DIR" + +if [[ -d "$ACTIVATION_DIR" ]]; then + debug_echo "Activation directory found" + ACTIVATION_SETUP_FLAG="$ACTIVATION_DIR/.done" + ACTIVATION_JSON_EXTENSION=".activationcode" + # get the first file in the dir that matches the extension, later parsed as JSON for specific values + ACTIVATION_JSON=$(find "$ACTIVATION_DIR" -maxdepth 1 -type f -name "*$ACTIVATION_JSON_EXTENSION" | head -n 1) + PARTNER_ASSETS_DIR="$ACTIVATION_DIR/assets" + WEBGUI_IMAGES_DIR="/usr/local/emhttp/webGui/images" + + ACTIVATION_JSON_VALID=false + if [[ -f "$ACTIVATION_JSON" ]]; then + debug_echo "Activation JSON found at $ACTIVATION_JSON, validating..." + # Validate the JSON file + if jq empty "$ACTIVATION_JSON" 2>/dev/null; then + ACTIVATION_JSON_VALID=true + debug_echo "Activation JSON is valid" + else + echo "⚠️ Warning: Activation JSON is not valid, skipping setup" + fi + fi + + if [[ "$ACTIVATION_JSON_VALID" == true ]]; then + debug_echo "Activation JSON is valid, proceeding with setup" + # create the setup flag file to prevent re-running this setup + touch "$ACTIVATION_SETUP_FLAG" + + # + # Inject welcome modal into .set-password.php + # + # We first need to add files to allow them to be requested without authentication + AUTH_REQUEST_FILE="/usr/local/emhttp/auth-request.php" + WEB_COMPS_DIR="/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/_nuxt/" + mapfile -t JS_FILES < <(find "$WEB_COMPS_DIR" -type f -name "*.js" | sed 's|/usr/local/emhttp||') # modifying the path to be relative to the webgui's webroot + debug_echo "Found ${#JS_FILES[@]} .js files in $WEB_COMPS_DIR" + + FILES_TO_ADD=( + "/webGui/images/partner-logo.svg" + ) + FILES_TO_ADD+=("${JS_FILES[@]}") + + if grep -q "\$arrWhitelist" "$AUTH_REQUEST_FILE"; then + cp "$AUTH_REQUEST_FILE" "${AUTH_REQUEST_FILE}.bak" + debug_echo "Backup of $AUTH_REQUEST_FILE created at ${AUTH_REQUEST_FILE}.bak" + + # prepending items to the array as appending them to the end of the array was causing issues with trying to detect the last item with or without a comma + awk -v files_to_add="$(printf "%s\n" "${FILES_TO_ADD[@]}" | awk '{printf " \x27%s\x27,\n", $0}')" ' + BEGIN { added = 0 } + /\$arrWhitelist\s*=\s*\[/ { + print $0 + print files_to_add + added = 1 + next + } + { print } + ' "$AUTH_REQUEST_FILE" > "${AUTH_REQUEST_FILE}.tmp" + + mv "${AUTH_REQUEST_FILE}.tmp" "$AUTH_REQUEST_FILE" + debug_echo "Default values and .js files from $WEB_COMPS_DIR added to \$arrWhitelist." + else + debug_echo "\$arrWhitelist array not found in the file." + fi + # Inject the welcome modal into the .set-password.php file + WELCOME_MODAL_INJECT_FILE="/usr/local/emhttp/plugins/dynamix/include/.set-password.php" + # shellcheck disable=SC2016 + WELCOME_MODAL_INJECT_STRING='' + + if grep -q "" "$WELCOME_MODAL_INJECT_FILE"; then + cp "$WELCOME_MODAL_INJECT_FILE" "${WELCOME_MODAL_INJECT_FILE}.bak" + debug_echo "Backup of $WELCOME_MODAL_INJECT_FILE created at ${WELCOME_MODAL_INJECT_FILE}.bak" + + awk -v inject="$WELCOME_MODAL_INJECT_STRING" ' + /<\/body>/ { + print inject + } + { print } + ' "$WELCOME_MODAL_INJECT_FILE" > "${WELCOME_MODAL_INJECT_FILE}.tmp" + + mv "${WELCOME_MODAL_INJECT_FILE}.tmp" "$WELCOME_MODAL_INJECT_FILE" + debug_echo "Welcome modal injected into $WELCOME_MODAL_INJECT_FILE" + else + debug_echo "Failed to inject welcome modal into $WELCOME_MODAL_INJECT_FILE" + fi + + # copy the logo into a location that the webgui can access + PARTNER_LOGO="$PARTNER_ASSETS_DIR/logo.svg" + if [[ -f "$PARTNER_LOGO" ]]; then + debug_echo "Partner logo found" + # symlink the file to the correct destination with the correct extension + LINK_DEST="$WEBGUI_IMAGES_DIR/partner-logo.svg" + ln -sf "$PARTNER_LOGO" "$LINK_DEST" + debug_echo "Partner logo symlinked to $LINK_DEST" + else + debug_echo "No partner logo found" + fi + + # if partner banner exists and there's not a webgui banner backup file that exists on the system + # then backup the original banner and replace the original banner with the included partner banner + PARTNER_BANNER="$PARTNER_ASSETS_DIR/banner.png" + WEBGUI_BANNER_OG="$WEBGUI_IMAGES_DIR/banner.png" + WEBGUI_BANNER_BK="$WEBGUI_BANNER_OG-" + + # On uninstall of the PLG the default banner is reverted. So we won't rely on the setup flag. Instead whether the backup file doesn't exist. + debug_echo "Checking for partner banner at $PARTNER_BANNER and backup banner at $WEBGUI_BANNER_BK" + if [[ -f "$PARTNER_BANNER" && ! -f "$WEBGUI_BANNER_BK" ]]; then + debug_echo "Partner banner found at $PARTNER_BANNER" + cp -f "$WEBGUI_BANNER_OG" "$WEBGUI_BANNER_BK" 2>/dev/null + if [[ $? -ne 0 ]]; then + echo "⚠️ Warning: Failed to back up the original banner." + else + debug_echo "Original banner backed up to $WEBGUI_BANNER_BK" + fi + cp -f "$PARTNER_BANNER" "$WEBGUI_BANNER_OG" 2>/dev/null + if [[ $? -ne 0 ]]; then + echo "⚠️ Warning: Failed to replace the original banner with the partner banner." + else + debug_echo "Partner banner replaced the original banner" + fi + else + debug_echo "Skipping partner banner setup" + fi + + # + # Inject the partner logo in DefaultPageLayout + # + DEFAULT_PAGE_LAYOUT_FILE="/usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php" + # shellcheck disable=SC2016 + WEBGUI_LOGO_STRING_FIND='' + # shellcheck disable=SC2016 + PARTNER_LOGO_STRING_REPLACE='' + # if a backup of the original layout doesn't already exist, then we'll create it. + if [[ ! -f "${DEFAULT_PAGE_LAYOUT_FILE}-" ]]; then + cp -f "$DEFAULT_PAGE_LAYOUT_FILE" "${DEFAULT_PAGE_LAYOUT_FILE}-" + debug_echo "Backup of $DEFAULT_PAGE_LAYOUT_FILE created at ${DEFAULT_PAGE_LAYOUT_FILE}-" + fi + + debug_echo "Injecting partner logo into $DEFAULT_PAGE_LAYOUT_FILE" + sed -i "s|$WEBGUI_LOGO_STRING_FIND|$PARTNER_LOGO_STRING_REPLACE|" "$DEFAULT_PAGE_LAYOUT_FILE" + + if [[ $? -eq 0 ]]; then + debug_echo "Injected partner logo into $DEFAULT_PAGE_LAYOUT_FILE" + else + debug_echo "Failed to inject partner logo into $DEFAULT_PAGE_LAYOUT_FILE, awk error" + fi + + # Set the display settings, if we haven't done it once already + if ! grep -q "display" "$ACTIVATION_SETUP_FLAG"; then + debug_echo "Checking for display settings in the activation JSON" + HEADER_TEXT_COLOR=$(jq -r '.header // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + HEADER_META_COLOR=$(jq -r '.headermetacolor // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + HEADER_BG_COLOR=$(jq -r '.background // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + HEADER_SHOW_BANNER_GRADIENT=$(jq -r '.showBannerGradient // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + WEBGUI_THEME=$(jq -r '.theme // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + + # Initialize array for parameters + declare -A DISPLAY_PARAMS + + # Check if variables have values and add them to the array, while stripping any leading # from the color values b/c the settings config doesn't use them + [[ -n $HEADER_TEXT_COLOR ]] && DISPLAY_PARAMS["header"]=${HEADER_TEXT_COLOR//\#/} + [[ -n $HEADER_META_COLOR ]] && DISPLAY_PARAMS["headermetacolor"]=${HEADER_META_COLOR//\#/} + [[ -n $HEADER_BG_COLOR ]] && DISPLAY_PARAMS["background"]=${HEADER_BG_COLOR//\#/} + [[ -n $HEADER_SHOW_BANNER_GRADIENT ]] && DISPLAY_PARAMS["showBannerGradient"]=$HEADER_SHOW_BANNER_GRADIENT + [[ -n $WEBGUI_THEME ]] && DISPLAY_PARAMS["theme"]=$WEBGUI_THEME + DISPLAY_PARAMS["banner"]="image" + + debug_echo "Display settings found:" + for key in "${!DISPLAY_PARAMS[@]}"; do + debug_echo "$key: ${DISPLAY_PARAMS[$key]}" + done + + CONFIG_FILE="/boot/config/plugins/dynamix/dynamix.cfg" + CONFIG_SECTION="display" + debug_echo "Updating display settings in $CONFIG_FILE" + # Iterate over the DISPLAY_PARAMS array and update the config file + for key in "${!DISPLAY_PARAMS[@]}"; do + value=${DISPLAY_PARAMS[$key]} + debug_echo "Setting $key to $value" + + awk -v section="$CONFIG_SECTION" -v key="$key" -v value="$value" ' + BEGIN { in_section = 0; key_found = 0 } + /^\[.*\]$/ { + if (in_section && !key_found) { + # Append the key-value pair before leaving the section + print key "=" "\"" value "\"" + } + in_section = ($0 == "[" section "]") + key_found = 0 + } + { + if (in_section && $0 ~ "^" key "=") { + print key "=" "\"" value "\"" + key_found = 1 + next + } + } + { print } + END { + if (in_section && !key_found) { + # Append key-value pair at the end of the section if not found + print key "=" "\"" value "\"" + } + }' "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE" + done + + # Add what changed to the .done flag file + echo "display" >> "$ACTIVATION_SETUP_FLAG" + debug_echo "Display settings updated" + else + debug_echo "Skipping display settings setup, flag already set" + fi + + # Set the case model icon, if we haven't done it once already + if ! grep -q "case" "$ACTIVATION_SETUP_FLAG"; then + debug_echo "Check for case model icon setup" + CASE_MODEL_CFG="/boot/config/plugins/dynamix/case-model.cfg" + CUSTOM_CASE_FILE_NAME="case-model.png" + # if the system has a custom icon already set, we need to skip this step + # First preference is to use a custom icon, if it exists in the activation/assets dir + # Second preference is to use an included icon with the system that's been specified in the activation json + CURRENT_CASE_MODEL=$(cat $CASE_MODEL_CFG 2>/dev/null || true) + debug_echo "Current case model icon: $CURRENT_CASE_MODEL" + # If CURRENT_CASE_MODEL === "case-model.png" then a custom icon has already been set and we should skip this step + if [[ -n "$CURRENT_CASE_MODEL" && "$CURRENT_CASE_MODEL" != "$CUSTOM_CASE_FILE_NAME" ]]; then + PARTNER_CASE_MODEL="$PARTNER_ASSETS_DIR/$CUSTOM_CASE_FILE_NAME" # for custom image + PARTNER_CASE_ICON=$(jq -r '.caseIcon // empty' "$ACTIVATION_JSON" 2>/dev/null || true); # for included with system icon + debug_echo "Partner case model icon: $PARTNER_CASE_MODEL" + if [[ -f "$PARTNER_CASE_MODEL" ]]; then + cp -f "$PARTNER_CASE_MODEL" "$WEBGUI_IMAGES_DIR/$CUSTOM_CASE_FILE_NAME" + if [[ $? -ne 0 ]]; then + echo "⚠️ Warning: Failed to replace the original case model icon with the custom icon." + else + echo -n "$CUSTOM_CASE_FILE_NAME" > $CASE_MODEL_CFG # set the custom icon in the config file + echo "case: $CUSTOM_CASE_FILE_NAME" >> "$ACTIVATION_SETUP_FLAG" # add what changed to the .done flag file + debug_echo "Custom case model set" + fi + elif [[ -n "$PARTNER_CASE_ICON" ]]; then + echo -n "$PARTNER_CASE_ICON" > $CASE_MODEL_CFG # set the parsed icon name in the config file + echo "case: $PARTNER_CASE_ICON" >> "$ACTIVATION_SETUP_FLAG" # add what changed to the .done flag file + debug_echo "Case model set to $PARTNER_CASE_ICON" + fi + else + echo "case: skipped, already custom" >> "$ACTIVATION_SETUP_FLAG" # add what changed to the .done flag file + debug_echo "Skipping case model setup, already set as custom icon" + fi + else + debug_echo "Skipping case model setup, flag already set" + fi + + # Set the server name, model, and description if we haven't already done it once + if ! grep -q "identity" "$ACTIVATION_SETUP_FLAG"; then + debug_echo "Checking server identification" + VAR_INI="/usr/local/emhttp/state/var.ini" + # If there's not a set system model or comment (aka description), we'll attempt to set it from activation json + CURRENT_NAME=$(awk -F "=" '/NAME/ {print $2}' $VAR_INI 2>/dev/null | tr -d '"') + CURRENT_SYS_MODEL=$(awk -F "=" '/SYS_MODEL/ {print $2}' $VAR_INI 2>/dev/null | tr -d '"') + CURRENT_COMMENT=$(awk -F "=" '/COMMENT/ {print $2}' $VAR_INI 2>/dev/null | tr -d '"') + + if [[ -z "$CURRENT_SYS_MODEL" || -z "$CURRENT_COMMENT" || "$CURRENT_COMMENT" == "Media server" || "$CURRENT_NAME" == "Tower" ]]; then + PARTNER_SERVER_NAME=$(jq -r '.serverName // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + PARTNER_SYS_MODEL=$(jq -r '.sysModel // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + PARTNER_COMMENT=$(jq -r '.comment // empty' "$ACTIVATION_JSON" 2>/dev/null || true) + # Sanitize strings to remove quotes and backslashes + PARTNER_SERVER_NAME=${PARTNER_SERVER_NAME//["\\"]/} + PARTNER_SYS_MODEL=${PARTNER_SYS_MODEL//["\\"]/} + PARTNER_COMMENT=${PARTNER_COMMENT//["\\"]/} + + debug_echo "Partner server name: $PARTNER_SERVER_NAME" + debug_echo "Partner system model: $PARTNER_SYS_MODEL" + debug_echo "Partner comment: $PARTNER_COMMENT" + + declare -A IDENT_PARAMS + if [[ -n "$PARTNER_SERVER_NAME" ]]; then + IDENT_PARAMS["NAME"]=$PARTNER_SERVER_NAME + fi + if [[ -n "$PARTNER_SYS_MODEL" ]]; then + IDENT_PARAMS["SYS_MODEL"]=$PARTNER_SYS_MODEL + fi + if [[ -n "$PARTNER_COMMENT" ]]; then + IDENT_PARAMS["COMMENT"]=$PARTNER_COMMENT + fi + + if [[ ${#IDENT_PARAMS[@]} -gt 0 ]]; then + echo "⏳ Please wait...updating system identification" + + # @todo - This may not be needed, double check if emhttp is updating the ident.cfg file + for key in "${!IDENT_PARAMS[@]}"; do + value=${IDENT_PARAMS[$key]} + CONFIG_FILE="/boot/config/ident.cfg" + debug_echo "Setting $key to $value in $CONFIG_FILE" + + # Use awk to update or append the key-value pair + awk -v key="$key" -v value="$value" ' + BEGIN { key_found = 0 } + { + if ($0 ~ "^" key "=") { + print key "=" "\"" value "\"" + key_found = 1 + } else { + print $0 + } + } + END { + if (!key_found) { + print key "=" "\"" value "\"" + } + }' "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE" + done + + EM_CMD=$(IFS="&"; for key in "${!IDENT_PARAMS[@]}"; do echo "$key=${IDENT_PARAMS[$key]}"; done | paste -sd '&') + + debug_echo "updating system identification for emhttp" + + emcmd "$EM_CMD&changeNames=Apply" + + debug_echo "System identification updated" + echo "✅ Identification updated: $EM_CMD" + + # Add what changed to the .done flag file + echo "identity: $EM_CMD" >> "$ACTIVATION_SETUP_FLAG" + fi + fi + else + debug_echo "Skipping server identification setup, flag already set" + fi + + debug_echo "Activation setup complete" + fi +else + debug_echo "Activation directory not found" +fi diff --git a/web/_data/serverState.ts b/web/_data/serverState.ts index 6c767be00..945532889 100644 --- a/web/_data/serverState.ts +++ b/web/_data/serverState.ts @@ -44,9 +44,9 @@ import type { // EBLACKLISTED2 // ENOCONN -const state: ServerState = "ENOKEYFILE2" as ServerState; -const currentFlashGuid = "4444-1111-FOUR-999900008888"; // this is the flash drive that's been booted from -const regGuid = "4444-1111-FOUR-999900008888"; // this guid is registered in key server +const state: ServerState = "ENOKEYFILE" as ServerState; +const currentFlashGuid = "1111-1111-YIJD-ZACK1234TEST"; // this is the flash drive that's been booted from +const regGuid = "1111-1111-YIJD-ZACK1234TEST"; // this guid is registered in key server const keyfileBase64 = ""; // const randomGuid = `1111-1111-${makeid(4)}-123412341234`; // this guid is registered in key server @@ -133,6 +133,19 @@ const osVersionBranch = "stable"; // }; export const serverState: Server = { + activationCodeData: { + "code": "CC2KP3TDRF", + "partnerName": "OEM Partner", + "partnerUrl": "https://unraid.net/OEM+Partner", + "sysModel": "OEM Partner v1", + "comment": "OEM Partner NAS", + "caseIcon": "case-model.png", + "header": "#ffffff", + "headermetacolor": "#eeeeee", + "background": "#000000", + "showBannerGradient": "yes", + "partnerLogo": true, + }, apiKey: "unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810", avatar: "https://source.unsplash.com/300x300/?portrait", config: { diff --git a/web/components/Activation/Modal.vue b/web/components/Activation/Modal.vue new file mode 100644 index 000000000..28a728814 --- /dev/null +++ b/web/components/Activation/Modal.vue @@ -0,0 +1,121 @@ + + + diff --git a/web/components/Activation/PartnerLogo.vue b/web/components/Activation/PartnerLogo.vue new file mode 100644 index 000000000..b811118d8 --- /dev/null +++ b/web/components/Activation/PartnerLogo.vue @@ -0,0 +1,17 @@ + + + diff --git a/web/components/Activation/PartnerLogoImg.vue b/web/components/Activation/PartnerLogoImg.vue new file mode 100644 index 000000000..dc35373ac --- /dev/null +++ b/web/components/Activation/PartnerLogoImg.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/web/components/ColorSwitcher.ce.vue b/web/components/ColorSwitcher.ce.vue index f8446c284..82c41f93a 100644 --- a/web/components/ColorSwitcher.ce.vue +++ b/web/components/ColorSwitcher.ce.vue @@ -2,17 +2,27 @@ import Input from '~/components/shadcn/input/Input.vue'; import Label from '~/components/shadcn/label/Label.vue'; import { defaultColors, useThemeStore, type Theme } from '~/store/theme'; -import { useToggle } from '@vueuse/core'; const themeStore = useThemeStore(); const { darkMode } = toRefs(themeStore); +const setDarkMode = ref(false); +const setGradient = ref(false); +const setDescription = ref(true); +const setBanner = ref(true); -const [setDarkMode, toggleDarkMode] = useToggle(false); -const [setGradient, toggleGradient] = useToggle(false); -const [setDescription, toggleDescription] = useToggle(true); -const [setBanner, toggleBanner] = useToggle(true); - +const toggleSwitch = (value: boolean) => { + setDarkMode.value = value; +}; +const toggleGradient = (value: boolean) => { + setGradient.value = value; +}; +const toggleDescription = (value: boolean) => { + setDescription.value = value; +}; +const toggleBanner = (value: boolean) => { + setBanner.value = value; +}; const textPrimary = ref(''); const textSecondary = ref(''); @@ -22,7 +32,7 @@ const textPrimaryToSet = computed(() => { if (textPrimary.value) { return textPrimary.value; } - return darkMode.value ? defaultColors.dark['--headerTextPrimary'] : defaultColors.light['--headerTextPrimary']; + return darkMode.value ? defaultColors.dark.headerTextPrimary : defaultColors.light.headerTextPrimary; }); const textSecondaryToSet = computed(() => { @@ -30,8 +40,8 @@ const textSecondaryToSet = computed(() => { return textSecondary.value; } return darkMode.value - ? defaultColors.dark['--header-text-secondary'] - : defaultColors.light['--header-text-secondary']; + ? defaultColors.dark.headerTextSecondary + : defaultColors.light.headerTextSecondary; }); const bgColorToSet = computed(() => { @@ -39,52 +49,42 @@ const bgColorToSet = computed(() => { return bgColor.value; } return darkMode.value - ? defaultColors.dark['--header-background'] - : defaultColors.light['--header-background']; + ? defaultColors.dark.headerBackgroundColor + : defaultColors.light.headerBackgroundColor; }); -watch( - [ - setDarkMode, - bgColorToSet, - textSecondaryToSet, - textPrimaryToSet, - setDescription, - setBanner, - setGradient, - ], - () => { - const themeToSet: Theme = { - banner: setBanner.value, - bannerGradient: setGradient.value, - descriptionShow: setDescription.value, - textColor: textPrimaryToSet.value, - metaColor: textSecondaryToSet.value, - bgColor: bgColorToSet.value, - name: setDarkMode.value ? 'black' : 'light', - }; - themeStore.setTheme(themeToSet); - } -); +watch([setDarkMode, bgColorToSet, textSecondaryToSet, textPrimaryToSet], (newVal) => { + console.log(newVal); + const themeToSet: Theme = { + banner: setBanner.value, + bannerGradient: setGradient.value, + descriptionShow: setDescription.value, + textColor: textPrimaryToSet.value, + metaColor: textSecondaryToSet.value, + bgColor: bgColorToSet.value, + name: setDarkMode.value ? 'black' : 'light', + }; + themeStore.setTheme(themeToSet); +}); diff --git a/web/components/Modal.vue b/web/components/Modal.vue index 03422df14..9851f8dba 100644 --- a/web/components/Modal.vue +++ b/web/components/Modal.vue @@ -2,6 +2,7 @@ import { TransitionChild, TransitionRoot } from '@headlessui/vue'; import { XMarkIcon } from '@heroicons/vue/24/outline'; import type { ComposerTranslation } from 'vue-i18n'; +import { cn } from '~/components/shadcn/utils'; export interface Props { centerContent?: boolean; @@ -14,6 +15,13 @@ export interface Props { t: ComposerTranslation; tallContent?: boolean; title?: string; + titleInMain?: boolean; + headerJustifyCenter?: boolean; + overlayColor?: string; + overlayOpacity?: string; + modalVerticalCenter?: boolean | string; + disableShadow?: boolean; + disableOverlayClose?: boolean; } const props = withDefaults(defineProps(), { centerContent: true, @@ -25,6 +33,13 @@ const props = withDefaults(defineProps(), { success: false, tallContent: false, title: '', + titleInMain: false, + headerJustifyCenter: true, + overlayColor: 'bg-black', + overlayOpacity: 'bg-opacity-80', + modalVerticalCenter: true, + disableShadow: false, + disableOverlayClose: false, }); watchEffect(() => { // toggle body scrollability @@ -40,8 +55,16 @@ const closeModal = () => { emit('close'); }; -const ariaLablledById = computed((): string|undefined => props.title ? `ModalTitle-${Math.random()}`.replace('0.', '') : undefined); - +const ariaLablledById = computed(() => props.title ? `ModalTitle-${Math.random()}`.replace('0.', '') : undefined); +const computedVerticalCenter = computed(() => { + if (props.tallContent) { + return 'items-start sm:items-center'; + } + if (typeof props.modalVerticalCenter === 'string') { + return props.modalVerticalCenter; + } + return props.modalVerticalCenter ? 'items-center' : 'items-start'; +});