Merge pull request #1462 from RaspAP/feat/check-update

Feature: Check for update
This commit is contained in:
Bill Zimmerman 2023-11-25 13:18:19 +01:00 committed by GitHub
commit 7ac8d8b9f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 359 additions and 15 deletions

View File

@ -0,0 +1,26 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/config.php';
require_once '../../includes/defaults.php';
if (isset($_POST['csrf_token'])) {
if (csrfValidateRequest() && !CSRFValidate()) {
handleInvalidCSRFToken();
}
$uri = RASPI_API_ENDPOINT;
preg_match('/(\d+(\.\d+)+)/', RASPI_VERSION, $matches);
$thisRelease = $matches[0];
$json = shell_exec("wget --timeout=5 --tries=1 $uri -qO -");
$data = json_decode($json, true);
$tagName = $data['tag_name'];
$updateAvailable = checkReleaseVersion($thisRelease, $tagName);
$response['tag'] = $tagName;
$response['update'] = $updateAvailable;
echo json_encode($response);
} else {
handleInvalidCSRFToken();
}

View File

@ -0,0 +1,21 @@
<?php
require '../../includes/csrf.php';
if (isset($_POST['csrf_token'])) {
if (csrfValidateRequest() && !CSRFValidate()) {
handleInvalidCSRFToken();
}
// set installer path + options
$path = getenv("DOCUMENT_ROOT");
$opts = " --update --yes --path $path";
$installer = "sudo /etc/raspap/system/raspbian.sh";
$execUpdate = $installer.$opts;
$response = shell_exec($execUpdate);
echo json_encode($response);
} else {
handleInvalidCSRFToken();
}

View File

@ -0,0 +1,43 @@
<?php
$logFile = '/tmp/raspap_install.log';
$searchStrings = [
'Configure update' => 1,
'Updating sources' => 2,
'Installing required packages' => 3,
'Cloning latest files' => 4,
'Installing application' => 5,
'Installation completed' => 6,
'error' => 7
];
usleep(500);
if (file_exists($logFile)) {
$handle = fopen($logFile, 'r');
if ($handle) {
while (($line = fgets($handle)) !== false) {
foreach ($searchStrings as $searchString => $value) {
if (strpos($line, $searchString) !== false) {
echo $value .PHP_EOL;
flush();
ob_flush();
if ($value === 6) {
fclose($handle);
exit();
} elseif ($value === 7) {
echo $line .PHP_EOL;
fclose($handle);
exit();
}
}
}
}
fclose($handle);
} else {
echo json_encode("Unable to open file: $logFile");
}
} else {
echo json_encode("File does not exist: $logFile");
}

View File

