Pull to refresh

Быстрое и надежное резервное копирование данных в облако 2

Reading time6 min
Views5.1K
В моей предыдущей статье я описал пример скрипта, который может заархивировать и закинуть в облако определенный объем файлов пользователя без его участия, тем самым обеспечив простейшее резервное копирование файлов пользователя. Скрипт обеспечивает закрытие следующих вопросов:

  • быстрое (идеально в фоне);
  • сохраняло бы как актуальную версию файлов, так и предыдущие;
  • хранилище файлов было бы недоступно вирусам или стихийным бедствиям типа уничтожения носителя или его воровства;
  • содержимое резевной копии было бы доступно только пользователю, т.е. паролировалось.

Естественно, простота скрипта обернулась и его недостатками, а именно:

  • Хранение паролей в теле скрипта. Да, многие программы хранят пароли незашифрованными в текстовых файлах, и защита этих данных происходит через контроль доступа к файлам, но все таки вынести пароль из кода — это признак хорошего тона и минимальной защиты на случай, если каким то образом рабочий скрипт попадет в чужие руки.
  • Отсутствие проверки успешного завершения операции, и откат к предыдущему состоянию в случае если операция не была успешно завершена.
  • Отсутствие логирования и оповещения пользователя об успешности операции, если скрипт запускается через планировщик заданий.

В связи с этим код скриптов полного и инкрементного архива был дополнен необходимым функционалом. Общее описание см. предыщущую статью, здесь я хочу остановиться лишь на изменениях.

Скрипт создания полного архива


@echo off
chcp 1251 >nul
set filebkp=server
call pass.bat user 1
call pass.bat pass 2
call pass.bat pwd 3
call pass.bat recipient 4
set mailsend=mailsend1.17b15.exe
set i=1
set pathbkp=..\backup
set pathtemp=..\temp
set srvbkp=https://%user%:%pass%@webdav.yandex.ru/backup/%filebkp%
set full=%filebkp%-full
set inc=%filebkp%-inc
set h=%TIME:~0,2%
set m=%TIME:~3,2%
set s=%TIME:~6,2%
set ms=%TIME:~9,2%
set curtime=%h%-%m%-%s%
set dd=%DATE:~0,2%
set mm=%DATE:~3,2%
set yyyy=%DATE:~6,4%
set curdate=%yyyy%-%mm%-%dd%
set curdatetime=%curdate: =0%-%curtime: =0%
call :loging "-----------------------------------"
call :loging "Текущее время - %curdatetime%"
call :loging "Создаем резервную копию текущих архивов"
ren "%pathtemp%" temp-bkp
md "%pathtemp%"
call :loging "Создаем полный архив %full%.7z"
7z.exe a -xr0!*.log -xr0!*.bak -xr0!*.tmp "%pathtemp%\%full%".7z -r -mx1 "%pathbkp%\*" -%pwd%
call :loging "Создаем резервную копию текущих архивов на сервере"
curl.exe -k -X MOVE -H "Destination:/backup/%filebkp%"-bkp "%srvbkp%" -o .\stdout
curl.exe -k -X MKCOL "%srvbkp%" -o .\stdout
:upload
call :loging "Попытка отправки номер %i%"
call :loging "Отправляем на сервер файл %full%.7z"
curl.exe -k -T "%pathtemp%\%full%".7z "%srvbkp%"/ --progress-bar -o .\stdout
call :loging "Скачиваем файл %full%.7z с сервера для сравнения с исходным"
curl.exe -k "%srvbkp%/%full%".7z -o "%pathtemp%"\test.7z --progress-bar -o .\stdout
call :loging "Сравниваем скачанный файл с исходным"
fc /LB1 /B "%pathtemp%\%full%".7z "%pathtemp%"\test.7z > nul
if ERRORLEVEL 1 goto Different
call :loging "Файлы одинаковы:"
set tolog="%full%.7z успешно отправлен на сервер"
call :loging %tolog%
set mailsubject=%tolog:"=%
call :loging "Удаляем устаревшие версии архива с компьютера и сервера"
RD /s/q "%pathtemp%"-bkp
curl.exe -k -X DELETE "%srvbkp%"-bkp -o .\stdout
del /q "%pathtemp%"\test.7z
goto exit
:Different
call :loging "Файлы различаются: %full%.7z на сервере НЕ совпадает с исходным"
call :loging "Повторяем отправку"
set /a i+=1
if %i% = 5 goto exit-f
goto upload
:exit-f
set tolog="Отправка файла %full%.7z на сервер не удалась"
call :loging %tolog%
set mailsubject=%tolog:"=%
call :loging "Восстанавливаем файлы предыдущего архива"
RD /s/q "%pathtemp%"
ren "%pathtemp%"-bkp temp
curl.exe -k -X DELETE "%srvbkp%" -o .\stdout
curl.exe -k -X MOVE -H "Destination:/backup/%filebkp%" "%srvbkp%"-bkp -o .\stdout
:exit
echo Отправляем лог %filebkp%-log.txt на сервер
curl.exe -k -T %filebkp%-log.txt "%srvbkp%"/../ --progress-bar -o .\stdout
echo Отправляем отчет в почту
%mailsend% -to %recipient% -from %user%@yandex.ru -ssl -port 465 -auth -smtp smtp.yandex.ru -user %user% -pass %pass% -sub "%filebkp%: %curdatetime% - %mailsubject%" -cs "windows-1251" -mime-type "text/plain" -msg-body %filebkp%-log.tmp
del /q %filebkp%-log.tmp
exit

