И сбоку батник. Задаем KeePass'у параметры запуска

Запуская KeePass батником, мы можем по-своему задавать рабочий каталог, аргументы командной строки, значения переменных среды, а также обращаться к стандартному потоку ввода. Что это дает?

Фиксируем рабочий каталог

Многие программы — и KeePass 2.x тут не исключение — считают рабочим каталогом место, обусловленное способом запуска, а не своим расположением. Из-за этого при обращении к базам и компонентам программы приходится указывать пути полностью.

Чтобы избежать непредсказуемости в положении рабочего каталога, можно условиться всегда запускать KeePass каким-нибудь стартером, который устанавливает рабочим каталогом расположение программы. Простейшим вариантом будет батник Run.bat, лежащий в каталоге программы и состоящий из строки:

start "" /d "%~dp0" KeePass.exe

Этот батник можно будет запускать уже произвольным способом, например, ярлыком на рабочем столе (для красоты — с измененным значком и опцией свернутого окна).

Ярлык и батник, запускающие KeePass

Теперь, когда рабочий каталог зафиксирован, во многих строках базы и конфигурации можно будет использовать вместо абсолютных путей относительные. Однако не будем злоупотреблять этой возможностью, а все-таки предпочтем указывать абсолютные пути (с помощью заполнителей {APPDIR}, {DB_DIR}, {ENV_PROGRAMFILES_X86}) и заключать их в кавычки. Место, где действительно пригодятся относительные пути, — конфигурация плагинов, не поддерживающих заполнители.

Указываем базу

В зависимости от настройки, KeePass может сразу при запуске предлагать открытие базы, которая закрывалась последней. Это удобно, когда база одна. Но если баз несколько, то зачастую KeePass будет открывать не то, что требуется.

Решить проблему можно по-разному. Можно отключить запоминание последней базы и создать триггер, открывающий нужную базу по событию «Приложение запущено и готово». Другой вариант — создать в каталоге программы файл KeePass.config.enforced.xml и зафиксировать в нем «последнюю» базу.

Содержимое файла KeePass.config.enforced.xml
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Application>
		<LastUsedFile>
			<Path>DBases\Database.kdbx</Path>
		</LastUsedFile>
	</Application>
</Configuration>

Но пожалуй, самый простой и гибкий способ — добавить путь к базе в командную строку. Поскольку наш батник Run.bat делает каталог программы рабочим, будет достаточно указать путь относительно этого каталога, и код примет такой вид:

start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx"

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

Несколько таких батников могут использоваться для разных баз.

Помимо пути к базе, можно заранее подставить и путь к ключевому файлу (если, конечно его расположение не секретно), тогда в диалоге открытия базы останется лишь ввести пароль. Это делается аргументом командной строки -preselect, батник примет вид:

start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -preselect:"K:\Database.key"

Расположение открываемой базы может быть и удаленным, причем, если соображения безопасности позволяют, можно добавить в командную строку учетные данные подключения:

start "" /d "%~dp0" KeePass.exe https://webdav.mydrive.ch/Database.kdbx -iousername:"myConnectionLogin" -iopassword:"myConnectionPassword" -ioiscomplete

Задаем конфигурацию

Предотвращаем нежелательное сохранение конфигурации

Предположим, в какой-то ситуации портативный KeePass не сможет сохранить конфигурацию. Например, не окажется доступа на запись в каталог программы. Или вы намеренно присвоите файлу KeePass.config.xml атрибут «Только чтение», чтобы не испортить настройку программы.

Некоторым сюрпризом может оказаться, что в этих случаях конфигурация все-таки сохраняется — в профиль пользователя. Пожалуй, это не совсем то, чего ожидаешь от портативного приложения...

Тем не менее, такое поведение соответствует заявленному в официальном руководстве. А чтобы предотвратить запись в профиль пользователя, нужно указать в командной строке другое расположение пользовательской конфигурации — туда изменения и сохранятся.

Будем считать, что портативному KeePass'у не положено сохранять конфигурацию никуда, кроме файла KeePass.config.xml в своем каталоге, поэтому его же и назначим пользовательской конфигурацией. Наш батник примет такой вид:

