Преминете към основното съдържание

API на Matrix

Уеб приложението на Matrix е обикновен клиент на REST API под /api/v1. Всичко, което прави приложението, можете да направите и чрез API. Пълният справочник на крайните точки е справочникът на API на Matrix, генериран от entrosity-matrix.backend/api/openapi.yaml – спецификацията, от която се генерират маршрутизаторът и валидирането на заявките на сървъра (и TypeScript типовете на приложението).

Конвенции​

  • Базов URL: https://hub.entrosity.com/matrix/api/v1 (проксито премахва /matrix). API на конектора е под /matrix/api/connector/v1 (Протокол на конектора на Matrix).
  • Удостоверяване: Authorization: Bearer <product token> – петминутен токен от Entrosity Hub за продукта matrix (POST /api/platform/v1/auth/product-token {"product":"matrix"} със сесията в Hub, API на Hub). Matrix няма собствено влизане; потребителите, тенантите и ролите идват от Hub. Докато Matrix е в бета версия, Hub издава токените му само на администраторите на платформата.
  • Правила за достъп: всеки маршрут има правило в entrosity-matrix.backend/internal/http/portal/access.go: публичен, влязъл потребител, глобален администратор или право в тенанта (Роли и права). Потребителите на тенант могат да извикват само /tenants/{id на техния тенант}/…; всеки друг тенант връща 404. Липсващо право връща 403. Маршрутите за промяна (състояние на зала, групово състояние, отмяна на график, промяна на адрес, създаване и повторен опит, промяна на списък с разрешени сайтове) изискват в маршрутизатора само rooms:read / addresses:read: обработчикът проверява rooms:operate заедно с правата по зали на учителя, addresses:manage или allowed_sites:manage, така че отказаният опит да бъде записан в историята, преди да се върне 403.
  • Учителите виждат само своите зали: за учител GET /rooms, разрешените сайтове, адресните групи, графиците, историята и потокът от събития пропускат всяка зала, която не му е предоставена (и защитните стени без нито една от неговите зали); задача, групово действие, адресна група или операция на такава зала, както и разрешените сайтове или адресните групи на такава защитна стена, връщат 404, а промяна на такава зала връща 404 unknown_room (записва се като отказана), точно както несъществуваща зала. Наблюдателите и администраторите виждат всички зали (entrosity-matrix.backend/internal/visibility).
  • JSON тела с ключове в snake_case, най-много 1 MB. Схемите на заявките отказват непознати полета (422).
  • Списъци: одитните журнали и администраторският списък с тенанти приемат ?page=&page_size= (по подразбиране 50, най-много 200) и връщат items, page, page_size и total. Историята използва курсор (История). Другите списъци връщат всички елементи.
  • Ограничения на заявките: 20 заявки в секунда за IP адрес на клиент, пик 60 (MATRIX_API_RATE_PER_SECOND, MATRIX_API_RATE_BURST); над това 429 без код. Промените се броят и към ограниченията от 10 на потребител и 30 на тенант в минута (429 rate_limited, записва се като отказана).
  • Всеки отговор съдържа X-Request-ID.

Грешки​

Грешките са RFC 7807 application/problem+json със стабилен code:

{
"type": "/problems/snapshot_stale",
"title": "Conflict",
"status": 409,
"code": "snapshot_stale",
"detail": "the firewall's state is out of date; wait for the next report",
"request_id": "…"
}

Грешките при валидиране имат code: "validation" и fields със съобщение за всяко поле (например policy_pattern без (?P<room>…), reenable_at извън интервала от 5 минути до 7 дни, reenable_at с enable). Най-честите:

КодКога
unknown_room (404)Учител превключва зала, която не му е предоставена, или несъществуваща зала (при групова промяна: която и да е от залите; нищо не се изпраща).
forbidden (403)Ролята няма правото (зрител превключва, учител променя адрес).
snapshot_stale (409)Залите на защитната стена са неактуални (Зали → Неактуални данни).
connector_offline (409)Конекторът на защитната стена не е свързан.
writes_disabled (409)writes_enabled (зали), address_writes_enabled (адреси) или site_writes_enabled (разрешени сайтове) на защитната стена е изключено.
busy (409)Промяна на залата (или адресна промяна на защитната стена) все още е в ход.
unknown_room (409)Защитната стена не отчита залата.
conflict (409)Адреси: групата се е променила след group_version или IP адресът – след expected_ip. Разрешени сайтове: списъкът се е променил след list_version.
rate_limited (429)Ограничения на промените.

Всички кодове: Кодове на грешки.

Защитни стени​

POST /tenants/{tenantID}/firewalls добавя защитна стена зад един от конекторите на тенанта; PATCH я променя, а DELETE я премахва. Всяка промяна изпраща конфигурацията на конектора (matrix.firewall.apply, протокол). По подразбиране writes_enabled, address_writes_enabled и site_writes_enabled са false, verify_tls е true, port е 443, vdom е root, а report_interval_s е 30. Firewall има и sites_supported (само за четене: конекторът ѝ е обявил възможността sites). services_enabled (премахнатите услуги на Entrosity) вече не е част от API: заявка, която го изпраща, се отказва (422).

API ключът на FortiGate е само за запис: token в заявката за създаване или PUT /tenants/{tenantID}/firewalls/{firewallID}/token {"token": "…"} (204). Той никога не се връща; съхраняването му увеличава credentials_version и прилага отново защитната стена.

POST …/check (202, Job) изпълнява проверката само за четене; result на задачата е CheckResult (version, direction_ok, rooms, groups, members, warnings, guard_state, policy_names, а от конектори, които поддържат разрешени сайтове, и sites). POST …/refresh {"scope": "rooms" | "addresses" | "all"} прочита защитната стена веднага.

Превключване на зали​

GET /tenants/{tenantID}/rooms[?firewall_id=] връща firewalls (със stale, updated_at, error, error_code, simulated, guard_state, writes_enabled, site_writes_enabled, sites_supported, shared_allowed_sites: домейните от списъка за всички зали) и rooms (със status, present, can_manage за извикващия, busy_job_id, schedule, last_change и allowed_sites: домейните от собствения списък на залата, 0, когато няма такъв).

POST /tenants/{tenantID}/firewalls/{firewallID}/rooms/SB1-102/status
{"status": "disable", "reenable_at": "2026-10-01T14:00:00Z"}

връща 202 с {change, job}: реда в историята (резултат pending) и задачата matrix.policy.set. Резултатът пристига асинхронно:

  1. следете job.update и matrix.change в потока на живо или проверявайте GET /tenants/{tenantID}/jobs/{jobID};
  2. result на промяната става success, unconfirmed, denied или error (Промени и резултати), с detail (кода на грешката) за последните три;
  3. result на задачата съдържа PolicySetResult на конектора (previous, status, wrote, confirmed).

Правила: reenable_at само с disable, от 5 минути до 7 дни напред; то създава график за включване. Всяка по-нова промяна на залата отменя чакащия ѝ график. Отказана заявка също записва промяна denied.

Групово: POST …/firewalls/{firewallID}/bulk-status {"status", "rooms": […] | "building": "SB1", "reenable_at"?} връща {bulk: {id, items: [{room, change_id, job_id, error?}]}}; залите с промяна в ход се пропускат (error: "busy"). GET /tenants/{tenantID}/bulk-actions/{bulkID} показва резултата за всяка зала.

Графици: GET /tenants/{tenantID}/schedules[?status=], POST …/schedules/{scheduleID}/cancel (само pending; иначе 409 schedule_not_pending).

Адресни операции​

POST /tenants/{tenantID}/firewalls/{firewallID}/addresses/update
{"policy_id": 102, "group": "SB1-102-Students address", "name": "pc-102-01.coding.local",
"ip": "192.0.2.21", "expected_ip": "192.0.2.11", "group_version": "<64 hex>",
"request_id": "<uuid>"}