:loging
echo %~1
echo %~1 >> %filebkp%-log.txt
echo %~1 >> %filebkp%-log.tmp
exit /b

Скрипт создания инкрементного архива


@echo off
chcp 1251 >nul
set filebkp=server
call pass.bat user 1
call pass.bat pass 2
call pass.bat pwd 3
call pass.bat recipient 4
set mailsend=mailsend1.17b15.exe
set tolog=zero
set mailsubject=zero
set i=1
set pathbkp=..\backup
set pathtemp=..\temp
set srvbkp=https://%user%:%pass%@webdav.yandex.ru/backup/%filebkp%
set full=%filebkp%-full
set inc=%filebkp%-inc
set h=%TIME:~0,2%
set m=%TIME:~3,2%
set s=%TIME:~6,2%
set ms=%TIME:~9,2%
set curtime=%h%-%m%-%s%
set dd=%DATE:~0,2%
set mm=%DATE:~3,2%
set yyyy=%DATE:~6,4%
set curdate=%yyyy%-%mm%-%dd%
set curdatetime=%curdate: =0%-%curtime: =0%
call :loging "-----------------------------------"
call :loging "Текущее время - %curdatetime%"
call :loging "Создаем инкрементный архив %inc%-%curdatetime%.7z"
7z.exe u -xr0!*.log -xr0!*.bak -xr0!*.tmp "%pathtemp%\%full%".7z -u- -up3q3r2x2y2z0w2!"%pathtemp%\%inc%-%curdatetime%".7z "%pathbkp%\*" -%pwd%
:upload
call :loging "Попытка отправки номер %i%"
call :loging "Отправляем архив на сервер"
curl.exe -k -T "%pathtemp%\%inc%-%curdatetime%".7z "%srvbkp%"/ --progress-bar -o .\stdout
call :loging "Скачиваем архив с сервера для сравнения с исходным"
curl.exe -k "%srvbkp%/%inc%-%curdatetime%".7z -o "%pathtemp%"\test.7z --progress-bar -o .\stdout
call :loging "Сравниваем скачанный архив с исходным"
fc /LB1 /B "%pathtemp%\%inc%-%curdatetime%".7z "%pathtemp%"\test.7z > nul
if ERRORLEVEL 1 goto Different
call :loging "Файлы одинаковы"
set tolog="%inc%-%curdatetime%.7z успешно отправлен на сервер"
call :loging %tolog%
set mailsubject=%tolog:"=%
goto exit
:Different
call :loging "Файлы различаются: %inc%-%curdatetime%.7z на сервере НЕ совпадает с исходным"
call :loging "Повторяем отправку"
set /a i+=1
if %i% = 5 goto exit-f
goto upload
:exit-f
set tolog="Отправка файла %inc%-%curdatetime%.7z на сервер не удалась"
call :loging %tolog%
set mailsubject=%tolog:"=%
:exit
del /q "%pathtemp%"\test.7z
echo Отправляем лог %filebkp%-log.txt на сервер
curl.exe -k -T %filebkp%-log.txt "%srvbkp%"/../ --progress-bar -o .\stdout
echo Отправляем отчет в почту
%mailsend% -to %recipient% -from %user%@yandex.ru -ssl -port 465 -auth -smtp smtp.yandex.ru -user %user% -pass %pass% -sub "%filebkp%: %mailsubject%" -cs "windows-1251" -mime-type "text/plain" -msg-body %filebkp%-log.tmp
del /q %filebkp%-log.tmp
exit

