Metadata-Version: 2.5
Name: s-totp-client
Version: 0.3.0
Summary: TOTP-хранилище и генератор одноразовых кодов для любых сервисов: CLI и клиентская библиотека
Project-URL: Homepage, https://gitlab.com/S-kits/totpkit
Project-URL: Source, https://gitlab.com/S-kits/totpkit
Author: Dmitry Semyonov
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: keyring>=24
Requires-Dist: pyotp>=2.9
Requires-Dist: s-clikit>=0.1.5
Requires-Dist: s-librarykit>=0.7.7
Description-Content-Type: text/markdown

# totp-client — одноразовые коды (TOTP) для любых сервисов

Одно шифрованное хранилище вторых факторов на все сервисы: PyPI, GitHub,
Bitrix24, что угодно. Другие проекты берут коды из того же стора одной строкой,
не заводя собственных копий секретов.

Это **клиент**, и только клиент: библиотека плюс CLI. Фронтендов он не
содержит — Telegram-бот выдачи кодов живёт отдельным проектом
[`totp-bot`](../totp-bot), серверная часть с общим стором и журналом выдач —
[`totp-service`](../totp-service). Граница проведена намеренно: клиент
ставится в окружение каждого навыка, которому нужен код, и тащить туда
aiogram с обработчиками чужого интерфейса — плохая сделка.

## Установка

```bash
uv add s-totp-client        # как зависимость
uv run python scripts/self_check.py
```

## Быстрый старт

```bash
totp entry add --uri "otpauth://totp/PyPI:alice?secret=…&issuer=PyPI"
totp list
totp code pypi              # {"code": "366845", "seconds_left": 20}
```

Вывод — JSON по умолчанию; `--text` переключает на человекочитаемый.

## Из своего кода

```python
from totp_client import provider_for

login(username, password, totp_provider=provider_for("pypi"))
```

Провайдер отдаёт код по сигнатуре `(попытка, прошлая ошибка) -> код` и сам
разбирается с границей 30-секундного окна: ждёт ротацию, когда коду осталось
жить меньше трёх секунд, и никогда не отдаёт дважды один и тот же код — иначе
повторная попытка входа сгорает на коде, который сервис уже отверг.

## Модель хранения

Запись — это **сервис + аккаунт + иконка + группа**. Ключ строится как
`сервис` или `сервис:аккаунт` и служит тем, что вы набираете руками: пока
аккаунт один, работает короткое `totp code pypi`; когда их стало два, короткая
форма даёт ошибку со списком вариантов, а не выдаёт код наугад.

Групп по умолчанию нет — всё лежит одним плоским списком, пока группу не
задали.

Секреты пишутся в системное хранилище (keyring). Если рабочего бэкенда нет, кит
честно предупреждает и уходит в файл — проверить можно командой
`totp store status`. Длинные сторы режутся на куски: у Windows Credential
Manager есть жёсткий потолок на размер значения, и без нарезки хранилище молча
деградировало бы в открытый файл ровно тогда, когда записей стало много.

## Коды на телефоне

Кнопка в Telegram — это отдельный проект `totp-bot`: он ставит себе этот
клиент зависимостью и берёт коды тем же `provider_for`. Здесь про него только
одно: иконку сервиса и подписи кнопок в любом фронтенде задаёт **провайдер** —
плагин навыка, объявленный entry-point'ом `totpkit.providers` (имя группы
осталось прежним после переименования пакета, чтобы уже написанные плагины
продолжали находиться). Провайдер отдаёт готовые строки и ничего не знает ни
про Telegram, ни про aiogram — потому и живёт в клиенте, а не во фронтенде.

## Лицензия

MIT