…/addresses/create приема същите полета без expected_ip. И двете изискват addresses:manage и връщат 202 с {operation, job, change}.

  • request_id (UUID, генериран от клиента) прави заявката идемпотентна: повторното ѝ изпращане връща същата операция; request_id_reused, когато принадлежи на друга операция.
  • group_version е version на групата от GET …/address-groups/detail?policy_id=&group=, което връща и незавършените операции на извикващия.
  • stage на операцията следва дневника на конектора (prepared, update_sent, create_sent, created, member_sent, done), а result ѝ – този на промяната.
  • POST /tenants/{tenantID}/address-operations/{operationID}/retry {"group_version": "…"} продължава прекъсната операция: само от автора ѝ и само когато е retryable (запис е започнал и тя не е приключила; иначе 409 not_retryable).

Разрешени сайтове​

GET /tenants/{tenantID}/firewalls/{firewallID}/allowed-sites

(rooms:read) връща AllowedSitesView:

  • firewall: stale, updated_at (кога списъците са прочетени последно), connector_online, enabled, guard_state, site_writes_enabled, sites_supported;
  • shared и rooms (всяка налична зала, подредени като на страницата със залите): AllowedSitesList с list (shared или кодът на залата), room, building, group, exists, policy ({policy_id, name, status, covers}), setup (ok, group_missing, policy_missing, policy_disabled, policy_not_covering или unknown, когато конекторът не е изпратил списъците), version, editable и reason, domains (SiteEntry {domain, object, owned, editable, reason}), can_edit (за извикващия), busy_job_id и last_change;
  • can_setup: извикващият може да получи командите за настройка.
PUT /tenants/{tenantID}/firewalls/{firewallID}/allowed-sites/SB1-102
{"domains": ["classroom.google.com", "*.moodle.example.org"], "list_version": "<64 hex>"}

{list} е shared или код на зала. domains е пълното желано множество от домейни, управлявани от Matrix (с малки букви, сортирани, без повторения; най-много 200); list_version е version на списъка. Общият списък изисква allowed_sites:manage (администратори на тенанта); списък на зала приема и учител с rooms:operate и право за залата. Отговорът е 202 с {change, job}: промяната sites и задачата matrix.sites.set, чийто резултат пристига като при превключване на зала (success, unconfirmed, denied, error; result на задачата е SitesSetResult с added, removed, wrote и confirmed). Откази, всеки записан като промяна denied:

КодКога
forbidden (403)Общият списък от потребител, който не е администратор, или наблюдател.
unknown_room (404)Учител без право за залата.
group_read_only (403)Matrix не може да променя групата във FortiGate (подробностите казват защо).
unknown_room (409)Залата не е налична зала на защитната стена.
invalid_domain (422)Домейн не е валиден (fields.domains казва кой) или са повече от 200.
connector_offline (409)Конекторът е офлайн.
connector_outdated (409)Конекторът не поддържа разрешени сайтове (няма възможността sites).
snapshot_stale (409)Данните от защитната стена са неактуални или списъците никога не са изпращани.
writes_disabled (409)site_writes_enabled на защитната стена е изключено.
sites_not_set_up (409)Групата на списъка или нейното ACCEPT правило липсва.
conflict (409)list_version не е текущата версия на списъка.
busy (409)Друга промяна на този списък все още се изпълнява.
rate_limited (429)Ограниченията на промените (запазването се брои като превключване на зала).
GET /tenants/{tenantID}/firewalls/{firewallID}/allowed-sites/setup-cli?rooms=SB1-102,SB1-108

(allowed_sites:manage) връща {cli, lists, warnings}: командите за FortiOS, които създават липсващото от общия списък и списъците на посочените зали (празно, когато нищо не липсва), списъците, които настройват (shared, кодове на зали), и проблемите, които не могат да оправят (Настройка на FortiGate).

Права по зали​