:loging
echo %~1
echo %~1 >> %filebkp%-log.txt
echo %~1 >> %filebkp%-log.tmp
exit /b

Новые команды:


call pass.bat xx x — вызов внешней программы, возвращающей обратно переменную xx со значением, указанным для идентификатора x.

Соответственно переменной user присваивается значение, привязанное к идентификатору 1 (имя пользователя учетной записи yandex), pass — 2 (пароль учетной записи yandex), pwd — 3 (пароль к архиву), recipient — 4 (почта, куда отправить лог операции).

Скрипт pass.bat приведен условно, метод защиты паролей может быть выбран другой, но для тех и этот вариант подходит, привожу самый простой код этого скрипта:

for /f "usebackq  delims=" %%i in (`find /n /v "" "%~dp0"pass.txt ^| find "[%2]"`) do (
set newvar=%%i
)
set %1=%newvar:~3%

Данный код при его вызове находит рядом с собой файл pass.txt, и присваивает переменной, имя которой указано в первом аргументе вызова скрипта, значение той строки файла pass.txt, номер которой указан во втором аргументе вызова скрипта. Расположение файлов pass.bat и pass.txt не принципиально, лишь бы они лежали в одном каталоге, который указан в переменной path системы.

set mailsend=mailsend1.17b15.exe — указание программы для отправки отчета в почту пользователя. Отправка письма происходит с учетной записи yandex.ru, с которой происходит отправка файлов в облако.

set i=1 — установка счетчика попыток на 1

call :loging "-----------------------------------" — вызов процедуры логирования. Процедуре передается строка, которая далее записывается в 2 файла — файл лога %filebkp%-log.txt и отдельный файл текущих операций %filebkp%-log.tmp, который затем отправляется пользователю как отчет об результате архивирования.

Соответственно строки логирования в теле скриптов одновременно показывают пользователю совершаемые операции во время работы, записывают их в логи и для меня являются комментариями в теле скрипта, поясняющими что выполняется на последующих строках.

Соотвественно скрипт полного копирования и скрипт инкрементного копирования выполняют следующие операции:

  1. для полного архива — создает резервные копии текущих архивов на сервере и на локальном компьютере
  2. создает новую резервную копию
  3. пытается отправить её на сервер
  4. после отправки скачивает резервную копию и сравнивает с оригиналом
  5. в случае успеха сравнения — отправляет на сервер лог операций и пользователю в почту отчет об успешной операции через программу mailsend1.17b15.exe + для полного архива — удаляет устаревшие версии архива
  6. в случае обнаружения разницы между файлами — пытается выполнить повторную отправку файла на сервер, и если в течении 5 попыток отправка не удается — отправляет на сервер лог операций и пользователю в почту отчет об неудаче через программу mailsend1.17b15.exe:
  7. подчищает временный файл текущих операций.

P.S.


Данные скрипты приведены лишь как примеры, переписывать под PowerShell пока нет желания, т.к. мне важно чтобы он работал на любой системе, включая Windows XP. Защиты от кражи паролей здесь нет, самому было бы интересно что предложили бы специалисты по безопасности, но разделение кода и паролей с возможностью размещения паролей в другом каталоге хотя бы снимает вероятность глупой ошибки, что при отправке скрипта другу ему же достанутся и пароли.
Tags:
Hubs:
+7
Comments15

Articles

Change theme settings