From cc5ad456e6b65c3e0d8d1ad9d7bd7ab4b31d2249 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Wed, 14 Aug 2024 15:59:21 +0100 Subject: [PATCH] Expose the 'sanitize' system for backup restores to the web GUI --- .env.example | 1 + app/Http/Controllers/SettingsController.php | 28 ++++-- config/backup.php | 2 + resources/assets/js/snipeit.js | 99 ++++++------------- .../lang/en-US/admin/settings/general.php | 2 + resources/views/settings/backups.blade.php | 63 +++++++++--- 6 files changed, 108 insertions(+), 87 deletions(-) diff --git a/.env.example b/.env.example index 426af4ff88..946bcd8012 100644 --- a/.env.example +++ b/.env.example @@ -185,6 +185,7 @@ REQUIRE_SAML=false API_THROTTLE_PER_MINUTE=120 CSV_ESCAPE_FORMULAS=true LIVEWIRE_URL_PREFIX=null +SANITIZE_BY_DEFAULT=false # -------------------------------------------- # OPTIONAL: HASHING diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index e58647d72c..441db3f1f1 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -1203,7 +1203,7 @@ class SettingsController extends Controller * @author [A. Gianotto] [] * @since [v6.0] */ - public function postRestore($filename = null) : RedirectResponse + public function postRestore(Request $request, $filename = null): RedirectResponse { if (! config('app.lock_passwords')) { @@ -1223,13 +1223,29 @@ class SettingsController extends Controller Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename); - // run the restore command - Artisan::call('snipeit:restore', - [ + $restore_params = [ '--force' => 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 $output = Artisan::output(); diff --git a/config/backup.php b/config/backup.php index 3571329b23..412c9faced 100644 --- a/config/backup.php +++ b/config/backup.php @@ -237,4 +237,6 @@ return [ ], ], + 'sanitize_by_default' => env('SANITIZE_BY_DEFAULT', false), + ]; diff --git a/resources/assets/js/snipeit.js b/resources/assets/js/snipeit.js index f8b0a21efc..7c06ac6233 100755 --- a/resources/assets/js/snipeit.js +++ b/resources/assets/js/snipeit.js @@ -82,84 +82,45 @@ pieOptions = { var baseUrl = $('meta[name="baseUrl"]').attr('content'); -(function($, settings) { - var Components = {}; - Components.modals = {}; +$(function () { + + var $el = $('table'); // confirm restore modal - Components.modals.confirmRestore = function() { - var $el = $('table'); - var events = { - 'click': function(evnt) { - var $context = $(this); - var $restoreConfirmModal = $('#restoreConfirmModal'); - var href = $context.attr('href'); - var message = $context.attr('data-content'); - var title = $context.attr('data-title'); + $el.on('click', '.restore-asset', function (evnt) { + var $context = $(this); + var $restoreConfirmModal = $('#restoreConfirmModal'); + var href = $context.attr('href'); + var message = $context.attr('data-content'); + var title = $context.attr('data-title'); - $('#restoreConfirmModalLabel').text(title); - $restoreConfirmModal.find('.modal-body').text(message); - $('#restoreForm').attr('action', href); - $restoreConfirmModal.modal({ - show: true - }); - return false; - } - }; - - var render = function() { - $el.on('click', '.restore-asset', events['click']); - }; - - return { - render: render - }; - }; + $('#confirmModalLabel').text(title); + $restoreConfirmModal.find('.modal-body').text(message); + $('#restoreForm').attr('action', href); + $restoreConfirmModal.modal({ + show: true + }); + return false; + }); // confirm delete modal - Components.modals.confirmDelete = function() { - var $el = $('table'); - var events = { - 'click': function(evnt) { - var $context = $(this); - var $dataConfirmModal = $('#dataConfirmModal'); - var href = $context.attr('href'); - var message = $context.attr('data-content'); - var title = $context.attr('data-title'); + $el.on('click', '.delete-asset', function (evnt) { + var $context = $(this); + var $dataConfirmModal = $('#dataConfirmModal'); + var href = $context.attr('href'); + var message = $context.attr('data-content'); + var title = $context.attr('data-title'); - $('#myModalLabel').text(title); - $dataConfirmModal.find('.modal-body').text(message); - $('#deleteForm').attr('action', href); - $dataConfirmModal.modal({ - show: true - }); - 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(); + $('#myModalLabel').text(title); + $dataConfirmModal.find('.modal-body').text(message); + $('#deleteForm').attr('action', href); + $dataConfirmModal.modal({ + show: true + }); + return false; }); -}(jQuery, window.snipeit.settings)); - -$(document).ready(function () { /* * Slideout help menu diff --git a/resources/lang/en-US/admin/settings/general.php b/resources/lang/en-US/admin/settings/general.php index 31165cf3f0..1c62754778 100644 --- a/resources/lang/en-US/admin/settings/general.php +++ b/resources/lang/en-US/admin/settings/general.php @@ -31,6 +31,8 @@ return [ 'backups' => 'Backups', 'backups_help' => 'Create, download, and restore backups ', '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_path' => 'Backups on the server are stored in :path', 'backups_restore_warning' => 'Use the restore button to restore from a previous backup. (This does not currently work with S3 file storage or Docker.)

Your entire :app_name database and any uploaded files will be completely replaced by what\'s in the backup file. ', diff --git a/resources/views/settings/backups.blade.php b/resources/views/settings/backups.blade.php index d090daf3bb..e5d31f1506 100644 --- a/resources/views/settings/backups.blade.php +++ b/resources/views/settings/backups.blade.php @@ -7,7 +7,8 @@ @stop @section('header_right') - + {{ trans('general.back') }} @@ -21,8 +22,36 @@ {{-- Page content --}} @section('content') + -
+
@@ -85,13 +114,13 @@ @endif - + {{ trans('general.restore') }} @@ -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; + }) @stop