access v0.2.2 [core]


Единый владелец ADMIN_IDS, операций над правами и привязок мессенджер<->web (сидинг, таргеты, identity).

README

# access

Единый владелец ID администраторов, операций над правами и привязок мессенджер<->web (сидинг, таргеты, identity). Все модули спрашивают «кто админ и у кого какое право» только здесь.

Тип: Модуль. Категория: `core`. Зависимостей нет.

## Описание

- Держит список TG-администраторов и отдаёт его через API. Файл прав принадлежит ядру: чтение — живое, без кешей, запись — атомарно через сервис.
- При старте делает сидинг: выдаёт админам из `ADMIN_IDS` положенные права и вычищает мусор (ключи `telegram:*`, которых нет в списке, — кроме привязанных к web-аккаунтам). Ручные правки файла прав при живом боте сид перезапишет.
- Считает получателей рассылок: кому слать уведомление с конкретным правом, включая флаг «без звука».
- Умеет добавлять/убирать админа: правит `.env` и сразу просидирует права.
- Владеет привязками мессенджер<->web (`identity_links.json`; один TG-qid — один uid, один uid — много qid). Коды одноразовые, персистентные (`identity_codes.json`, TTL 10 мин), два вектора: кабинет→бот (`link_code` → `/link`) и бот→кабинет (`/bind` → `link_tg_consume`). Перебор кодов ограничен rate-limit.
- Наследование прав (3a, `IDENTITY_UNIFIED_RIGHTS=union`, только opt-in + согласие `inherit` на каждой связке): привязанный TG видит web-права своего uid; `all` не наследуется никогда.
- Волшебный вход (3b, `MAGIC_LOGIN=1`): ticket из привязанной лички ТГ (`/weblogin`) → одноразовая cookie-сессия через `GET /api/auth/magic`; TTL 5 мин, хранится только хеш, вход уведомляется в личку.

## Возможности

- `access.admin_ids {}` → TG id администраторов, единственный источник списка
- `access.is_admin {uid}` → входит ли пользователь в `ADMIN_IDS`
- `access.get_right {uid, key}` → живое значение права (с учётом union)
- `access.toggle_right {key: 'ns:id', right}` → переключить право, вернуть новое значение
- `access.notify_targets {right}` → получатели рассылки с этим правом `(chat_id, no_sound)`
- `access.seed {}` → прогнать сидинг вручную (синхронизация с `ADMIN_IDS` + чистка чужих `telegram:*`, привязанные не трогает)
- `access.add_admin {uid}` → добавить TG-админа (дописать в `.env` + сид)
- `access.remove_admin {uid}` → убрать TG-админа (из `.env` и из прав)
- `access.link_code {uid}` → код привязки web->tg (10 мин)
- `access.link_consume {code, qid}` → погасить код из `/link`
- `access.linked_uid {qid}` → web-uid связки
- `access.linked_telegram {uid}` → первый qid (legacy)
- `access.linked_telegrams {uid}` → все qid связки
- `access.canonical_owner {qid}` → канонический владелец пользовательских данных: привязан — `web:<uid>` (общий раздел связки), иначе — сам qid (раздельные данные)
- `access.link_tg_code {qid}` → код привязки tg->web (для `/bind`)
- `access.link_tg_consume {code, uid}` → погасить tg-код в кабинете
- `access.link_set_inherit {qid, flag}` → согласие на наследование (union)
- `access.link_list {}` → все связки (для админки)
- `access.link_admin {uid, qid}` → админская связка пары (минуя коды)
- `access.unlink {qid}` / `access.unlink_uid {uid}` → снять связку(и)
- `access.effective_can {qid, right}` → право TG с учётом union
- `access.magic_issue {uid, qid}` → ticket волшебного входа
- `access.magic_consume {ticket}` → погасить ticket (одноразово)

## Конфигурация (`config.schema.json`)

- Обязательных нет.
- Опциональные:
  - `ADMIN_IDS` = `123456789,987654321` — TG id администраторов через запятую
  - `IDENTITY_LINKS_FILE` = `` — файл связок (дефолт `data/identity_links.json`)
  - `IDENTITY_CODES_FILE` = `` — файл кодов (дефолт `data/identity_codes.json`)
  - `IDENTITY_UNIFIED_RIGHTS` = `off` — `union` включает наследование web-прав в TG
  - `MAGIC_LOGIN` = `0` — `1` включает волшебный вход `/weblogin`

Манифест

{
  "name": "access",
  "version": "0.2.2",
  "category": "core",
  "description": "Единый владелец ADMIN_IDS, операций над правами и привязок мессенджер<->web (сидинг, таргеты, identity).",
  "requires": [],
  "rights": [],
  "api_methods": [],
  "web_routes": [],
  "commit": "41ba0ab3e578a818feded3517457663f4d7a4872",
  "updated": "2026-10-27 21:50:14 +0300",
  "history": [
    {
      "version": "0.1.0",
      "date": "2026-09-08 10:45:06 +0300",
      "commit": "f1448e3d04bf1545e84324132cf3a70ca08cacb9"
    },
    {
      "version": "0.2.0",
      "date": "2026-10-07 22:46:22 +0300",
      "commit": "30231374bb58d56272c7cdc2261989af7146d3a9"
    },
    {
      "version": "0.2.1",
      "date": "2026-10-07 23:19:08 +0300",
      "commit": "7c17fbe1539928163b0b7a7be0f6e2005f699dcd"
    },
    {
      "version": "0.2.2",
      "date": "2026-10-27 21:50:14 +0300",
      "commit": "41ba0ab3e578a818feded3517457663f4d7a4872"
    }
  ],
  "integrity": "sha256:4a69008fa235a52ccef334dd371f5bd14f70ce8275de9e47930f55d5130e803f",
  "files": "[5 файлов — см. вкладки ниже]",
  "note": "",
  "wdesc": "",
  "wbody": "",
  "_extra": {
    "api": "",
    "events_emitted": "[]",
    "events_subscribed": "[]",
    "config_schema": "config.schema.json",
    "env_example": ".env.example"
  }
}

Файлы и исходники

Дерево файлов

  • · корень
    • 5.3 КБ
    • 0.2 КБ
    • 27.9 КБ
    • 5.0 КБ
    • 4.3 КБ

Предпросмотр

Выберите файл в дереве выше — код откроется здесь.

История версий

versiondatecommit
0.2.22026-10-2741ba0ab3e578
0.2.12026-10-077c17fbe15399
0.2.02026-10-0730231374bb58
0.1.02026-09-08f1448e3d04bf