From 6a94d84cfa91e4164a59c5257e55473d01389d03 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Fri, 21 Mar 2025 15:02:11 -0400 Subject: [PATCH 1/6] Cleanup Changelog Function Cleanup Changelog Function --- MerlinAU.asp | 123 ++++++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 55 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index 911b46ac..b88db3b0 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -796,64 +796,77 @@ const fwUpdateDirPath = } }; -function ShowLatestChangelog() -{ - document.form.action_script.value = 'start_MerlinAUdownloadchangelog'; - document.form.action_wait.value = 10; - - // Open popup **before** form submission to avoid browser popup blocking // - var changelogWindow = window.open("", "ChangelogPopup", "width=800,height=600,scrollbars=1,resizable=1"); +function fetchChangelog(startTime) { + $.ajax({ + url: '/ext/MerlinAU/changelog.htm', + dataType: 'text', + timeout: 1500, // each attempt times out after 9 seconds + success: function(data) { + $('#changelogData').html('
' + data + '
'); + }, + error: function() { + var currentTime = new Date().getTime(); + // if less than 10 seconds have elapsed since we started, retry after 500ms + if (currentTime - startTime < 10000) { + setTimeout(function() { + fetchChangelog(startTime); + }, 500); + } else { + $('#changelogData').html('

Failed to load the changelog.

'); + } + } + }); +} - if (!changelogWindow) - { - alert("Popup blocked! Please allow popups for this site to view the changelog."); - return; +function ShowLatestChangelog(e) { + if (e) e.preventDefault(); + + // If the modal already exists, clear its content to force a fresh fetch. + if ($('#changelogModal').length) { + $('#changelogData').html('

Loading latest changelog...

'); + } else { + // Create modal overlay if it doesn't exist + $('body').append( + '' + ); + $('#closeChangelogModal').on('click', function(){ + $('#changelogModal').hide(); + }); } - - changelogWindow.document.open(); - changelogWindow.document.write("Latest Changelog"); - changelogWindow.document.write(""); - changelogWindow.document.write("

Loading latest changelog...

"); - changelogWindow.document.write(""); - changelogWindow.document.close(); - - // Now submit the form (which might trigger a page refresh) // - showLoading(); - document.form.submit(); - - // Delay the AJAX request slightly (but make sure it runs before page refresh) // + + // Show the modal overlay + $('#changelogModal').show(); + + // Trigger the backend shell script via form submission (using AJAX) + var formData = $('form[name="form"]').serializeArray(); + formData.push({ name: "action_script", value: "start_MerlinAUdownloadchangelog" }); + formData.push({ name: "action_wait", value: "10" }); + + $.post('start_apply.htm', formData) + .done(function(response) { + console.log("Changelog trigger submitted successfully."); + }) + .fail(function() { + console.error("Failed to submit changelog trigger."); + }); + + // Record the start time and wait 8 seconds before attempting to fetch the changelog + var startTime = new Date().getTime(); setTimeout(function() { - $.ajax({ - url: '/ext/MerlinAU/changelog.htm', - dataType: 'text', - timeout: 9000, - success: function(data) - { - // Ensure the popup is still open before modifying it // - if (changelogWindow && !changelogWindow.closed) - { - changelogWindow.document.open(); - changelogWindow.document.write("Latest Changelog"); - changelogWindow.document.write(""); - changelogWindow.document.write("
" + data + "
"); - changelogWindow.document.write(""); - changelogWindow.document.close(); - } - }, - error: function() - { - if (changelogWindow && !changelogWindow.closed) - { - changelogWindow.document.open(); - changelogWindow.document.write("Changelog Error"); - changelogWindow.document.write(""); - changelogWindow.document.write("

Failed to load the changelog.

"); - changelogWindow.document.write(""); - changelogWindow.document.close(); - } - } - }); - }, 8000); // Delay slightly to allow form processing, but not too much // + fetchChangelog(startTime); + }, 8000); + + return false; } // **Control "Approve/Block Changelog" Checkbox State** // From 3a2a650c64bfeb898f1f5c2ba1829d11ab734845 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Fri, 21 Mar 2025 16:19:50 -0400 Subject: [PATCH 2/6] Update MerlinAU.asp --- MerlinAU.asp | 1297 +++++++++++++++++++++++++------------------------- 1 file changed, 649 insertions(+), 648 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index b88db3b0..09711f65 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -77,7 +77,7 @@ const validationErrorMsg = 'Validation failed. Please correct invalid value and /** Added by Martinski W. [2025-Feb-21] **/ /**-------------------------------------**/ /** Set to false for Production Release **/ -var doConsoleLogDEBUG = false; +var doConsoleLogDEBUG = true; function ConsoleLogDEBUG (debugMsg, debugVar) { if (!doConsoleLogDEBUG) { return ; } @@ -2012,221 +2012,170 @@ function initial() /**----------------------------------------**/ /** Modified by Martinski W. [2025-Mar-07] **/ /**----------------------------------------**/ -function SaveActionsConfig() -{ - // Clear amng_custom for any existing content before saving +function SaveCombinedConfig() { + // Clear the hidden field before saving document.getElementById('amng_custom').value = ''; - // Collect Action form-specific settings // + /*============================== + ACTIONS CONFIG SECTION + ==============================*/ var passwordElem = document.getElementById('routerPassword'); var usernameElem = document.getElementById('http_username'); var usernameStr = usernameElem ? usernameElem.value.trim() : 'admin'; - // Validate that Username is not empty // - if (usernameStr === null || usernameStr.length === 0) - { + // Validate that Username is not empty + if (usernameStr === null || usernameStr.length === 0) { console.error("HTTP Username is missing."); alert("HTTP Username is not set. Please contact your administrator."); return false; } - if (!ValidatePasswordString (passwordElem, 'onSAVE')) - { + if (!ValidatePasswordString(passwordElem, 'onSAVE')) { alert(`${validationErrorMsg}\n\n` + loginPassword.ErrorMsg()); return false; } - if (!ValidatePostponedDays (document.form.fwUpdatePostponement)) - { + if (!ValidatePostponedDays(document.form.fwUpdatePostponement)) { alert(`${validationErrorMsg}\n\n` + fwPostponedDays.ErrorMsg()); return false; } if (document.form.fwScheduleHOUR.disabled === false && - !ValidateFWUpdateTime (document.form.fwScheduleHOUR, 'HOUR')) - { + !ValidateFWUpdateTime(document.form.fwScheduleHOUR, 'HOUR')) { alert(`${validationErrorMsg}\n\n` + fwScheduleTime.ErrorMsg('HOUR')); return false; } if (document.form.fwScheduleMINS.disabled === false && - !ValidateFWUpdateTime (document.form.fwScheduleMINS, 'MINS')) - { + !ValidateFWUpdateTime(document.form.fwScheduleMINS, 'MINS')) { alert(`${validationErrorMsg}\n\n` + fwScheduleTime.ErrorMsg('MINS')); return false; } if (document.getElementById('fwSchedBoxDAYSX').checked && - !ValidateFWUpdateXDays (document.form.fwScheduleXDAYS, 'DAYS')) - { + !ValidateFWUpdateXDays(document.form.fwScheduleXDAYS, 'DAYS')) { alert(`${validationErrorMsg}\n\n` + fwScheduleTime.ErrorMsg('DAYS')); return false; } + + // Process FW update cron schedule conversion let fwUpdateRawCronSchedule = custom_settings.FW_New_Update_Cron_Job_Schedule; - fwUpdateRawCronSchedule = FWConvertWebUISettingsToCronSchedule (fwUpdateRawCronSchedule); + fwUpdateRawCronSchedule = FWConvertWebUISettingsToCronSchedule(fwUpdateRawCronSchedule); - // Encode credentials in Base64 // + // Encode credentials in Base64 var credentials = usernameStr + ':' + passwordElem.value; var encodedCredentials = btoa(credentials); - // Collect only Action form-specific settings // - var action_settings = - { + // Build the Actions settings object + var action_settings = { credentials_base64: encodedCredentials, FW_New_Update_Cron_Job_Schedule: fwUpdateRawCronSchedule, FW_New_Update_Postponement_Days: document.getElementById('fwUpdatePostponement')?.value || '0', CheckChangeLog: document.getElementById('changelogCheckEnabled').checked ? 'ENABLED' : 'DISABLED', FW_Update_Check: document.getElementById('FW_AutoUpdate_Check').checked ? 'ENABLED' : 'DISABLED' }; - // Prefix only Action settings // - var prefixedActionSettings = PrefixCustomSettings(action_settings, 'MerlinAU_'); - - // ***** FIX BUG WHERE MerlinAU_FW_Auto_Backupmon is saved from the wrong button ***** - // ***** Only when the Advanced Options section is saved first, and then Actions Section is saved second ***** - var ADVANCED_KEYS = [ - "MerlinAU_FW_Auto_Backupmon", - "MerlinAU_FW_Allow_Beta_Production_Up", - "MerlinAU_FW_New_Update_ZIP_Directory_Path", - "MerlinAU_FW_New_Update_LOG_Directory_Path", - "MerlinAU_FW_New_Update_EMail_Notification", - "MerlinAU_FW_New_Update_EMail_FormatType", - "MerlinAU_FW_New_Update_EMail_CC_Address", - "MerlinAU_Allow_Updates_OverVPN", - "MerlinAU_Allow_Script_Auto_Update", - "MerlinAU_ROGBuild", - "MerlinAU_TUFBuild" - ]; - ADVANCED_KEYS.forEach(function (key){ - if (shared_custom_settings.hasOwnProperty(key)) - { delete shared_custom_settings[key]; } - }); - - // Merge Server Custom Settings and prefixed Action form settings // - var updatedSettings = Object.assign({}, shared_custom_settings, prefixedActionSettings); - ConsoleLogDEBUG("Actions Config Form submitted with settings:", updatedSettings); - - // Save merged settings to the hidden input field // - document.getElementById('amng_custom').value = JSON.stringify(updatedSettings); - - let actionScriptValue; - if (!document.getElementById('RunLoginTestOnSave').checked) - { actionScriptValue = 'start_MerlinAUconfig'; } - else - { actionScriptValue = 'start_MerlinAUconfig_runLoginTest'; } - - // Apply the settings // - document.form.action_script.value = actionScriptValue; - document.form.action_wait.value = 10; - showLoading(); - document.form.submit(); - isFormSubmitting = true; -} -/**----------------------------------------**/ -/** Modified by Martinski W. [2025-Feb-23] **/ -/**----------------------------------------**/ -function SaveAdvancedConfig() -{ - // Clear amng_custom for any existing content before saving // - document.getElementById('amng_custom').value = ''; + // Prefix the Actions settings + var prefixedActionSettings = PrefixCustomSettings(action_settings, 'MerlinAU_'); - // F/W Update Email Notifications - only if NOT disabled // + /*============================== + ADVANCED CONFIG SECTION + ==============================*/ + // Process Email Notification settings (only if enabled) let emailFormat = document.getElementById('emailFormat'); let secondaryEmail = document.getElementById('secondaryEmail'); let emailNotificationsEnabled = document.getElementById('emailNotificationsEnabled'); - // If the box is enabled, we save these fields // - if (emailNotificationsEnabled && !emailNotificationsEnabled.disabled) - { advanced_settings.FW_New_Update_EMail_Notification = emailNotificationsEnabled.checked ? 'ENABLED' : 'DISABLED'; } - - if (emailFormat && !emailFormat.disabled) - { advanced_settings.FW_New_Update_EMail_FormatType = emailFormat.value || 'HTML'; } - - if (secondaryEmail && !secondaryEmail.disabled) - { advanced_settings.FW_New_Update_EMail_CC_Address = secondaryEmail.value || 'TBD'; } + if (emailNotificationsEnabled && !emailNotificationsEnabled.disabled) { + advanced_settings.FW_New_Update_EMail_Notification = emailNotificationsEnabled.checked ? 'ENABLED' : 'DISABLED'; + } + if (emailFormat && !emailFormat.disabled) { + advanced_settings.FW_New_Update_EMail_FormatType = emailFormat.value || 'HTML'; + } + if (secondaryEmail && !secondaryEmail.disabled) { + advanced_settings.FW_New_Update_EMail_CC_Address = secondaryEmail.value || 'TBD'; + } - // F/W Update ZIP Directory (more checks are made in the shell script) // + // Process F/W Update ZIP Directory let fwUpdateZIPdirectory = document.getElementById('fwUpdateZIPDirectory'); - if (fwUpdateZIPdirectory !== null && typeof fwUpdateZIPdirectory !== 'undefined') - { - if (ValidateDirectoryPath (fwUpdateZIPdirectory, 'ZIP')) - { advanced_settings.FW_New_Update_ZIP_Directory_Path = fwUpdateZIPdirectory.value; } - else - { + if (fwUpdateZIPdirectory !== null && typeof fwUpdateZIPdirectory !== 'undefined') { + if (ValidateDirectoryPath(fwUpdateZIPdirectory, 'ZIP')) { + advanced_settings.FW_New_Update_ZIP_Directory_Path = fwUpdateZIPdirectory.value; + } else { alert(`${validationErrorMsg}\n\n` + fwUpdateDirPath.ErrorMsg('ZIP')); return false; } } - // F/W Update LOG Directory (more checks are made in the shell script) // + // Process F/W Update LOG Directory let fwUpdateLOGdirectory = document.getElementById('fwUpdateLOGDirectory'); - if (fwUpdateLOGdirectory !== null && typeof fwUpdateLOGdirectory !== 'undefined') - { - if (ValidateDirectoryPath (fwUpdateLOGdirectory, 'LOG')) - { advanced_settings.FW_New_Update_LOG_Directory_Path = fwUpdateLOGdirectory.value; } - else - { + if (fwUpdateLOGdirectory !== null && typeof fwUpdateLOGdirectory !== 'undefined') { + if (ValidateDirectoryPath(fwUpdateLOGdirectory, 'LOG')) { + advanced_settings.FW_New_Update_LOG_Directory_Path = fwUpdateLOGdirectory.value; + } else { alert(`${validationErrorMsg}\n\n` + fwUpdateDirPath.ErrorMsg('LOG')); return false; } } - // Tailscale/ZeroTier VPN Access - only if not disabled // + // Process Tailscale/ZeroTier VPN Access let tailscaleVPNEnabled = document.getElementById('tailscaleVPNEnabled'); - if (tailscaleVPNEnabled && !tailscaleVPNEnabled.disabled) - { advanced_settings.Allow_Updates_OverVPN = tailscaleVPNEnabled.checked ? 'ENABLED' : 'DISABLED'; } + if (tailscaleVPNEnabled && !tailscaleVPNEnabled.disabled) { + advanced_settings.Allow_Updates_OverVPN = tailscaleVPNEnabled.checked ? 'ENABLED' : 'DISABLED'; + } - // Automatic Updates for Script - only if not disabled // + // Process Automatic Script Updates let script_AutoUpdate_Check = document.getElementById('Script_AutoUpdate_Check'); - if (script_AutoUpdate_Check && !script_AutoUpdate_Check.disabled) - { advanced_settings.Allow_Script_Auto_Update = script_AutoUpdate_Check.checked ? 'ENABLED' : 'DISABLED'; } + if (script_AutoUpdate_Check && !script_AutoUpdate_Check.disabled) { + advanced_settings.Allow_Script_Auto_Update = script_AutoUpdate_Check.checked ? 'ENABLED' : 'DISABLED'; + } - // Beta-to-Release Updates - only if not disabled // + // Process Beta-to-Release Updates let betaToReleaseUpdatesEnabled = document.getElementById('betaToReleaseUpdatesEnabled'); - if (betaToReleaseUpdatesEnabled && !betaToReleaseUpdatesEnabled.disabled) - { advanced_settings.FW_Allow_Beta_Production_Up = betaToReleaseUpdatesEnabled.checked ? 'ENABLED' : 'DISABLED'; } + if (betaToReleaseUpdatesEnabled && !betaToReleaseUpdatesEnabled.disabled) { + advanced_settings.FW_Allow_Beta_Production_Up = betaToReleaseUpdatesEnabled.checked ? 'ENABLED' : 'DISABLED'; + } - // Automatic Backups - only if not disabled // + // Process Automatic Backups let autobackupEnabled = document.getElementById('autobackupEnabled'); - if (autobackupEnabled && !autobackupEnabled.disabled) - { advanced_settings.FW_Auto_Backupmon = autobackupEnabled.checked ? 'ENABLED' : 'DISABLED'; } + if (autobackupEnabled && !autobackupEnabled.disabled) { + advanced_settings.FW_Auto_Backupmon = autobackupEnabled.checked ? 'ENABLED' : 'DISABLED'; + } - // ROG/TUF F/W Build Type - handle conditional rows if visible // + // Process ROG/TUF F/W Build Types (if the rows are visible) let rogFWBuildRow = document.getElementById('rogFWBuildRow'); let rogFWBuildType = document.getElementById('rogFWBuildType'); - if (rogFWBuildRow && rogFWBuildRow.style.display !== 'none' && rogFWBuildType) - { advanced_settings.ROGBuild = (rogFWBuildType.value === 'ROG') ? 'ENABLED' : 'DISABLED'; } - + if (rogFWBuildRow && rogFWBuildRow.style.display !== 'none' && rogFWBuildType) { + advanced_settings.ROGBuild = (rogFWBuildType.value === 'ROG') ? 'ENABLED' : 'DISABLED'; + } let tufFWBuildRow = document.getElementById('tuffFWBuildRow'); let tuffFWBuildType = document.getElementById('tuffFWBuildType'); - if (tufFWBuildRow && tufFWBuildRow.style.display !== 'none' && tuffFWBuildType) - { advanced_settings.TUFBuild = (tuffFWBuildType.value === 'TUF') ? 'ENABLED' : 'DISABLED'; } + if (tufFWBuildRow && tufFWBuildRow.style.display !== 'none' && tuffFWBuildType) { + advanced_settings.TUFBuild = (tuffFWBuildType.value === 'TUF') ? 'ENABLED' : 'DISABLED'; + } - // Prefix only Advanced settings // + // Prefix the Advanced settings var prefixedAdvancedSettings = PrefixCustomSettings(advanced_settings, 'MerlinAU_'); - // Remove any action keys from shared_custom_settings to avoid overwriting // - var ACTION_KEYS = [ - "MerlinAU_credentials_base64", - "MerlinAU_FW_New_Update_Postponement_Days", - "MerlinAU_CheckChangeLog", - "MerlinAU_FW_Update_Check", - "FW_New_Update_Cron_Job_Schedule" - ]; - ACTION_KEYS.forEach(function (key){ - if (shared_custom_settings.hasOwnProperty(key)) - { delete shared_custom_settings[key]; } - }); - - // Merge Server Custom Settings and prefixed Advanced settings - var updatedSettings = Object.assign({}, shared_custom_settings, prefixedAdvancedSettings); - ConsoleLogDEBUG("Advanced Config Form submitted with settings:", updatedSettings); + /*============================== + MERGE SETTINGS & SUBMIT FORM + ==============================*/ + // Merge shared settings with both prefixed Action and Advanced settings + var updatedSettings = Object.assign({}, shared_custom_settings, prefixedActionSettings, prefixedAdvancedSettings); + ConsoleLogDEBUG("Combined Config Form submitted with settings:", updatedSettings); - // Save merged settings to the hidden input field // + // Save merged settings to the hidden input field document.getElementById('amng_custom').value = JSON.stringify(updatedSettings); - // Apply the settings // - document.form.action_script.value = 'start_MerlinAUconfig'; + // Determine action script based on the RunLoginTestOnSave checkbox + let actionScriptValue; + if (!document.getElementById('RunLoginTestOnSave').checked) { + actionScriptValue = 'start_MerlinAUconfig'; + } else { + actionScriptValue = 'start_MerlinAUconfig_runLoginTest'; + } + document.form.action_script.value = actionScriptValue; document.form.action_wait.value = 10; + showLoading(); document.form.submit(); isFormSubmitting = true; - setTimeout(GetExternalCheckResults,4000); + setTimeout(GetExternalCheckResults, 4000); } /**----------------------------------------**/ @@ -2450,517 +2399,569 @@ function initializeCollapsibleSections() -
- - - -
- - - - - - - -" /> -" /> - -" /> - -" /> -" /> -" /> -" /> -" /> -" /> - - - - - - - - -
  - - - - - - - -
- - - -
-
 
-
MerlinAU
-
-
This is the MerlinAU add-on integrated into the router WebUI -[ - Wiki ] - -
-
 
- - - - - - - - -
- - - - - - - - - - - -
Firmware Status (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: - <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> -
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
Changelog Approval:Disabled
- - - - - - - - - - - -
Settings Status (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
F/W Update Check:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
- -
 
- - - - - - - - - -
Actions (click to expand/collapse)
-
- -- - - - - - - - - -
- -
- -
-
- -
- -
-
- -
- -
-
-
- - -- - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-
- -
-
-
- -
-
- - -
- - - -
- - - -
- - -
- Days: - - - - -
- - - - - - - -
-
-
- Hour: - -
-
- Minutes: - -
-
-
- -
- -
- -
 
- - - - - - - - -
Advanced Options (click to expand/collapse)
-
- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - -
- -
- -
- -
- - - - -
- - - - -
- - - - -
- -
- -
-
- -
-
-
MerlinAU
-
- +
+ + + +
+ + + + + + + + " /> + " /> + + " /> + + " /> + " /> + " /> + " /> + " /> + " /> + + + + + + + + + +
  + + + + + + + + + +
+ + + + + + +
+
 
+
MerlinAU
+
+
+ This is the MerlinAU add-on integrated into the router WebUI + + [Wiki] + +
+
 
+ + + + + + + + + + +
+ + + + + + + + + + + + + + +
Firmware Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: + <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> +
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
Changelog Approval:Disabled
+
+
+ + + + + + + + + + + + + + +
Settings Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Update Check:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
+
+
+ +
 
+ + +
 
+ + + + + + + + + + + +
Actions (click to expand/collapse)
+
+ + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
 
+ + + + + + + + + + + + + +
Configuration (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+ +
+
+ + + + +
+ + + +
+ + + +
+ + +
+ Days: + + + + +
+ + + + + + + +
+
+
+ Hour: + +
+
+ Minutes: + +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ + + +
+ + + +
+
+ +
+ +
+
MerlinAU
+
+
+
+ + From c31fe52f94378aa4117d548c2052d9a046566147 Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Fri, 21 Mar 2025 16:21:12 -0400 Subject: [PATCH 3/6] Revert "Update MerlinAU.asp" This reverts commit 3a2a650c64bfeb898f1f5c2ba1829d11ab734845. --- MerlinAU.asp | 1297 +++++++++++++++++++++++++------------------------- 1 file changed, 648 insertions(+), 649 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index 09711f65..b88db3b0 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -77,7 +77,7 @@ const validationErrorMsg = 'Validation failed. Please correct invalid value and /** Added by Martinski W. [2025-Feb-21] **/ /**-------------------------------------**/ /** Set to false for Production Release **/ -var doConsoleLogDEBUG = true; +var doConsoleLogDEBUG = false; function ConsoleLogDEBUG (debugMsg, debugVar) { if (!doConsoleLogDEBUG) { return ; } @@ -2012,170 +2012,221 @@ function initial() /**----------------------------------------**/ /** Modified by Martinski W. [2025-Mar-07] **/ /**----------------------------------------**/ -function SaveCombinedConfig() { - // Clear the hidden field before saving +function SaveActionsConfig() +{ + // Clear amng_custom for any existing content before saving document.getElementById('amng_custom').value = ''; - /*============================== - ACTIONS CONFIG SECTION - ==============================*/ + // Collect Action form-specific settings // var passwordElem = document.getElementById('routerPassword'); var usernameElem = document.getElementById('http_username'); var usernameStr = usernameElem ? usernameElem.value.trim() : 'admin'; - // Validate that Username is not empty - if (usernameStr === null || usernameStr.length === 0) { + // Validate that Username is not empty // + if (usernameStr === null || usernameStr.length === 0) + { console.error("HTTP Username is missing."); alert("HTTP Username is not set. Please contact your administrator."); return false; } - if (!ValidatePasswordString(passwordElem, 'onSAVE')) { + if (!ValidatePasswordString (passwordElem, 'onSAVE')) + { alert(`${validationErrorMsg}\n\n` + loginPassword.ErrorMsg()); return false; } - if (!ValidatePostponedDays(document.form.fwUpdatePostponement)) { + if (!ValidatePostponedDays (document.form.fwUpdatePostponement)) + { alert(`${validationErrorMsg}\n\n` + fwPostponedDays.ErrorMsg()); return false; } if (document.form.fwScheduleHOUR.disabled === false && - !ValidateFWUpdateTime(document.form.fwScheduleHOUR, 'HOUR')) { + !ValidateFWUpdateTime (document.form.fwScheduleHOUR, 'HOUR')) + { alert(`${validationErrorMsg}\n\n` + fwScheduleTime.ErrorMsg('HOUR')); return false; } if (document.form.fwScheduleMINS.disabled === false && - !ValidateFWUpdateTime(document.form.fwScheduleMINS, 'MINS')) { + !ValidateFWUpdateTime (document.form.fwScheduleMINS, 'MINS')) + { alert(`${validationErrorMsg}\n\n` + fwScheduleTime.ErrorMsg('MINS')); return false; } if (document.getElementById('fwSchedBoxDAYSX').checked && - !ValidateFWUpdateXDays(document.form.fwScheduleXDAYS, 'DAYS')) { + !ValidateFWUpdateXDays (document.form.fwScheduleXDAYS, 'DAYS')) + { alert(`${validationErrorMsg}\n\n` + fwScheduleTime.ErrorMsg('DAYS')); return false; } - - // Process FW update cron schedule conversion let fwUpdateRawCronSchedule = custom_settings.FW_New_Update_Cron_Job_Schedule; - fwUpdateRawCronSchedule = FWConvertWebUISettingsToCronSchedule(fwUpdateRawCronSchedule); + fwUpdateRawCronSchedule = FWConvertWebUISettingsToCronSchedule (fwUpdateRawCronSchedule); - // Encode credentials in Base64 + // Encode credentials in Base64 // var credentials = usernameStr + ':' + passwordElem.value; var encodedCredentials = btoa(credentials); - // Build the Actions settings object - var action_settings = { + // Collect only Action form-specific settings // + var action_settings = + { credentials_base64: encodedCredentials, FW_New_Update_Cron_Job_Schedule: fwUpdateRawCronSchedule, FW_New_Update_Postponement_Days: document.getElementById('fwUpdatePostponement')?.value || '0', CheckChangeLog: document.getElementById('changelogCheckEnabled').checked ? 'ENABLED' : 'DISABLED', FW_Update_Check: document.getElementById('FW_AutoUpdate_Check').checked ? 'ENABLED' : 'DISABLED' }; - - // Prefix the Actions settings + // Prefix only Action settings // var prefixedActionSettings = PrefixCustomSettings(action_settings, 'MerlinAU_'); - /*============================== - ADVANCED CONFIG SECTION - ==============================*/ - // Process Email Notification settings (only if enabled) + // ***** FIX BUG WHERE MerlinAU_FW_Auto_Backupmon is saved from the wrong button ***** + // ***** Only when the Advanced Options section is saved first, and then Actions Section is saved second ***** + var ADVANCED_KEYS = [ + "MerlinAU_FW_Auto_Backupmon", + "MerlinAU_FW_Allow_Beta_Production_Up", + "MerlinAU_FW_New_Update_ZIP_Directory_Path", + "MerlinAU_FW_New_Update_LOG_Directory_Path", + "MerlinAU_FW_New_Update_EMail_Notification", + "MerlinAU_FW_New_Update_EMail_FormatType", + "MerlinAU_FW_New_Update_EMail_CC_Address", + "MerlinAU_Allow_Updates_OverVPN", + "MerlinAU_Allow_Script_Auto_Update", + "MerlinAU_ROGBuild", + "MerlinAU_TUFBuild" + ]; + ADVANCED_KEYS.forEach(function (key){ + if (shared_custom_settings.hasOwnProperty(key)) + { delete shared_custom_settings[key]; } + }); + + // Merge Server Custom Settings and prefixed Action form settings // + var updatedSettings = Object.assign({}, shared_custom_settings, prefixedActionSettings); + ConsoleLogDEBUG("Actions Config Form submitted with settings:", updatedSettings); + + // Save merged settings to the hidden input field // + document.getElementById('amng_custom').value = JSON.stringify(updatedSettings); + + let actionScriptValue; + if (!document.getElementById('RunLoginTestOnSave').checked) + { actionScriptValue = 'start_MerlinAUconfig'; } + else + { actionScriptValue = 'start_MerlinAUconfig_runLoginTest'; } + + // Apply the settings // + document.form.action_script.value = actionScriptValue; + document.form.action_wait.value = 10; + showLoading(); + document.form.submit(); + isFormSubmitting = true; +} + +/**----------------------------------------**/ +/** Modified by Martinski W. [2025-Feb-23] **/ +/**----------------------------------------**/ +function SaveAdvancedConfig() +{ + // Clear amng_custom for any existing content before saving // + document.getElementById('amng_custom').value = ''; + + // F/W Update Email Notifications - only if NOT disabled // let emailFormat = document.getElementById('emailFormat'); let secondaryEmail = document.getElementById('secondaryEmail'); let emailNotificationsEnabled = document.getElementById('emailNotificationsEnabled'); - if (emailNotificationsEnabled && !emailNotificationsEnabled.disabled) { - advanced_settings.FW_New_Update_EMail_Notification = emailNotificationsEnabled.checked ? 'ENABLED' : 'DISABLED'; - } - if (emailFormat && !emailFormat.disabled) { - advanced_settings.FW_New_Update_EMail_FormatType = emailFormat.value || 'HTML'; - } - if (secondaryEmail && !secondaryEmail.disabled) { - advanced_settings.FW_New_Update_EMail_CC_Address = secondaryEmail.value || 'TBD'; - } + // If the box is enabled, we save these fields // + if (emailNotificationsEnabled && !emailNotificationsEnabled.disabled) + { advanced_settings.FW_New_Update_EMail_Notification = emailNotificationsEnabled.checked ? 'ENABLED' : 'DISABLED'; } + + if (emailFormat && !emailFormat.disabled) + { advanced_settings.FW_New_Update_EMail_FormatType = emailFormat.value || 'HTML'; } - // Process F/W Update ZIP Directory + if (secondaryEmail && !secondaryEmail.disabled) + { advanced_settings.FW_New_Update_EMail_CC_Address = secondaryEmail.value || 'TBD'; } + + // F/W Update ZIP Directory (more checks are made in the shell script) // let fwUpdateZIPdirectory = document.getElementById('fwUpdateZIPDirectory'); - if (fwUpdateZIPdirectory !== null && typeof fwUpdateZIPdirectory !== 'undefined') { - if (ValidateDirectoryPath(fwUpdateZIPdirectory, 'ZIP')) { - advanced_settings.FW_New_Update_ZIP_Directory_Path = fwUpdateZIPdirectory.value; - } else { + if (fwUpdateZIPdirectory !== null && typeof fwUpdateZIPdirectory !== 'undefined') + { + if (ValidateDirectoryPath (fwUpdateZIPdirectory, 'ZIP')) + { advanced_settings.FW_New_Update_ZIP_Directory_Path = fwUpdateZIPdirectory.value; } + else + { alert(`${validationErrorMsg}\n\n` + fwUpdateDirPath.ErrorMsg('ZIP')); return false; } } - // Process F/W Update LOG Directory + // F/W Update LOG Directory (more checks are made in the shell script) // let fwUpdateLOGdirectory = document.getElementById('fwUpdateLOGDirectory'); - if (fwUpdateLOGdirectory !== null && typeof fwUpdateLOGdirectory !== 'undefined') { - if (ValidateDirectoryPath(fwUpdateLOGdirectory, 'LOG')) { - advanced_settings.FW_New_Update_LOG_Directory_Path = fwUpdateLOGdirectory.value; - } else { + if (fwUpdateLOGdirectory !== null && typeof fwUpdateLOGdirectory !== 'undefined') + { + if (ValidateDirectoryPath (fwUpdateLOGdirectory, 'LOG')) + { advanced_settings.FW_New_Update_LOG_Directory_Path = fwUpdateLOGdirectory.value; } + else + { alert(`${validationErrorMsg}\n\n` + fwUpdateDirPath.ErrorMsg('LOG')); return false; } } - // Process Tailscale/ZeroTier VPN Access + // Tailscale/ZeroTier VPN Access - only if not disabled // let tailscaleVPNEnabled = document.getElementById('tailscaleVPNEnabled'); - if (tailscaleVPNEnabled && !tailscaleVPNEnabled.disabled) { - advanced_settings.Allow_Updates_OverVPN = tailscaleVPNEnabled.checked ? 'ENABLED' : 'DISABLED'; - } + if (tailscaleVPNEnabled && !tailscaleVPNEnabled.disabled) + { advanced_settings.Allow_Updates_OverVPN = tailscaleVPNEnabled.checked ? 'ENABLED' : 'DISABLED'; } - // Process Automatic Script Updates + // Automatic Updates for Script - only if not disabled // let script_AutoUpdate_Check = document.getElementById('Script_AutoUpdate_Check'); - if (script_AutoUpdate_Check && !script_AutoUpdate_Check.disabled) { - advanced_settings.Allow_Script_Auto_Update = script_AutoUpdate_Check.checked ? 'ENABLED' : 'DISABLED'; - } + if (script_AutoUpdate_Check && !script_AutoUpdate_Check.disabled) + { advanced_settings.Allow_Script_Auto_Update = script_AutoUpdate_Check.checked ? 'ENABLED' : 'DISABLED'; } - // Process Beta-to-Release Updates + // Beta-to-Release Updates - only if not disabled // let betaToReleaseUpdatesEnabled = document.getElementById('betaToReleaseUpdatesEnabled'); - if (betaToReleaseUpdatesEnabled && !betaToReleaseUpdatesEnabled.disabled) { - advanced_settings.FW_Allow_Beta_Production_Up = betaToReleaseUpdatesEnabled.checked ? 'ENABLED' : 'DISABLED'; - } + if (betaToReleaseUpdatesEnabled && !betaToReleaseUpdatesEnabled.disabled) + { advanced_settings.FW_Allow_Beta_Production_Up = betaToReleaseUpdatesEnabled.checked ? 'ENABLED' : 'DISABLED'; } - // Process Automatic Backups + // Automatic Backups - only if not disabled // let autobackupEnabled = document.getElementById('autobackupEnabled'); - if (autobackupEnabled && !autobackupEnabled.disabled) { - advanced_settings.FW_Auto_Backupmon = autobackupEnabled.checked ? 'ENABLED' : 'DISABLED'; - } + if (autobackupEnabled && !autobackupEnabled.disabled) + { advanced_settings.FW_Auto_Backupmon = autobackupEnabled.checked ? 'ENABLED' : 'DISABLED'; } - // Process ROG/TUF F/W Build Types (if the rows are visible) + // ROG/TUF F/W Build Type - handle conditional rows if visible // let rogFWBuildRow = document.getElementById('rogFWBuildRow'); let rogFWBuildType = document.getElementById('rogFWBuildType'); - if (rogFWBuildRow && rogFWBuildRow.style.display !== 'none' && rogFWBuildType) { - advanced_settings.ROGBuild = (rogFWBuildType.value === 'ROG') ? 'ENABLED' : 'DISABLED'; - } + if (rogFWBuildRow && rogFWBuildRow.style.display !== 'none' && rogFWBuildType) + { advanced_settings.ROGBuild = (rogFWBuildType.value === 'ROG') ? 'ENABLED' : 'DISABLED'; } + let tufFWBuildRow = document.getElementById('tuffFWBuildRow'); let tuffFWBuildType = document.getElementById('tuffFWBuildType'); - if (tufFWBuildRow && tufFWBuildRow.style.display !== 'none' && tuffFWBuildType) { - advanced_settings.TUFBuild = (tuffFWBuildType.value === 'TUF') ? 'ENABLED' : 'DISABLED'; - } + if (tufFWBuildRow && tufFWBuildRow.style.display !== 'none' && tuffFWBuildType) + { advanced_settings.TUFBuild = (tuffFWBuildType.value === 'TUF') ? 'ENABLED' : 'DISABLED'; } - // Prefix the Advanced settings + // Prefix only Advanced settings // var prefixedAdvancedSettings = PrefixCustomSettings(advanced_settings, 'MerlinAU_'); - /*============================== - MERGE SETTINGS & SUBMIT FORM - ==============================*/ - // Merge shared settings with both prefixed Action and Advanced settings - var updatedSettings = Object.assign({}, shared_custom_settings, prefixedActionSettings, prefixedAdvancedSettings); - ConsoleLogDEBUG("Combined Config Form submitted with settings:", updatedSettings); + // Remove any action keys from shared_custom_settings to avoid overwriting // + var ACTION_KEYS = [ + "MerlinAU_credentials_base64", + "MerlinAU_FW_New_Update_Postponement_Days", + "MerlinAU_CheckChangeLog", + "MerlinAU_FW_Update_Check", + "FW_New_Update_Cron_Job_Schedule" + ]; + ACTION_KEYS.forEach(function (key){ + if (shared_custom_settings.hasOwnProperty(key)) + { delete shared_custom_settings[key]; } + }); + + // Merge Server Custom Settings and prefixed Advanced settings + var updatedSettings = Object.assign({}, shared_custom_settings, prefixedAdvancedSettings); + ConsoleLogDEBUG("Advanced Config Form submitted with settings:", updatedSettings); - // Save merged settings to the hidden input field + // Save merged settings to the hidden input field // document.getElementById('amng_custom').value = JSON.stringify(updatedSettings); - // Determine action script based on the RunLoginTestOnSave checkbox - let actionScriptValue; - if (!document.getElementById('RunLoginTestOnSave').checked) { - actionScriptValue = 'start_MerlinAUconfig'; - } else { - actionScriptValue = 'start_MerlinAUconfig_runLoginTest'; - } - document.form.action_script.value = actionScriptValue; + // Apply the settings // + document.form.action_script.value = 'start_MerlinAUconfig'; document.form.action_wait.value = 10; - showLoading(); document.form.submit(); isFormSubmitting = true; - setTimeout(GetExternalCheckResults, 4000); + setTimeout(GetExternalCheckResults,4000); } /**----------------------------------------**/ @@ -2399,569 +2450,517 @@ function initializeCollapsibleSections() -
- - - -
- - - - - - - - " /> - " /> - - " /> - - " /> - " /> - " /> - " /> - " /> - " /> - - - - - - - - - -
  - - - - - - - - - -
- - - - - - -
-
 
-
MerlinAU
-
-
- This is the MerlinAU add-on integrated into the router WebUI - - [Wiki] - -
-
 
- - - - - - - - - - -
- - - - - - - - - - - - - - -
Firmware Status (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: - <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> -
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
Changelog Approval:Disabled
-
-
- - - - - - - - - - - - - - -
Settings Status (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
F/W Update Check:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
-
-
- -
 
- - -
 
- - - - - - - - - - - -
Actions (click to expand/collapse)
-
- - - - - - - - - - - -
- -
- -
-
- -
- -
-
- -
- -
-
-
-
- -
 
- - - - - - - - - - - - - -
Configuration (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-
- -
-
-
-
- -
-
- - - - -
- - - -
- - - -
- - -
- Days: - - - - -
- - - - - - - -
-
-
- Hour: - -
-
- Minutes: - -
-
- - - -
- - - -
- - - -
- - - -
- - - -
- - - - -
- - - - -
- - - - -
- - - -
- - - -
- - - -
-
- -
- -
-
MerlinAU
-
-
-
- - +
+ + + +
+ + + + + + + +" /> +" /> + +" /> + +" /> +" /> +" /> +" /> +" /> +" /> + + + + + + + + +
  + + + + + + + +
+ + + +
+
 
+
MerlinAU
+
+
This is the MerlinAU add-on integrated into the router WebUI +[ + Wiki ] + +
+
 
+ + + + + + + + +
+ + + + + + + + + + + +
Firmware Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: + <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> +
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
Changelog Approval:Disabled
+ + + + + + + + + + + +
Settings Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Update Check:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
+ +
 
+ + + + + + + + + +
Actions (click to expand/collapse)
+
+ ++ + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ + ++ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+ +
+
+ + +
+ + + +
+ + + +
+ + +
+ Days: + + + + +
+ + + + + + + +
+
+
+ Hour: + +
+
+ Minutes: + +
+
+
+ +
+ +
+ +
 
+ + + + + + + + +
Advanced Options (click to expand/collapse)
+
+ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+ +
+ +
+ + + + +
+ + + + +
+ + + + +
+ +
+ +
+
+ +
+
+
MerlinAU
+
+ From f887cdc5aa310a54bc1d98bda6fa25a7afaafa03 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Fri, 21 Mar 2025 16:29:26 -0400 Subject: [PATCH 4/6] Update MerlinAU.asp --- MerlinAU.asp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index b88db3b0..0ca7011f 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -823,7 +823,7 @@ function ShowLatestChangelog(e) { // If the modal already exists, clear its content to force a fresh fetch. if ($('#changelogModal').length) { - $('#changelogData').html('

Loading latest changelog...

'); + $('#changelogData').html('

Please wait...

'); } else { // Create modal overlay if it doesn't exist $('body').append( @@ -834,7 +834,7 @@ function ShowLatestChangelog(e) { '

Latest Changelog

' + '' + '
' + - '

Loading latest changelog...

' + + '

Please wait and allow up to 10 seconds for changelog to load...

' + '
' + '' + '' From 1ec7a5b1eb2ced8fa533553f624cacd008d2df87 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Fri, 21 Mar 2025 16:55:39 -0400 Subject: [PATCH 5/6] Update MerlinAU.asp --- MerlinAU.asp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index 0ca7011f..cae34c2b 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -2496,7 +2496,7 @@ function initializeCollapsibleSections()
MerlinAU
This is the MerlinAU add-on integrated into the router WebUI -[ +[ Wiki ] From a0f728350b15e2ee6c0eeb875c874ba26812ace3 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Sat, 22 Mar 2025 01:48:09 -0400 Subject: [PATCH 6/6] Update MerlinAU.asp --- MerlinAU.asp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index cae34c2b..893c27b2 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -821,9 +821,14 @@ function fetchChangelog(startTime) { function ShowLatestChangelog(e) { if (e) e.preventDefault(); - // If the modal already exists, clear its content to force a fresh fetch. + // Define the loading message + var loadingMessage = '

Please wait and allow up to 10 seconds for the changelog to load.
' + + 'Click on "Cancel" button to stop and exit this dialog.

'; + + // If the modal already exists, update its content for a fresh fetch. if ($('#changelogModal').length) { - $('#changelogData').html('

Please wait...

'); + $('#changelogData').html(loadingMessage); + $('#closeChangelogModal').text("Cancel"); } else { // Create modal overlay if it doesn't exist $('body').append( @@ -832,9 +837,9 @@ function ShowLatestChangelog(e) { '
' + '

Latest Changelog

' + - '' + + '' + '
' + - '

Please wait and allow up to 10 seconds for changelog to load...

' + + loadingMessage + '
' + '
' + '
' @@ -864,6 +869,8 @@ function ShowLatestChangelog(e) { var startTime = new Date().getTime(); setTimeout(function() { fetchChangelog(startTime); + // Once the changelog has loaded, update the button text to "Close" + $('#closeChangelogModal').text("Close"); }, 8000); return false;