start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -cfg-local:KeePass.config.xml

Портативный KeePass, запущенный таким батником, будет работать как обычно, когда файл KeePass.config.xml в каталоге программы доступен для записи. А когда недоступен — не произойдет «странного» сохранения конфигурации в профиль пользователя.

Если вам случается открывать один KeePass из другого внутренней ссылкой вида kdbx://путь к базе, то нужно, чтобы и при таком открытии указывалась конфигурация в командной строке. Для этого можно добавить в переопределение схемы kdbx аргумент  -cfg-local:"{APPDIR}\KeePass.config.xml". Впрочем, ниже будет приведено более универсальное решение.

Отступление о конфигурациях

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

  • В enforced-конфигурации (файле KeePass.config.enforced.xml) задаются значения какой-либо части параметров, при этом они получают наивысший приоритет, многие из них запрещается менять даже на время работы программы.
  • Если enforced-конфигурация не устанавливает значение флага PreferUserConfiguration, то оно определяется global-конфигурацией (файлом KeePass.config.xml).
  • Если в результате этот флаг остается незаданным или устанавливается в false, то все остальные параметры берутся из global-конфигурации, их разрешается менять.
  • Если же этот флаг устанавливается в true, то все параметры, не заданные в enforced-конфигурации, берутся из local-конфигурации — файла, лежащего в профиле пользователя или заданного аргументом командной строки -cfg-local.

Хотя enforced-конфигурация предназначена, в основном, для администрирования, ей можно найти полезное применение и в использовании портативного KeePass'а.

Используем несколько конфигураций

Бывает удобно одновременно использовать KeePass в разных вариантах настройки. Например, один экземпляр KeePass'а может работать с учетными записями, а другой, настроенный более мягко, с закладками. В предыдущей статье предлагалось для этого поместить копию программы и некоторых плагинов в отдельный каталог. Такое решение кажется избыточным — почему бы просто не добавить дополнительную конфигурацию к той же программе?

С этим связана одна тонкость: если вы хотите запускать один и тот же портативный KeePass с разными конфигурациями, то каждый запуск нужно выполнять с аргументами командной строки. Т.е. при таком использовании невозможна «конфигурация по умолчанию», которая применялась бы в отсутствие этих аргументов.

Таким образом, для базы закладок был предпочтен вариант с отдельным экземпляром KeePass'а, чтобы не усложнять жизнь пользователя дополнительными стартерами. Однако теперь, когда мы к ним немного привыкли, попробуем все-таки добиться от одного портативного KeePass'а работы с разными конфигурациями.

Чтобы разрешить использование произвольных конфигураций, создадим в каталоге программы специальный файл KeePass.config.enforced.xml.

Содержимое файла KeePass.config.enforced.xml
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Meta>
		<PreferUserConfiguration>true</PreferUserConfiguration>
	</Meta>
</Configuration>

Теперь при каждом запуске KeePass'а будем задавать желаемую конфигурацию аргументом командной строки -cfg-local. Чтобы использовать обычную конфигурацию KeePass.config.xml, будем запускать KeePass батником, состоящим из строки:

start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -cfg-local:KeePass.config.xml

Можно добавить другие конфигурации под произвольными именами и соответствующие батники. Например, конфигурацию KeePass.config.B.xml будет применять батник вида:

start "" /d "%~dp0" KeePass.exe "DBases\Bookmarks.kdbx" -cfg-local:"KeePass.config.B.xml"

Настроенный таким образом KeePass никогда не должен запускаться без аргумента -cfg-local — иначе он сохранит конфигурацию в профиль пользователя.

Позаботимся, чтобы этот аргумент подставлялся, когда мы открываем какую-либо базу в новом окне KeePass'а ссылкой вида kdbx://путь к базе. Будем считать, что расположение конфигурации задается полем Cfg текущей записи, а если это поле отсутствует или пусто — должна использоваться конфигурация KeePass.config.xml. Чтобы это реализовать, добавим в переопределение схемы kdbx (Параметры → Интеграция → Переопределение URL) такой аргумент:

 -cfg-local:"{T-REPLACE-RX:#{S:Cfg}#^(?:\{.*)?$#{T-REPLACE-RX:!{APPDIR}{ENV_DIRSEP}KeePass.config.xml!\$!$$$$!}#}"

