Двухфакторная защита
Одноразовые коды внутри профиля
- RFC 6238 поверх RFC 4226
- Стандарт
- 6 знаков, шаг 30 секунд
- Код
- SHA1, SHA256, SHA512
- Алгоритмы
- На вашей машине, без сети
- Где считается
Телефон не тянет полсотни
Двухфакторная защита перестала быть необязательной. Площадки, рекламные кабинеты и социальные сети просят шесть знаков при каждом входе.
С двумя аккаунтами телефон устраивает всех. С пятьюдесятью он становится самой долгой частью дня: разблокировать, найти нужную запись среди полусотни похожих, прочитать цифры, успеть их вписать.
Что меняется с ключом внутри профиля
Сам ключ, из которого берутся эти цифры, и так лежит рядом с аккаунтом: в таблице, в заметке, в общем хранилище паролей. ARMANOS переносит его на шаг ближе, в тот профиль, который этим аккаунтом и пользуется.
Второе устройство не нужно
Код появляется в том же окне, где живёт профиль.
Не надо искать нужную запись
Ключ принадлежит профилю, сопоставлять по названию нечего.
Не надо спешно перепечатывать
Код вы копируете кнопкой, а в форму его впишет сценарий.
В сеть ничего не уходит
Программа делает код из ключа прямо на этом компьютере.
Куда ложится ключ
Откройте меню на карточке профиля и выберите «Одноразовый код». Если ключа ещё нет, окно попросит его вместо того, чтобы показывать цифры.
Вставить можно любой вид: голый ключ, который сайт печатает рядом с картинкой QR, или целую строку otpauth://, зашитую в саму картинку. Из строки программа читает издателя, имя аккаунта, число знаков, шаг и алгоритм, поэтому необычный сайт лучше вставлять строкой.
Четыре шага до первого кода
- 1
Откройте меню профиля
«Одноразовый код» стоит в том же меню, что «Отпечаток» и «Данные для входа».
- 2
Вставьте ключ
JBSWY3DPEHPK3PXP или otpauth://totp/... Пробелы, дефисы, нижний регистр и знаки = не мешают.
- 3
Сохраните
Негодный ключ программа вернёт ошибкой, и на диск ничего не ляжет.
- 4
Посмотрите на карточку
На профиле появляется отметка 2FA: сразу видно, каким аккаунтам телефон уже не нужен.
Как получается код
Расчёт идёт по RFC 6238 поверх RFC 4226, по тому же стандарту, что и приложение в телефоне. Текущее время делится на шаг, полученный счётчик идёт через HMAC с вашим ключом, и оттуда режутся те самые знаки, которые просит форма входа.
Счётчик уходит в восемь байтов двумя половинами, как и требует стандарт, поэтому короткая четырёхбайтовая запись нас не подведёт. Сходятся все шесть эталонов, дальний из них на t=20000000000.
Ничего никуда не уходит: ключ остаётся у вас в файле, а считает код сама программа, поэтому он появится и при полностью отключённой сети.
| Настройка | По умолчанию | Что принимается |
|---|---|---|
| Число знаков | 6 | 6, 7 или 8, если так сказано в строке otpauth |
| Шаг | 30 секунд | от 1 до 300 секунд из той же строки |
| Алгоритм | HMAC-SHA1 | SHA1, SHA256 и SHA512 |
| Вид ключа | base32 | пробелы, дефисы, нижний регистр и знаки = |
Что видно в окне
Код стоит крупно посередине и разбит по три знака: «482 913» глазами переносится в форму легче, чем «482913». Кнопка копирования кладёт его в буфер обмена уже без пробела.
Полоска под кодом убывает вместе с окном, а последние пять секунд отмечены отдельно, чтобы никто не начинал печатать код, который вот-вот сменится.
Строка выше называет издателя и имя аккаунта, прочитанные из строки. Именно она подтверждает, что код относится к нужному аккаунту, когда профиль один из пятидесяти.
Скрипт спрашивает код
В программе есть локальный API по HTTP для программ на этом же компьютере. Он выключен, пока вы его не включите, слушает только петлевой адрес, и токен несёт каждый вызов, кроме одного: состояние интерфейса спрашивается без него.
Одним вызовом вы называете профиль и получаете текущий код с остатком секунд. Ради этого он и нужен: скрипту, который входит в аккаунт, второй шаг требуется ровно в тот миг, когда форма его просит, а не за полминуты до.
ИИ-помощник ходит по тому же адресу через встроенный сервер MCP, под тем же токеном и с теми же отказами.
- Вызов
- GET /api/v1/profile/code?profileId=p-42
- Токен
- параметр token, заголовок x-api-token или Authorization: Bearer
- Ответ
- { "code": 0, "data": { "code": "482913", "secondsRemaining": 17, "issuer": "Shop" } }
- У профиля нет ключа
- code -1, msg no_2fa_key
- Токена нет или он не тот
- HTTP 401
- Запрос пришёл со страницы
- Отказ, каким бы ни был токен
Ноль это состояние ответа, общее для всех вызовов. Сами шесть знаков лежат в data.code.

