---

layout: post

lang: 'ru'
date: '2024-07-27'

year: '2024'
section: 'posts'

title: 'wrapped bw'
description: 'Превращаем fully-featured Bitwarden command-line interface в удобный.'
---

# Интеграция Bitwarden CLI с&nbsp;fzf и&nbsp;буфером обмена

Менеджер паролей&nbsp;— это специальное приложение, которое помогает делать вид, что я&nbsp;помню разные пароли для разных аккаунтов, а&nbsp;не&nbsp;ввожу везде один и&nbsp;тот&nbsp;же. Мне нравится Bitwarden: открытый исходный код, возможность поднять собственный сервер, клиенты под разные устройства и&nbsp;расширения под разные браузеры.

Самым удобным, внезапно, оказался клиент для Android, который не&nbsp;заставляет меня каждый раз вводить 12+ знаков мастер-пароля (такую длину требуют Bitwarden и&nbsp;здравый смысл), а&nbsp;может быть разблокирован с&nbsp;помощью биометрии. Похожего удобства захотелось достичь и&nbsp;на&nbsp;Linux.

## Дикий CLI

На&nbsp;ноутбуке я&nbsp;использую [Bitwarden CLI](https://bitwarden.com/help/cli/). Это powerful, fully-featured tool, которым на&nbsp;практике оказалось не&nbsp;слишком удобно пользоваться, если ты&nbsp;человек.

### Ключи от&nbsp;ключей

> You are responsible for maintaining your session key.

Bitwarden CLI поддерживает [механизм сессий](https://bitwarden.com/help/cli/#using-a-session-key), который призван избавить пользователя от&nbsp;бесконечного ввода мастер-пароля. Приложение позволяет разблокировать хранилище и&nbsp;получить временный сессионный ключ, который можно либо хранить в&nbsp;беззащитной переменной окружения, либо прикладывать к&nbsp;каждому запросу вручную. 

По&nbsp;сути своей, сессионный ключ отличается от&nbsp;мастер-пароля тем, что его можно моментально деактивировать, но&nbsp;совершенно невозможно запомнить, а, значит, нужно где-то хранить. Хочется делать это удобно и&nbsp;безопасно, а&nbsp;не&nbsp;в&nbsp;общедоступной переменной окружения.

### Пароли в&nbsp;stdout

> The get command can only return one result, so&nbsp;you should use specific search terms. If&nbsp;multiple results are found, the CLI will return an&nbsp;error.

Где-то в&nbsp;этот момент чтения документации я&nbsp;окончательно начал подозревать, что официальный CLI предназначен для скриптов: всё строго, никакого автодополнения, никакого интерактивного поиска, а&nbsp;пароли лаконично вываливаются в&nbsp;стандартный вывод терминала, откуда их&nbsp;ещё нужно как-то переправить в&nbsp;место назначения.

## Приручение CLI 

Может показаться, что я&nbsp;ругаюсь, но&nbsp;отсутствие удобств и&nbsp;излишеств в&nbsp;официальном CLI&nbsp;— это хорошо:
- Отсутствие фич всегда приятнее, чем кривые фичи.
- Минимализм упрощает жизнь мейнтейнерам.
- Минимализм повышает надёжность.
- Меньше сторонних зависимостей.
- Стандартные интерфейсы идеально подходят для автоматизации.

Идея сделать Bitwarden CLI удобнее, разумеется, пришла в&nbsp;голову не&nbsp;только мне, так что на&nbsp;GitHub предсказуемо быстро нашёлся [скрипт-обёртка](https://gist.github.com/loeschzwerg/c2b9d0b50f712a026aa6454af3b58598) от&nbsp;[@loeschzwerg](https://github.com/loeschzwerg). Этот ZSH-скрипт менее требователен к&nbsp;пользователю и&nbsp;позволяет в&nbsp;случае, когда под пользовательский поисковый запрос подходит несколько аккаунтов, выбрать нужный из&nbsp;списка с&nbsp;помощью fzf и&nbsp;автоматически скопировать логин, пароль и&nbsp;даже TOTP в&nbsp;буфер обмена.

К&nbsp;сожалению, найденный скрипт никак не&nbsp;решал проблему управления сессиями, так что я&nbsp;решил его немного доработать, избавив заодно от&nbsp;избытка многоточий в&nbsp;интерфейсе.

### «Безопасное» хранение сессионного ключа

Как я&nbsp;писал выше, мне нравится подход Android-клиента: нужно один раз ввести свой невероятно длинный мастер-пароль, после чего можно разблокировать хранилище отпечатком пальца. В&nbsp;ходе непродолжительных размышлений я&nbsp;решил, что самое простое и&nbsp;надёжное подобие для приложения в&nbsp;терминале&nbsp;— один раз получить сессионный ключ и&nbsp;сохранить его в&nbsp;файл, который будет доступен для чтения только пользователю `root` и&nbsp;недоступен любым другим приложениям, запущенным от&nbsp;имени текущего пользователя.

Приятный бонус для владельцев биометрических сканеров: они отлично интегрируются с&nbsp;утилитой `sudo`.

В&nbsp;результате скрипт обогатился двумя функциями и&nbsp;одной проверкой:

```zsh
local sessionfile="$HOME/.bitwarden_session"

get_saved_sessionkey () {
  sudo touch $sessionfile
  echo $(sudo cat $sessionfile)
}

save_sessionkey () {
  local sessionkey=$1
  sudo chmod 600 $sessionfile
  sudo sh -c "echo $sessionkey > $sessionfile"
} 
```
```
local sessionkey=$(get_saved_sessionkey)

if [[ -z $sessionkey ]] ; then
  # Get and save a new session key
  sessionkey=$(bw unlock --raw)
  save_sessionkey $sessionkey
else
  echo "Using the existing session key from '$sessionfile'."
fi
```

При первом запуске сессионный ключ, полученный после ввода мастер-пароля, записывается в&nbsp;файл, который после выполнения команды `chmod 600` становится недоступен для чтения никому, кроме суперпользователя:

```
~ » ls -lah
...
-rw-------. 1 root root   89 Jul 24 22:15 .bitwarden_session
...

~ » less .bitwarden_session 
.bitwarden_session: Permission denied
```

Парольный менеджер и&nbsp;скрипт-обёртка запускаются от&nbsp;имени текущего пользователя, повышение привилегий требуется только в&nbsp;момент записи и&nbsp;чтения сессионного ключа.

Деактивировать сохранённый ключ можно с&nbsp;помощью команды `bw lock`.
К&nbsp;сожалению, я&nbsp;так и&nbsp;не&nbsp;понял, как с&nbsp;помощью утилиты `bw` можно проверить, валиден&nbsp;ли ключ, так что после деактивации придётся удалить файл `~/.bitwarden_session` вручную, иначе скрипт так и&nbsp;будет подставлять протухший сохранённый ключ, а&nbsp;`bw` будет каждый раз игнорировать его и&nbsp;настойчиво спрашивать мастер-пароль.

## Применять с&nbsp;осторожностью

Взаимодействие с&nbsp;менеджером паролей выглядит для меня теперь примерно так:

```
~ » bwc github 
[sudo] password for $USER: 
Using the existing session key from '/home/$USER/.bitwarden_session'.
Searching for 'github'...

abcdefgh-ijkl-mnop-qrst-uvwxyz123456
github.com

Username 'Username' copied to clipboard.
Press any key to copy the password...
Password copied to clipboard.
```

Финальный вариант скрипта можно найти в&nbsp;репозитории [He4eT/fuzzy-bitwarden-clipboard](https://github.com/He4eT/fuzzy-bitwarden-clipboard). 

Настоятельно рекомендую читать любой код перед тем, как запускать&nbsp;его. Особенно в&nbsp;тех случаях, когда речь идёт о&nbsp;настолько чувствительных данных.

**Важно!** На&nbsp;системах без шифрования диска все эти танцы с&nbsp;правами на&nbsp;доступ к&nbsp;файлу не&nbsp;несут никакой пользы и&nbsp;превращают затею в&nbsp;увлекательный цирк.

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

Нужно помнить, что такое упрощение жизни ведёт к&nbsp;новым рискам: теперь любой, кто знает ваш пароль для учётной записи системного пользователя и&nbsp;имеет доступ к&nbsp;компьютеру, будет также иметь доступ и&nbsp;ко&nbsp;всем паролям, сохранённым в&nbsp;Bitwarden.

Пользуйтесь с&nbsp;осторожностью и/или храните свои пароли в&nbsp;надёжных местах =)
