Expose the 'sanitize' system for backup restores to the web GUI

This commit is contained in:
Brady Wetherington 2024-08-14 15:59:21 +01:00
parent 0f1e5181a6
commit cc5ad456e6
6 changed files with 108 additions and 87 deletions

View file

@ -185,6 +185,7 @@ REQUIRE_SAML=false
API_THROTTLE_PER_MINUTE=120 API_THROTTLE_PER_MINUTE=120
CSV_ESCAPE_FORMULAS=true CSV_ESCAPE_FORMULAS=true
LIVEWIRE_URL_PREFIX=null LIVEWIRE_URL_PREFIX=null
SANITIZE_BY_DEFAULT=false
# -------------------------------------------- # --------------------------------------------
# OPTIONAL: HASHING # OPTIONAL: HASHING

View file

@ -1203,7 +1203,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>] * @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.0] * @since [v6.0]
*/ */
public function postRestore($filename = null) : RedirectResponse public function postRestore(Request $request, $filename = null): RedirectResponse
{ {
if (! config('app.lock_passwords')) { if (! config('app.lock_passwords')) {
@ -1223,13 +1223,29 @@ class SettingsController extends Controller
Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename); Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);
// run the restore command $restore_params = [
Artisan::call('snipeit:restore',
[
'--force' => true, '--force' => true,
'--no-progress' => true, '--no-progress' => true,
'filename' => storage_path($path).'/'.$filename 'filename' => storage_path($path) . '/' . $filename
];
if ($request->input('clean')) {
Log::debug("Attempting 'clean' - first, guessing prefix...");
Artisan::call('snipeit:restore', [
'--sanitize-guess-prefix' => true,
'filename' => storage_path($path) . '/' . $filename
]); ]);
$guess_prefix_output = Artisan::output();
Log::debug("Sanitize output is: $guess_prefix_output");
list($prefix, $_output) = explode("\n", $guess_prefix_output);
Log::debug("prefix is: '$prefix'");
$restore_params['--sanitize-with-prefix'] = $prefix;
}
// run the restore command
Artisan::call('snipeit:restore',
$restore_params
);
// If it's greater than 300, it probably worked // If it's greater than 300, it probably worked
$output = Artisan::output(); $output = Artisan::output();

View file

@ -237,4 +237,6 @@ return [
], ],
], ],
'sanitize_by_default' => env('SANITIZE_BY_DEFAULT', false),
]; ];

View file