@ -276,6 +276,98 @@ $('#debugModal').on('shown.bs.modal', function (e) {
});
});
$('#chkupdateModal').on('shown.bs.modal', function (e) {
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_chk_update.php',{'csrf_token': csrfToken},function(data){
var response = JSON.parse(data);
var tag = response.tag;
var update = response.update;
var msg;
var msgUpdate = $('#msgUpdate').data('message');
var msgLatest = $('#msgLatest').data('message');
var msgInstall = $('#msgInstall').data('message');
var msgDismiss = $('#js-check-dismiss').data('message');
var faCheck = '<i class="fas fa-check ml-2"></i><br />';
$("#updateSync").removeClass("fa-spin");
if (update === true) {
msg = msgUpdate +' '+tag;
$("#msg-check-update").html(msg);
$("#msg-check-update").append(faCheck);
$("#msg-check-update").append("<p>"+msgInstall+"</p>");
$("#js-sys-check-update").removeClass("collapse");
} else {
msg = msgLatest;
dismiss = $("#js-check-dismiss");
$("#msg-check-update").html(msg);
$("#msg-check-update").append(faCheck);
$("#js-sys-check-update").remove();
dismiss.text(msgDismiss);
dismiss.removeClass("btn-outline-secondary");
dismiss.addClass("btn-primary");
}
});
});
$('#performUpdate').on('submit', function(event) {
event.preventDefault();
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_perform_update.php',{
'csrf_token': csrfToken
})
$('#chkupdateModal').modal('hide');
$('#performupdateModal').modal('show');
});
$('#performupdateModal').on('shown.bs.modal', function (e) {
fetchUpdateResponse();
});
function fetchUpdateResponse() {
const xhr = new XMLHttpRequest();
const complete = 6;
const error = 7;
let phpFile = 'ajax/system/sys_read_logfile.php';
$.ajax({
url: phpFile,
type: 'GET',
success: function(response) {
let endPolling = false;
for (let i = 1; i <= 6; i++) {
let divId = '#updateStep' + i;
if (response.includes(i.toString())) {
$(divId).removeClass('invisible');
}
if (response.includes(complete)) {
var successMsg = $('#successMsg').data('message');
$('#updateMsg').after('<span class="small">' + successMsg + '</span>');
$('#updateMsg').addClass('fa-check');
$('#updateMsg').removeClass('invisible');
$('#updateStep6').removeClass('invisible');
$('#updateSync2').removeClass("fa-spin");
$('#updateOk').removeAttr('disabled');
endPolling = true;
break;
} else if (response.includes(error)) {
var errorMsg = $('#errorMsg').data('message');
$('#updateMsg').after('<span class="small">' + errorMsg + '</span>');
$('#updateMsg').addClass('fa-times');
$('#updateMsg').removeClass('invisible');
$('#updateSync2').removeClass("fa-spin");
$('#updateOk').removeAttr('disabled');
endPolling = true;
break;
}
}
if (!endPolling) {
setTimeout(fetchUpdateResponse, 500);
}
},
error: function(xhr, status, error) {
console.error(error);
}
});
}
$('#hostapdModal').on('shown.bs.modal', function (e) {
var seconds = 3;
var pct = 0;

View File

@ -31,6 +31,9 @@ define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one');
// Constant for the GitHub API latest release endpoint
define('RASPI_API_ENDPOINT', 'https://api.github.com/repos/RaspAP/raspap-webgui/releases/latest');
// Constant for the 5GHz wireless regulatory domain
define("RASPI_5GHZ_CHANNEL_MIN", 100);
define("RASPI_5GHZ_CHANNEL_MAX", 192);

View File

@ -899,3 +899,28 @@ function getCountryCodes($locale = 'en', $flag = true) {
return $countryData;
}
/**
* Compares the current release with the latest available release
*
* @param string $installed
* @param string $latest
* @return boolean
*/
function checkReleaseVersion($installed, $latest) {
$installedArray = explode('.', $installed);
$latestArray = explode('.', $latest);
// compare segments of the version number
for ($i = 0; $i < max(count($installedArray), count($latestArray)); $i++) {
$installedSegment = (int)($installedArray[$i] ?? 0);
$latestSegment = (int)($latestArray[$i] ?? 0);
if ($installedSegment < $latestSegment) {
return true;
} elseif ($installedSegment > $latestSegment) {
return false;
}
}
return false;
}

View File

@ -545,33 +545,39 @@ function _create_openvpn_scripts() {
# Fetches latest files from github to webroot
function _download_latest_files() {
if [ -d "$webroot_dir" ] && [ "$update" == 0 ]; then
sudo mv $webroot_dir "$webroot_dir.`date +%F-%R`" || _install_status 1 "Unable to remove old webroot directory"
elif [ "$upgrade" == 1 ] || [ "$update" == 1 ]; then
sudo rm -rf "$webroot_dir"
fi
_install_log "Cloning latest files from GitHub"
source_dir="/tmp/raspap-webgui"
if [ -d "$source_dir" ]; then
echo "Temporary download destination $source_dir exists. Removing..."
rm -r "$source_dir"
fi
if [ "$repo" == "RaspAP/raspap-insiders" ]; then
if [ -n "$username" ] && [ -n "$acctoken" ]; then
insiders_source_url="https://${username}:${acctoken}@github.com/$repo"
git clone --branch $branch --depth 1 -c advice.detachedHead=false $insiders_source_url /tmp/raspap-webgui || clone=false
git clone --branch $branch --depth 1 -c advice.detachedHead=false $insiders_source_url $source_dir || clone=false
else
_install_status 3
echo "Insiders please read this: https://docs.raspap.com/insiders/#authentication"
fi
fi
if [ -z "$insiders_source_url" ]; then
git clone --branch $branch --depth 1 -c advice.detachedHead=false $git_source_url /tmp/raspap-webgui || clone=false
git clone --branch $branch --depth 1 -c advice.detachedHead=false $git_source_url $source_dir || clone=false
fi
if [ "$clone" = false ]; then
_install_status 1 "Unable to download files from github"
_install_status 1 "Unable to download files from GitHub"
echo "The installer cannot continue." >&2
exit 1
fi
if [ -d "$webroot_dir" ] && [ "$update" == 0 ]; then
sudo mv $webroot_dir "$webroot_dir.`date +%F-%R`" || _install_status 1 "Unable to move existing webroot directory"
elif [ "$upgrade" == 1 ] || [ "$update" == 1 ]; then
shopt -s extglob
sudo find "$webroot_dir" ! -path "${webroot_dir}/ajax/system/sys_read_logfile.php" -delete 2>/dev/null
fi
_install_log "Installing application to $webroot_dir"
sudo mv /tmp/raspap-webgui $webroot_dir || _install_status 1 "Unable to move raspap-webgui to $webroot_dir"
sudo rsync -av --exclude='ajax/system/sys_read_logfile.php' "$source_dir"/ "$webroot_dir"/ >/dev/null 2>&1 || _install_status 1 "Unable to install files to $webroot_dir"
if [ "$update" == 1 ]; then
_install_log "Applying existing configuration to ${webroot_dir}/includes"
@ -582,11 +588,13 @@ function _download_latest_files() {
sudo mv /tmp/raspap.auth $raspap_dir || _install_status 1 "Unable to restore authentification credentials file to ${raspap_dir}"
fi
else
echo "Copying primary RaspAP config to includes/config.php"
echo "Copying primary RaspAP config to ${webroot_dir}/includes/config.php"
if [ ! -f "$webroot_dir/includes/config.php" ]; then
sudo cp "$webroot_dir/config/config.php" "$webroot_dir/includes/config.php"
fi
fi
echo "Removing source files at ${source_dir}"
sudo rm -rf $source_dir
_install_status 0
}
@ -777,9 +785,12 @@ function _patch_system_files() {
sudo mkdir $raspap_dir/system || _install_status 1 "Unable to create directory '$raspap_dir/system'"
fi
_install_log "Creating RaspAP debug log control script"
_install_log "Copying RaspAP debug log control script"
sudo cp "$webroot_dir/installers/"debuglog.sh "$raspap_dir/system" || _install_status 1 "Unable to move debug logging script"
_install_log "Copying RaspAP install loader"
sudo cp "$webroot_dir/installers/"raspbian.sh "$raspap_dir/system" || _install_status 1 "Unable to move application update script"
# Set ownership and permissions
sudo chown -c root:root "$raspap_dir/system/"*.sh || _install_status 1 "Unable change owner and/or group"
sudo chmod 750 "$raspap_dir/system/"*.sh || _install_status 1 "Unable to change file permissions"

View File

@ -42,6 +42,7 @@ www-data ALL=(ALL) NOPASSWD:/etc/raspap/lighttpd/configport.sh
www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/configauth.sh
www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/openvpnlog.sh
www-data ALL=(ALL) NOPASSWD:/etc/raspap/system/debuglog.sh
www-data ALL=(ALL) NOPASSWD:/etc/raspap/system/raspbian.sh
www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/hostapd.log
www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /var/log/dnsmasq.log
www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/wireguard.log

View File

@ -187,6 +187,9 @@ function _setup_colors() {
function _log_output() {
readonly LOGFILE_PATH="/tmp"
if [ -f "$LOGFILE_PATH/raspap_install.log" ]; then
sudo rm "$LOGFILE_PATH/raspap_install.log"
fi
exec > >(tee -i $LOGFILE_PATH/raspap_install.log)
exec 2>&1
}

Binary file not shown.

View File

@ -1457,3 +1457,60 @@ msgstr "Insiders"
msgid "Contributing"
msgstr "Contributing"
msgid "Check for update"
msgstr "Check for update"
msgid "New release check in progress..."
msgstr "New release check in progress..."
msgid "A new release is available: Version"
msgstr "A new release is available: Version"
msgid "Installed version is the latest release."
msgstr "Installed version is the latest release."
msgid "GitHub authentication"
msgstr "GitHub authentication"
msgid "Updating Insiders requires GitHub authentication."
msgstr "Updating Insiders requires GitHub authentication."
msgid "Your credentials will be sent to GitHub securely with SSL. However, use caution if your RaspAP install is on a WLAN shared by untrusted users."
msgstr "Your credentials will be sent to GitHub securely with SSL. However, use caution if your RaspAP install is on a WLAN shared by untrusted users."
msgid "Personal Access Token"
msgstr "Personal Access Token"
msgid "Please provide a valid token."
msgstr "Please provide a valid token."
msgid "Perform update"
msgstr "Perform update"
msgid "Update in progress"
msgstr "Update in progress"
msgid "Application is being updated..."
msgstr "Application is being updated..."
msgid "Configuring update"
msgstr "Configuring update"
msgid "Updating sources"
msgstr "Updating sources"
msgid "Installing package updates"
msgstr "Installing package updates"
msgid "Downloading latest files"
msgstr "Downloading latest files"
msgid "Installing application"
msgstr "Installing application"
msgid "Update complete"
msgstr "Update complete"
msgid "An error occurred. Check the log at <code>/tmp/raspap_install.log</code>"
msgstr "An error occurred. Check the log at <code>/tmp/raspap_install.log</code>"

View File

@ -36,3 +36,53 @@ require_once 'app/lib/Parsedown.php';
</div><!-- /.card -->
</div><!-- /.col-lg-12 -->
</div><!-- /.row -->
<!-- modal check-update-->
<div class="modal fade" id="chkupdateModal" tabindex="-1" role="dialog" aria-labelledby="ModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form id="performUpdate" class="needs-validation" novalidate>
<div class="modal-header">
<div class="modal-title" id="ModalLabel"><i class="fas fa-sync-alt fa-spin mr-2" id="updateSync"></i><?php echo _("Check for update"); ?></div>
</div>
<div class="modal-body">
<div class="col-md-12 mb-3 mt-1" id="msg-check-update"><?php echo _("New release check in progress..."); ?></div>
</div>
<div class="modal-footer">
<div id="msgUpdate" data-message="<?php echo _("A new release is available: Version"); ?>"></div>
<div id="msgLatest" data-message="<?php echo _("Installed version is the latest release."); ?>"></div>
<div id="msgInstall" data-message="<?php echo _("Install this update now?"); ?>"></div>
<button type="button" data-message="<?php echo _("OK"); ?>" id="js-check-dismiss" class="btn btn-outline-secondary" data-dismiss="modal"><?php echo _("Cancel"); ?></button>
<button type="submit" id="js-sys-check-update" class="btn btn-outline btn-primary collapse"><?php echo _("OK"); ?></button>
</div>
</form>
</div>
</div>
</div>
<!-- modal update-cmd -->
<div class="modal fade" id="performupdateModal" tabindex="-1" role="dialog" aria-labelledby="ModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title" id="ModalLabel"><i class="fas fa-sync-alt fa-spin mr-2" id="updateSync2"></i><?php echo _("Update in progress"); ?></div>
</div>
<div class="modal-body">
<div class="col-md-12 mb-3 mt-1" id="msg-check-update"><?php echo _("Application is being updated..."); ?></div>
<div class="ml-5"><i class="fas fa-check mr-2 invisible" id="updateStep1"></i><?php echo _("Configuring update"); ?></div>
<div class="ml-5"><i class="fas fa-check mr-2 invisible" id="updateStep2"></i><?php echo _("Updating sources"); ?></div>
<div class="ml-5"><i class="fas fa-check mr-2 invisible" id="updateStep3"></i><?php echo _("Installing package updates"); ?></div>
<div class="ml-5"><i class="fas fa-check mr-2 invisible" id="updateStep4"></i><?php echo _("Downloading latest files"); ?></div>
<div class="ml-5"><i class="fas fa-check mr-2 invisible" id="updateStep5"></i><?php echo _("Installing application"); ?></div>
<div class="ml-5 mb-1"><i class="fas fa-check mr-2 invisible" id="updateStep6"></i><?php echo _("Update complete"); ?></div>
<div class="ml-5 mb-3"><i class="fas mr-2 invisible" id="updateMsg"></i></div>
<div id="errorMsg" data-message="<?php echo _("An error occurred. Check the log at <code>/tmp/raspap_install.log</code>"); ?>"></div>
<div id="successMsg" data-message="<?php echo _("Success. Refresh this page to confirm the new version."); ?>"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline btn-primary" data-dismiss="modal" disabled id="updateOk" /><?php echo _("OK"); ?></button>
</div>
</div>
</div>
</div>

View File

@ -1,9 +1,21 @@
<!-- about general tab -->
<div class="tab-pane active" id="aboutgeneral">
<div class="row">
<div class="col-md-8">
<h2 class="mt-3"><?php echo _("RaspAP") ." v".RASPI_VERSION; ?></h2>
<div class="ml-5 mt-3"><img class="about-logo" src="app/img/raspAP-logo.php" style="width: 175px; height:175px"></div>
<div class="col-md-6 mt-3">
<div class="card">
<div class="card-body">
<div class="ml-5 mt-2"><img class="about-logo" src="app/img/raspAP-logo.php" style="width: 175px; height:175px"></div>
<h2 class="mt-3 ml-4"><?php echo _("RaspAP") ." v".RASPI_VERSION; ?></h2>
<?php if (!RASPI_MONITOR_ENABLED) : ?>
<button type="button" class="btn btn-warning ml-4 mt-2" name="check-update" data-toggle="modal" data-target="#chkupdateModal" />
<i class="fas fa-sync-alt ml-1 mr-2"></i><?php echo _("Check for update"); ?>
</button>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-md-8">
<div class="mt-3">RaspAP is a co-creation of <a href="https://github.com/billz">billz</a> and <a href="https://github.com/sirlagz">SirLagz</a>
with the contributions of our <a href="https://github.com/raspap/raspap-webgui/graphs/contributors">developer community</a>
and <a href="https://crowdin.com/project/raspap">language translators</a>.