Переопределение схемы kdbx полностью

В случае настройки из предыдущей статьи, полный код для схемы kdbx получится таким:

cmd://{T-CONV:`"{T-REPLACE-RX:#{S:AppPath}#^(?:\{.*)?$#{T-REPLACE-RX:!{APPDIR}{ENV_DIRSEP}KeePass.exe!\$!$$$$!}#}" "{BASE:RMVSCM}" {T-REPLACE-RX:#{PASSWORD}#.+#-pw-enc:"{PASSWORD_ENC}"#} {T-REPLACE-RX:#-keyfile:"{S:KeyFile}"#^.{10}[\{\"].*##} {T-REPLACE-RX:#-iousername:"{S:ConnectionLogin}" -iopassword:"{S:ConnectionPassword}" -ioiscomplete#^.{13}[\{\"].*##} {T-REPLACE-RX:#{S:Args}#^\{.*##}`Raw`} -cfg-local:"{T-REPLACE-RX:#{S:Cfg}#^(?:\{.*)?$#{T-REPLACE-RX:!{APPDIR}{ENV_DIRSEP}KeePass.config.xml!\$!$$$$!}#}"

Если вы решите использовать таким способом готовую конфигурацию для закладок, предложенную в предыдущей статье, замените в ней все вхождения {T-REPLACE-RX::{APPDIR}:.{10}$::} на {APPDIR} и сохраните ее под именем KeePass.config.B.xml, а в записи, открывающей базу закладок, добавьте поле Cfg со значением {APPDIR}{ENV_DIRSEP}KeePass.config.B.xml и удалите поле AppPath.

Используем переменные среды

Ссылаемся на локальные ресурсы

В базе могут присутствовать различные ссылки на локальные ресурсы, например, пути запускаемых приложений. При этом одна база зачастую используется на нескольких ПК и синхронизируется между ними. Поэтому возникает задача, как сделать базу не зависящей от окружения.

Решение, предложенное в предыдущей статье — ссылаться в базе не на сами программы, а на их ярлыки, расположенные рядом с KeePass'ом. Однако это решение имеет кое-какие ограничения.

Другой подход — использование переменных среды. Эти переменные можно назначать в батнике, запускающем KeePass. Например, добавим в начало этого батника строку:

set "KeePass_VeraCrypt=c:\Program Files\VeraCrypt\VeraCrypt.exe"

Теперь в базе или в конфигурации KeePass'а можно будет вместо пути к программе VeraCrypt употреблять код %KeePass_VeraCrypt%. Таким образом, на разных ПК будет достаточно завести разные батники. А там, где используется портативная VeraCrypt, каталог которой расположен рядом с каталогом KeePass'а, подойдет батник, определяющий путь к VeraCrypt, исходя из собственного расположения:

cd /d "%~dp0.."
set "KeePass_VeraCrypt=%cd%\VeraCrypt\VeraCrypt.exe"
start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -cfg-local:KeePass.config.xml

Подобным образом можно определить в батнике несколько переменных среды и использовать их в KeePass'е. Например, зададим расположение открываемых баз (абсолютный путь), место сохранения их резервных копий и количество хранимых версий одной базы:

cd /d "%~dp0"
set "KeePass_DBDir=%cd%\DBases"
set "KeePass_BackupDir=R:\Backup\KeePassDB"
set "KeePass_BackupCount=100"
start "" /d "%~dp0" KeePass.exe "%KeePass_DBDir%\Database.kdbx" -cfg-local:KeePass.config.xml

Теперь созданные переменные можно будет использовать в триггере резервного копирования. А меняя значения этих переменных, можно будет переносить конфигурацию с этим триггером на разные ПК, в т.ч. с непортативным KeePass'ом, требующим хранить базы отдельно от программы.