Сценарий вписывает код сам
На экране «Сценарии» любое текстовое поле шага принимает {{profile.totp}}. Поставьте это в шаг ввода, нацеленный на поле кода, и сценарий заполнит его наравне с остальной формой.
Переменная здесь не запомненное значение, а свежий расчёт. Код, взятый в начале прогона, к третьему шагу был бы уже просрочен, поэтому профиль называет его ровно в тот миг, когда сценарий его вписывает.
В журнал шагов код не попадает: вместо значения из переменной там стоят четыре точки. Сценарий щёлкает в поле, стирает старое сочетанием клавиш и вводит код целиком, одним настоящим вводом. Если форма ждёт нажатий по буквам, поставьте код в шаг «Набрать как человек».
Ключ остаётся на компьютере
Ключ лежит в profiles.json в папке данных программы, рядом с остальными настройками профиля. Обрыв питания не порвёт его пополам: на месте останется либо целый старый файл, либо целый новый.
У файла стоят права «только хозяин», и они уезжают вместе с ним в резервную копию или в облачную папку. На Windows они не значат ничего, и файл там бережёт сама папка пользователя, куда другие учётные записи без прав администратора не заходят.
Куда ключ уезжает, вы решаете каждым действием отдельно. Копия профиля его не берёт: копию заводят под другой аккаунт.
На диске ключ не зашифрован
Полсотни ключей из таблицы
Столбец с ключом программа узнаёт по названию, английскому и русскому одинаково, так что готовую таблицу обычно переименовывать не нужно.
Ни один профиль не заведётся, пока вы не увидели, какой столбец каким полем стал. Строки с негодным ключом помечены ещё до импорта, и одной отметкой вы их пропустите, а не заведёте профиль со сломанным ключом.
При восстановлении из выгрузки вместе с ключом едут число знаков, шаг и алгоритм. Без них восьмизначный ключ или ключ с шагом в минуту стал бы обычным, и аккаунт просто перестал бы вас пускать.
Чего это не делает
- Это не хранилище паролей. Один ключ на профиль, без общего сейфа, без поиска по ключам и без места для запасных кодов, которые выдаёт сайт.
- На диске ключ лежит незашифрованным. На macOS и Linux его закрывают права на файл, на Windows только папка пользователя.
- Потерянный ключ потерян. На сервер он не уходит, и восстановить его по выданным кодам программа не может.
- Картинок программа не читает. Вы вставляете текст ключа или строку otpauth://, а снимок QR или экран телефона она не разбирает.
- Код идёт по часам этого компьютера. Если часы уехали, сайт код не примет, и программа об этой причине не предупредит.
Как проверить
За каждым утверждением выше стоит файл, а у большинства ещё и стенд, который падает, когда утверждение перестаёт быть правдой.
- Коды сходятся со всеми шестью эталонными векторами RFC 6238, включая самый дальний
- apps/desktop/src/lib/totp.js · apps/desktop/test/totp.js
- Файл с ключом пишется правами «только хозяин», а оставшиеся открытыми файлы закрываются при запуске
- apps/desktop/src/lib/secureFile.js · apps/desktop/test/secrets-on-disk.js
- Код отдаётся только по токену и никогда веб-странице
- apps/desktop/src/lib/local-api.js · apps/desktop/test/local-api-gate.js
- Сценарий считает код в момент подстановки
- apps/desktop/src/main/main.js · apps/web/test/страница-возможностей.js
- Восстановленный профиль сохраняет число знаков, шаг и алгоритм
- apps/desktop/src/main/main.js · apps/desktop/test/config-import-2fa.js
Вопросы
- Это тот же второй шаг, что при входе в ARMANOS?
- Нет. Этот ключ принадлежит аккаунту, в который заходит профиль, а второй шаг входа в вашу собственную учётную запись ARMANOS живёт на сервере и с запасными кодами.
- А если сайт выдаёт 8 знаков или шаг в 60 секунд?
- Вставьте целую строку otpauth://, она несёт эти настройки сама. У голого ключа их нет, поэтому программа берёт привычные значения, а строку, считающую входы вместо секунд, не принимает вовсе.
- Может ли страница из сети прочитать мой код?
- Нет. Вызов, похожий на пришедший со страницы, программа отклонит при любом токене: его выдают заголовок Origin, значение Sec-Fetch-Site, отличное от none, или чужой адрес узла.
- Уезжает ли ключ на вторую машину?
- Войдя на другой машине, вы ключа там не найдёте: на сервере такого поля попросту нет. Привезёт его только перенос профиля, под вашим паролем, а экспорт профилей вырезает секреты, пока вы не нажмёте «Включить секреты», и из отчёта о проблеме ключ вырезан всегда.
- Что происходит при замене и удалении ключа?
- «Заменить ключ» ставит новый: так делают после повторной привязки аккаунта. «Удалить» сначала спрашивает, а в журнале правок остаётся только сам факт замены, без значения.
- Можно раздать ключи уже готовым профилям?
- По одному, в окне профиля. Отдельного действия для всех сразу нет: полсотни ключей приезжают столбцом таблицы в тот момент, когда вы создаёте профили.
Что читать дальше
Профили
У каждого аккаунта свой браузер: куки, хранилище, отпечаток и прокси.
Локальный API
Тот самый вызов, который отдаёт код скрипту, и токен, который его стережёт.
Сборщик сценариев
Куда ставится {{profile.totp}}, чтобы код попал в форму входа.
Импорт из таблицы
Имена, прокси и ключи 2FA приезжают из готовой таблицы.
Пусть ключ лежит там, где живёт аккаунт
В ARMANOS добавьте ключ одному профилю и увидите код в том же окне.