@ -82,47 +82,31 @@ pieOptions = {
var baseUrl = $('meta[name="baseUrl"]').attr('content'); var baseUrl = $('meta[name="baseUrl"]').attr('content');
(function($, settings) { $(function () {
var Components = {};
Components.modals = {};
// confirm restore modal
Components.modals.confirmRestore = function() {
var $el = $('table'); var $el = $('table');
var events = { // confirm restore modal
'click': function(evnt) {
$el.on('click', '.restore-asset', function (evnt) {
var $context = $(this); var $context = $(this);
var $restoreConfirmModal = $('#restoreConfirmModal'); var $restoreConfirmModal = $('#restoreConfirmModal');
var href = $context.attr('href'); var href = $context.attr('href');
var message = $context.attr('data-content'); var message = $context.attr('data-content');
var title = $context.attr('data-title'); var title = $context.attr('data-title');
$('#restoreConfirmModalLabel').text(title); $('#confirmModalLabel').text(title);
$restoreConfirmModal.find('.modal-body').text(message); $restoreConfirmModal.find('.modal-body').text(message);
$('#restoreForm').attr('action', href); $('#restoreForm').attr('action', href);
$restoreConfirmModal.modal({ $restoreConfirmModal.modal({
show: true show: true
}); });
return false; return false;
} });
};
var render = function() {
$el.on('click', '.restore-asset', events['click']);
};
return {
render: render
};
};
// confirm delete modal // confirm delete modal
Components.modals.confirmDelete = function() {
var $el = $('table');
var events = { $el.on('click', '.delete-asset', function (evnt) {
'click': function(evnt) {
var $context = $(this); var $context = $(this);
var $dataConfirmModal = $('#dataConfirmModal'); var $dataConfirmModal = $('#dataConfirmModal');
var href = $context.attr('href'); var href = $context.attr('href');
@ -136,30 +120,7 @@ var baseUrl = $('meta[name="baseUrl"]').attr('content');
show: true show: true
}); });
return false; return false;
}
};
var render = function() {
$el.on('click', '.delete-asset', events['click']);
};
return {
render: render
};
};
/**
* Application start point
* Component definition stays out of load event, execution only happens.
*/
$(function() {
new Components.modals.confirmRestore().render();
new Components.modals.confirmDelete().render();
}); });
}(jQuery, window.snipeit.settings));
$(document).ready(function () {
/* /*
* Slideout help menu * Slideout help menu

View file

@ -31,6 +31,8 @@ return [
'backups' => 'Backups', 'backups' => 'Backups',
'backups_help' => 'Create, download, and restore backups ', 'backups_help' => 'Create, download, and restore backups ',
'backups_restoring' => 'Restoring from Backup', 'backups_restoring' => 'Restoring from Backup',
'backups_clean' => 'Clean the backed-up database before restore',
'backups_clean_helptext' => "This can be useful if you're changing between database versions",
'backups_upload' => 'Upload Backup', 'backups_upload' => 'Upload Backup',
'backups_path' => 'Backups on the server are stored in <code>:path</code>', 'backups_path' => 'Backups on the server are stored in <code>:path</code>',
'backups_restore_warning' => 'Use the restore button <small><span class="btn btn-xs btn-warning"><i class="text-white fas fa-retweet" aria-hidden="true"></i></span></small> to restore from a previous backup. (This does not currently work with S3 file storage or Docker.)<br><br>Your <strong>entire :app_name database and any uploaded files will be completely replaced</strong> by what\'s in the backup file. ', 'backups_restore_warning' => 'Use the restore button <small><span class="btn btn-xs btn-warning"><i class="text-white fas fa-retweet" aria-hidden="true"></i></span></small> to restore from a previous backup. (This does not currently work with S3 file storage or Docker.)<br><br>Your <strong>entire :app_name database and any uploaded files will be completely replaced</strong> by what\'s in the backup file. ',

View file

@ -7,7 +7,8 @@
@stop @stop
@section('header_right') @section('header_right')
<a href="{{ route('settings.index') }}" class="btn btn-default pull-right" style="margin-left: 5px;"> <a href="{{ route('settings.index') }}" class="btn btn-default pull-right" style="margin-left: 5px;"
xmlns="http://www.w3.org/1999/html">
{{ trans('general.back') }} {{ trans('general.back') }}
</a> </a>
@ -21,8 +22,36 @@
{{-- Page content --}} {{-- Page content --}}
@section('content') @section('content')
<div class="modal modal-warning fade" tabindex="-1" role="dialog" id="backupRestoreModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form method="post" role="form">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>{{ trans('admin/settings/message.backup.restore_warning') }}</p>
<p><label><input type="checkbox"
name="clean" {{ config('backup.sanitize_by_default') ? "checked='checked'" : "" }}>{{ trans('admin/settings/general.backups_clean') }}
</label></p>
<p>{{ trans('admin/settings/general.backups_clean_helptext') }}</p>
</div>
<div class="modal-footer">
{{ csrf_field() }}
{{ method_field('POST') }}
<button type="button" class="btn btn-default pull-left"
data-dismiss="modal">{{ trans('general.cancel') }}</button>
<button type="submit" class="btn btn-outline">{{ trans('general.yes') }}</button>
</div>
</form>
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
@ -87,9 +116,9 @@
<a data-html="true" <a data-html="true"
href="{{ route('settings.backups.restore', $file['filename']) }}" href="{{ route('settings.backups.restore', $file['filename']) }}"
class="btn btn-warning btn-sm restore-asset {{ (config('app.lock_passwords')) ? ' disabled': '' }}" class="btn btn-warning btn-sm restore-backup {{ (config('app.lock_passwords')) ? ' disabled': '' }}"
data-toggle="modal" {{-- data-toggle="modal"--}}
data-content="{{ trans('admin/settings/message.backup.restore_warning') }}" data-target="#backupRestoreModal"
data-title="{{ trans('admin/settings/message.backup.restore_confirm', array('filename' => e($file['filename']))) }}" data-title="{{ trans('admin/settings/message.backup.restore_confirm', array('filename' => e($file['filename']))) }}"
onClick="return false;"> onClick="return false;">
<i class="fas fa-retweet" aria-hidden="true"></i> <i class="fas fa-retweet" aria-hidden="true"></i>
@ -226,11 +255,21 @@
}); });
} }
}); });
}); });
// due to dynamic loading, we have to use the below 'weird' way of adding event handlers instead of just saying
// $('.restore-backup').on( .....
$('table').on('click', '.restore-backup', function (event) {
event.preventDefault();
var modal = $('#backupRestoreModal');
modal.find('.modal-title').text($(this).data('title'));
modal.find('form').attr('action', $(this).attr('href'));
modal.modal({
show: true
});
return false;
})
</script> </script>
@stop @stop