Пример триггера резервного копирования
  • Событие: Сохранен файл базы данных
  • Условие: переменная окружения KeePass_DBDir равна {DB_DIR}
  • Действие: выполнить команду
    • файл: %comspec%
    • аргументы:
      /c "copy "{DB_PATH}" "%KeePass_BackupDir%\{DT_UTC_SIMPLE}UTC-{DB_NAME}" /y& for /f "skip=%KeePass_BackupCount% tokens=*" %X in ('dir "%KeePass_BackupDir%\*UTC-{DB_NAME}" /b /o:-n') do del "%KeePass_BackupDir%\%X" /q"
    • опции: ждать выхода, скрытое окно.

Если вы используете настройку, предложенную в предыдущих статьях и желаете варьировать расположение каталога с базой, замените в файлах конфигурации все вхождения {APPDIR}{ENV_DIRSEP}DBases на %KeePass_DBDir%.

Заметим, что для настройки триггеров необязательно прибегать к переменным среды, так как на разных ПК конфигурацию можно сделать разной, в отличие от синхронизируемой базы. Но переменные среды упрощают изменение настройки.

Переменные среды наследуются дочерними процессами, поэтому новое окно KeePass'а, открытое kdbx-ссылкой, будет работать с этими же значениями переменных.

Оптимизируем работу с эквивалентными доменами

Способ использования KeePass'а, предложенный в предыдущих статьях, позволяет учитывать эквивалентные домены при глобальном автонаборе. Например, чтобы на странице https://passport.yandex.ru вводились учетные данные из записи со ссылкой https://mail.yandex.by

Каждый набор эквивалентных доменов задается отдельной записью в группе domains: заголовок записи состоит из доменов, разделенных знаками |, а также начинается и оканчивается этим знаком; логин опционально содержит регулярное выражение.