GET /tenants/{tenantID}/room-grants[?user_id=] (администраторите на тенанта виждат правата на всички, останалите – своите); PUT /tenants/{tenantID}/users/{userID}/room-grants {"firewall_id", "rooms": […]} заменя залите на учител в една защитна стена (grants:manage; 422 not_teacher за всеки, който не е учител в тенанта). Добавяните зали трябва да се отчитат от защитната стена; премахването е винаги възможно. Записва се като промяна grants.

История​

GET /tenants/{tenantID}/history връща промените от най-новите, с филтрите from, to, user_id, room (част от код на зала, без значение на главни и малки букви), kind (policy, address_update, address_create, grants, schedule, bulk, sites, а services за стари записи) и firewall_id, и limit (1–200, по подразбиране 50). Когато има още, страницата съдържа next_cursor: подайте го като cursor. Всяка промяна има source (matrix или stop-internet за прехвърлените редове) и metadata.steps (упълномощаванията в момента на запис и етапите на адресите и сайтовете).

Промените sites имат room (празно за общия списък), group_name, previous и desired (обобщения като 3 domains) и metadata {list, domains, added, removed, previous_domains} (при отказ: {list, requested}). Промените services са само история отпреди премахването на услугите на Entrosity: някогашният превключвател (previous / desired enable или disable) или системно синхронизиране на групата; нови не се правят.

Обновления на живо​

GET /tenants/{tenantID}/stream е text/event-stream. Браузърите се удостоверяват с ?sse_token= от POST /auth/sse-token {"tenant_id": "…"} (валиден 60 секунди; така токенът за достъп не попада в адреси). Събития:

СъбитиеДанниЗначение
matrix.rooms{firewall_id}Заредете отново залите (пристигнал е отчет, зала се е променила, защитната стена е станала неактуална или отново актуална).
matrix.addresses{firewall_id}Заредете отново адресните групи.
matrix.sites{firewall_id}Заредете отново разрешените сайтове (отчет с нови списъци, изпратена или завършена промяна).
matrix.changeпромянатаПромяна е приключила.
job.updateзадачатаСъстоянието или резултатът на задача се е променил.
connector.statusконекторътКонектор е станал онлайн или офлайн.

Инсталатори на конектора​

GET /tenants/{tenantID}/connector-release (администратори на тенанта) връща най-новото издание от канала за обновявания с връзка за изтегляне, валидна един час, или 404, когато няма съхранено издание. Глобалните администратори виждат всички съхранени издания в GET /admin/connector-releases. CI качва изданията в /api/releases/v1/connector (Работа с Entrosity Matrix → Издания на конектора).

Чувствителни действия​

Окончателното изтриване на токен за регистриране (глобални администратори) изисква step-up токен от Hub срещу паролата на извикващия (POST /api/platform/v1/auth/step-up, продукт matrix), изпратен като step_up_token към POST /tenants/{tenantID}/enrollment-tokens/{tokenID}/delete. API ключовете на FortiGate никога не се връщат от нито една крайна точка, а всяко изтегляне от конектор се записва в одитния журнал (firewall.credentials_fetch). Всяка приета промяна на разрешени сайтове се записва в одитния журнал като allowed_sites.set (ресурс: защитната стена).

Вътрешен API (Entrosity Axis)​

Стената с екрани на Entrosity Axis чете залите на отделен слушател, MATRIX_INTERNAL_ADDR (:8086), който никога не се публикува. Всяка заявка изисква Authorization: Bearer <MATRIX_AXIS_TOKEN> (иначе 401; без токена слушателят е изключен).

GET /internal/v1/screen-rooms?tenant=<id>&all=true връща всички зали от включените защитни стени на тенанта; ?tenant=<id>&user=<id> — само залите, дадени на този потребител като активен учител на активен тенант (нищо за другите роли). Идентификаторите са тези от Hub. Всяка зала има room, building, building_name, firewall_id, firewall_name и computers: имената на /32 членовете на адресните групи на залата от последния отчет на защитната стена. Договорът е proto/matrix.ScreenRooms в entrosity-shared-go.