Напомню, как реализована поддержка эквивалентных доменов. У каждой записи в качестве ассоциированного окна и адреса прописан код, который интерпретируется KeePass'ом как регулярное выражение, определяемое URL'ом записи. При этом непосредственно в записях указан не сам код, а ссылка на него. Благодаря этому не требуется обновлять все записи, чтобы менять этот код — достаточно редактировать лишь служебную запись <Associations>. Код хранится в ней в преобразованном виде, с экранированными знаками «{»; при обращении к нему выполняется обратное преобразование.

Однако многократные обращения к служебной записи и преобразования кода замедляют работу KeePass'а при глобальном автонаборе. Кроме того, можно заметить, что выбор кода зависит от внешней среды: от настройки браузеров, от мощности ПК. Поэтому хранение кода в базе выглядит не лучшей идеей.

Заменим ссылки на служебную запись переменными среды — тогда этот код вынесется за пределы базы и его можно будет сделать разным для разных ПК. Вместе с тем повысится быстродействие, так как из переменых среды будет поступать готовый код, не требующий обратного преобразования.

Итак, URL-ссылку записи <Associations> сохраним в файле TargetUrl.txt в подкаталоге Scripts. Двойным кликом скопируем пароль этой записи и сохраним там же в файле TargetTitle.txt. Затем в обоих файлах заменим все вхождения {{} на {.

Пример содержимого файлов

Код, помещаемый в файлы, необязательно получать через запись <Associations>, можно сформировать его непосредственно.

В этом примере разрешается соответствие адреса любым поддоменам, но с целью быстродействия не проверяется соответствие регулярному выражению. Для браузеров K-Meleon, Pale Moon, а также для любых браузеров, запущенных в песочнице Sandboxie, учитывается адрес, добавленный каким-либо расширением в конец оконного заголовка. В остальных браузерах адрес определяется лишь плагином WebAutoType.

Файл TargetUrl.txt:

//^(?i)(?:\w+\:\/\/)?(?:[\w\-\.]+\.)?(?=\w)(?:{T-REPLACE-RX:/{REF:T@T:|{T-REPLACE-RX:!{URL:HOST}!^www\.!!}|}/([^\w\s\|])/\$1/})(?:[\:\/#]\S*)?$//

Файл TargetTitle.txt:

//(?i) \W*(?:\w+\:\/\/)?(?:[\w\-\.]+\.)?(?=\w)(?:{T-REPLACE-RX:/{REF:T@T:|{T-REPLACE-RX:!{URL:HOST}!^www\.!!}|}/([^\w\s\|])/\$1/})(?:[\:\/#]\S*)?\W* (?:[^\.]*\[#\]|Pale Moon|K\-Meleon)$//

В батнике, запускающем KeePass, инициализируем переменные среды содержимым этих файлов:

cd /d "%~dp0"
set /p "KeePass_TargetUrl="<"Scripts\TargetUrl.txt"
if "%KeePass_TargetUrl%"=="" set "KeePass_TargetUrl={C:}"
set /p "KeePass_TargetTitle="<"Scripts\TargetTitle.txt"
if "%KeePass_TargetTitle%"=="" set "KeePass_TargetTitle={C:}"
start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -cfg-local:KeePass.config.xml

Теперь ассоциируем каждую запись с адресом %KeePass_TargetUrl% и заголовком %KeePass_TargetTitle%. Это можно сделать ручным редактированием или разными вариантами XML-замены (Сервис → База данных → XML-замена). Чтобы в дальнейшем новые записи имели готовые ассоциации с адресом и заголовком, будем создавать их по шаблонам.

Ручное редактирование отдельной записи

На вкладке Автонабор нужно добавить две ассоциации или изменить имеющиеся: в одной записать код %KeePass_TargetTitle% в поле Целевое окно, в другой — код %KeePass_TargetUrl% в поле Target URL.

Ассоциации для поддержки эквивалентных доменов

XML-замена ссылок на служебную запись переменными среды

Если вы пользуетесь настройкой из предыдущих статей, понадобится выполнить XML-замену, превращающую ссылки на служебную запись в переменные среды:

  • узлы: //Entry/AutoType/Association/Window
  • действие: Заменить данные
  • данные: Внутренний XML
  • найти: \{T\-REPLACE\-RX\:\/\{REF\:P@T\:&lt;Associations.*
  • заменить на: &#37;KeePass_TargetTitle&#37;
  • включить опцию Регулярные выражения.

Затем аналогично:

  • найти: \{T\-REPLACE\-RX\:\/\{REF\:A@T\:&lt;Associations.*
  • заменить на: &#37;KeePass_TargetUrl&#37;
Быстрая XML-замена

Можно одной XML-заменой обработать все записи с параметрами автонабора по умолчанию: т.е. у которых автонабор разрешен, последовательность не переопределена, усложнение отключено, ассоциаций с окнами нет.

Параметры автонабора в записях, подлежащих преобразованию

  • Узлы дерева: //Entry/AutoType
  • Действие: Заменить данные
  • Данные: Внешний XML
  • Искать:
    <AutoType>\s*<Enabled>True<\/Enabled>\s*<DataTransferObfuscation>0<\/DataTransferObfuscation>\s*<\/AutoType>
  • Заменить на:
    <AutoType><Enabled>True</Enabled><DataTransferObfuscation>1</DataTransferObfuscation><Association><Window>&#37;KeePass_TargetTitle&#37;</Window><KeystrokeSequence /></Association><Association><Window>??:URL:&#37;KeePass_TargetUrl&#37;</Window><KeystrokeSequence /></Association></AutoType>
  • опция Регулярное выражение включена.

В результате в таких записях включится усложнение и добавится поддержка эквивалентных доменов, а остальные записи останутся нетронутыми.

Выборочная XML-замена

Чтобы добавить поддержку эквивалентных доменов во все записи из определенного набора и ни в какие другие, создадим в базе группу toImprove и переместим в нее записи, подлежащие редактированию. Выполним XML-замену с параметрами:

  • Узлы дерева: //Group[Name="toImprove"]//Entry/AutoType
  • Действие: Заменить данные
  • Данные: Внешний XML
  • Искать: </AutoType>\Z
  • Заменить на:
    <Association><Window>&#37;KeePass_TargetTitle&#37;</Window><KeystrokeSequence /></Association><Association><Window>??:URL:&#37;KeePass_TargetUrl&#37;</Window><KeystrokeSequence /></Association></AutoType>
  • опция Регулярное выражение включена.

Затем расформируем группу toImprove и удалим ее.

Удаляем переменные среды

Переменные среды, предназначенные KeePass'у, могут унаследоваться браузерами и другими приложениями, которые он запустит. Можно не считать это проблемой и ничего не предпринимать, если имена и значения переменных не являются секретом.

Впрочем, в случае настройки, предложенной в предыдущей статье, и не наблюдается наследования переменных среды. Дело в том, что при этой настройке браузеры и другие приложения запускаются KeePass'ом через проводник.

Исключение — запуск по схеме cmdDirect. Если вы все-таки желаете избежать наследования переменных среды и при таком запуске, замените переопределение этой схемы (Параметры → Интеграция → Переопределение URL → cmdDirect):

cmd://%windir%\System32\wscript.exe "{APPDIR}\Scripts\RunActivate.js" /base:{T-CONV:!{BASE}!Uri!}

Также понадобится отредактировать скрипт RunActivate.js, добавив в него удаление всех переменных, имена которых начинаются на «KeePass_».

Скрипт RunActivate.js
var WshShell = WScript.CreateObject("WScript.Shell");
var FSO = WScript.CreateObject("Scripting.FileSystemObject");
var lnkDir = FSO.GetAbsolutePathName(
	FSO.GetFile(WScript.ScriptFullName).ParentFolder.ParentFolder) + "\\LNK";
var oNamedArgs = WScript.Arguments.Named;
var base = oNamedArgs.Exists("base") ? decodeURIComponent(oNamedArgs("base")) :  "";
var time = oNamedArgs.Exists("time") ? (+oNamedArgs("time")) : 0;
var win = oNamedArgs.Exists("win") ? decodeURIComponent(oNamedArgs("win")) : "";
var parsed = /^(?:(\w+)\:\/+)?((?:"([^"]*)"|([^"\s]*))(?:\s+(.*))?)$/.exec(base)
	|| new Array(6);
var scheme = (parsed[1] || "").toLowerCase();
var rmvscm = parsed[2] || "";
var app = parsed[3] || parsed[4] || "";
var args = parsed[5] || "";
if (scheme == "lnk") {
	scheme = "cmddirect";
	app = "%windir%\\explorer.exe";
	args = '"' + lnkDir + '\\' + rmvscm.replace(/"/g, '') + '.lnk"';
}
if (/\.lnk$/.test(app)) {
	var lnk = WshShell.CreateShortcut(app);
	app = lnk.TargetPath;
	args = lnk.Arguments + " " + args;
	WshShell.CurrentDirectory = lnk.WorkingDirectory || WshShell.CurrentDirectory;
}
if (scheme == "cmd") {
	var pathTempLnk = lnkDir + "\\temp.lnk";
	var tempLnk = WshShell.CreateShortcut(pathTempLnk);
	tempLnk.TargetPath = app;
	tempLnk.Arguments = args;
	tempLnk.WorkingDirectory = WshShell.CurrentDirectory;
	tempLnk.Save();
	WshShell.Run('%windir%\\explorer.exe "' + pathTempLnk + '"', 1, true);
	
	tempLnk.TargetPath = '%SystemRoot%\\System32\\cscript.exe';
	var s1020 = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
	s1020 += s1020; s1020 += s1020 + 'XXX'; s1020 += s1020; s1020 += s1020;
	tempLnk.Arguments = s1020;
	tempLnk.WorkingDirectory = '%SystemRoot%\\System32';
	tempLnk.Save();
} else if (scheme == "cmddirect") {
	
	// удаление переменных среды
	for (var env = WshShell.Environment("process"), en = new Enumerator(env);
			!en.atEnd(); en.moveNext()) {
		var aName = /^KeePass_[^\=]*/i.exec(en.item());
		aName && env.Remove(aName[0]);
	}
	
	WshShell.Run('"' + app + '" ' + args);
} else if (app) {
	WshShell.Run('%windir%\\explorer.exe ' + base, 1, true);
}
if (win) {
	WScript.Sleep(time * 0.1);
	time *= 0.9;
	while (!WshShell.AppActivate(win)) {
		if (time <= 0) {
			WScript.Quit(1);
		}
		WScript.Sleep(200);
		time -= 200;
	}
}

Открываем базу без ввода пароля

Используем командную строку

В командной строке можно передать компоненты ключа: аргументом -pw — мастер-пароль, аргументом -keyfile — ключевой файл (путь или содержимое в base64), аргументом -useraccount сообщить о шифровании учетными данными Windows. Должны быть указаны все компоненты, которыми зашифрована открываемая база.

start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -pw:"myMasterPassword" -keyfile:"K:\Database.key" -cfg-local:KeePass.config.xml

Однако передавать мастер-пароль в явном виде весьма опасно, так как аргументы командной строки легко увидеть, например, в диспетчере задач, и главное, они нередко логируются. (И само собой, недопустимо открыто хранить этот пароль в батнике.)

Относительно защищенный вариант — передавать в командной строке мастер-пароль, зашифрованный данными учетной записи Windows, как предлагалось в предыдущей статье:

start "" /d "%~dp0" KeePass.exe "DBases\Database.kdbx" -pw-enc:"зашифрованный пароль" -cfg-local:KeePass.config.xml

Напомню, что зашифровать пароль можно с помощью заполнителя {PASSWORD_ENC}.

Но теперь открытие базы сводится к доступу в учетную запись пользователя: злоумышленнику достаточно завладеть зашифрованным мастер-паролем (например, получив логи запуска программ или тот же батник) и войти в учетную запись, причем сделать это можно в разное время и в разном порядке. В частности, теряет всякий смысл блокировка базы. Кстати, об этом нужно помнить, открывая какую-либо базу в новом окне kdbx-ссылкой: такое открытие ставит ее мастер-пароль под удар. Безопаснее открывать базу в новой вкладке того же окна с помощью триггеров.

Используем стандартный поток ввода

Помимо командной строки, KeePass предоставляет еще один способ передачи мастер-пароля — через стандартный поток ввода. Этот вариант выглядит безопаснее предыдущих. Для его применения KeePass должен запускаться с аргументом -pw-stdin. Такую передачу мастер-пароля способен выполнить батник:

cd /d "%~dp0"
echo.myMasterPassword|KeePass.exe "DBases\Database.kdbx" -pw-stdin

Непонятно однако, откуда мастер-пароль возьмется в самом батнике — не хранить же его там в явном виде... Несколько спорное решение — прочитаем пароль из файла на шифрованном диске.

Предположим, перед запуском KeePass'а монтируется VeraCrypt-контейнер, например, зашифрована сама ОС. Разрешим в VeraCrypt кэширование пароля (в случае шифрованной ОС — Настройка → Шифрование системы → Кэшировать пароль дозагрузочной аутентификации). Создадим контейнер VeraCrypt минимального размера, защищенный тем же паролем, и поместим в него файл, содержащий мастер-пароль базы. Теперь будем запускать KeePass батником, который монтирует этот контейнер, считывает мастер-пароль, демонтирует, очищает кэш VeraCrypt и запускает KeePass, передавая ему мастер-пароль через стандартный поток ввода.

Скрипт Run.bat
@echo off
set "KeePass_VeraCrypt=c:\Program Files\VeraCrypt\VeraCrypt.exe"
cd /d "%~dp0"
start "" /i /wait "%KeePass_VeraCrypt%" /v "DBases\Database.pw" /l P /m ro /m rm /q /s
setlocal enableextensions enabledelayedexpansion
set /p "KeePass_MP="<"P:\Password.txt"
start "" /i "%KeePass_VeraCrypt%" /d P /f /w /q /s
endlocal & echo.%KeePass_MP%|KeePass.exe "DBases\Database.kdbx" -keyfile:"K:\Database.key" -cfg-local:KeePass.config.xml -pw-stdin

Считаем, что база Database.kdbx и криптоконтейнер Database.pw с ее паролем лежат в одном подкаталоге DBases, пароль записан в файле Password.txt в корне виртуального диска, для временного монтирования используется буква «P». Батник Run.bat устроен так, чтобы KeePass и VeraCrypt не унаследовали переменную с мастер-паролем.

Таким образом, вместо двух паролей, от шифрованного диска и от базы, будем вводить один. Если заблокировать базу, то повторно она уже не откроется батником, поскольку будет очищен кэш VeraCrypt. В случае шифрования ОС имеет смысл добавить батник в автозагрузку, чтобы очистка кэша произошла как можно скорее.

Впрочем, батник здесь неудобен, так как при таком запуске KeePass'а интерпретатор не завершается сам и приходится закрывать консольное окно вручную. Воспользуемся вместо него WSH-скриптом. Этот вид скрипта годится и для предыдущих приемов с использованием рабочего каталога, аргументов командной строки и переменных среды — все они присутствуют в коде.

Скрипт Run.js
var WshShell = WScript.CreateObject('WScript.Shell');
var ProcEnv = WshShell.Environment('process');
var FSO = WScript.CreateObject('Scripting.FileSystemObject');

/* считаем, что скрипт лежит в каталоге программы */
var keepass_dir = FSO.GetAbsolutePathName(FSO.GetFile(WScript.ScriptFullName).ParentFolder);

/* каталог программы назначается рабочим */
WshShell.CurrentDirectory = keepass_dir;

var veracrypt = 'c:\\Program Files\\VeraCrypt\\VeraCrypt.exe'; // путь к VeraCrypt
var container = 'DBases\\Database.pw'; // путь к контейнеру
var letter = 'P'; // буква для монтирования

/* переменным среды присваиваются явные значения */
ProcEnv('KeePass_DBDir') = keepass_dir + '\\DBases'; // абсолютный путь к каталогу с базами
ProcEnv('KeePass_BackupDir') = 'DBases\\BackUp'; // путь к каталогу с бэкапами
ProcEnv('KeePass_BackupCount') = '100'; // число бэкапов одной базы
ProcEnv('KeePass_VeraCrypt') = veracrypt;

/* переменным среды присваивается содержимое файлов */
setEnvVarFromFile('KeePass_TargetUrl', 'Scripts\\TargetUrl.txt');
setEnvVarFromFile('KeePass_TargetTitle', 'Scripts\\TargetTitle.txt');

try {
	WshShell.Run('"' + veracrypt + '" /v "' + container + '" /l ' + letter
		+ ' /m ro /m rm /q /s', 1, true);
	var pw = readFile(letter + ':\\Password.txt');
} finally {
	WshShell.Run('"' + veracrypt + '" /d ' + letter + ' /f /w /q /s');
}

WshShell.Exec('KeePass.exe'
	+ ' "DBases\\Database.kdbx"' // открываемая база
	+ ' -keyfile:"K:\\Database.key"' // ключевой файл (опциональная строка)
	+ ' -cfg-local:"KeePass.config.xml"' // конфигурация (опциональная строка)
	+ ' -minimize' // свернуть KeePass (опциональная строка)
	+ ' -pw-stdin'
).StdIn.WriteLine(pw);

function readFile(path) {
	try {
		var textStream = FSO.OpenTextFile(path, 1, false, 0);
		return textStream.readAll();
	} catch (e) {
		return "";
	} finally {
		textStream && textStream.close();
	}
}

function setEnvVarFromFile(var_name, path) {
	var env_val = readFile(path);
	ProcEnv(var_name) = env_val ? env_val : '{C:}';
}

Предупрежу, что каким бы способом вместо обычного набора мастер-пароль ни передавался KeePass'у, снятие дампа памяти грозит утечкой этого пароля, причем даже после блокировки базы.

Управление работающим KeePass'ом

Хотя статья посвящена параметрам запуска, в дополнение перечислим аргументы командной строки, которыми можно управлять уже запущенной программой:

  • автонабор для выбранной записи: -auto-type-selected
    (но если открыто несколько KeePass'ов, набираемые данные могут непредсказуемо перемешаться);
  • глобальный автонабор для всех работающих KeePass'ов: -auto-type
    (избежать смешения данных поможет опция Всегда показывать окно выбора записи для глобального автонабора);
  • открытие ссылки в записи с заданным идентификатором: -entry-url-open -uuid:идентификатор
    (например, в случае kdbx-ссылки эта команда откроет какую-либо базу в новом окне KeePass'а);
  • закрытие всех KeePass'ов (не принудительное): -exit-all
  • блокировка всех KeePass'ов: -lock-all
  • разблокировка всех KeePass'ов: -unlock-all

Комментарии и отзывы

Добавляя комментарий, ознакомьтесь с Правилами сообщества