Skip to content

fix(mgr): токен в ms3.config — гонка HTTP_MODAUTH на Ext-less Vue-страницах (#544) - #545

Merged
biz87 merged 2 commits into
betafrom
fix/544-mgr-token-race
Aug 12, 2026
Merged

fix(mgr): токен в ms3.config — гонка HTTP_MODAUTH на Ext-less Vue-страницах (#544)#545
biz87 merged 2 commits into
betafrom
fix/544-mgr-token-race

Conversation

@biz87

@biz87 biz87 commented Aug 12, 2026

Copy link
Copy Markdown
Member

Fixes #544

Проблема

На Ext-less Vue-страницах админки (после #533/#534/#536/#537) периодически падали config-запросы с «Доступ запрещён» — заметнее всего на Заказах: orders/filters и grid-config/orders в консоли, при этом сессия жива и список заказов грузится.

Причина

getModAuthToken() брал токен только из браузерного глобала MODx.siteId. Стартовый Promise.all([loadFilters, loadGridConfig]) уходит на DOMContentLoaded раньше, чем менеджерский JS выставит MODx.siteId → запросы уходят без HTTP_MODAUTH → MODX-коннектор отклоняет их (HTTP 200, тело {success:false, message:"Доступ запрещён.", object:{code:401}}). Список уходит чуть позже, токен уже есть → 200. Отсюда интермиттентность. #533 обнажил гонку, убрав waitForElement.

Диагностика по Network подтвердила: у упавшего orders/filters в Payload только action+route (нет HTTP_MODAUTH), а тело — code:401.

Решение

Отдать токен синхронно в inline-ms3.config, до старта Vue-модуля:

  • manager.class.php — новый хелпер addVueConfig(): кладёт token = $modx->user->getUserToken($contextKey) в конфиг и эмитит <script>var ms3 = { config }</script>;
  • customers / notifications / order / orders / settings / utilities$this->addHtml('var ms3…')$this->addVueConfig($config);
  • request.js getModAuthToken() — читать сперва ms3.config.token, фолбэк на MODx.siteId.

Токен присутствует в первом же inline-теге → гонки нет by construction. Покрыты все 6 Ext-less страниц. Права/сессия не затронуты.

Проверка

  • php -l ×7 ✓, ESLint ✓, npm run build ✓ (PHPStan не применим — controllers/ вне анализа).
  • На DEV после hard-reload: все страницы MiniShop без ошибок в консоли; ранее падавшие запросы теперь success:true с HTTP_MODAUTH в URL. Подтверждено на нескольких перезагрузках (гонка была интермиттентной).

…#544)

Ext-less Vue manager pages fire their first API requests on DOMContentLoaded,
before the manager JS populates the MODx.siteId global that request.js used as
HTTP_MODAUTH. Those early requests went out tokenless, so the connector rejected
them (HTTP 200 body {success:false, message:"Доступ запрещён.", object:{code:401}}),
surfacing as intermittent "Доступ запрещён" on orders filters/grid-config while the
later list request succeeded (grid filled). #533/#534/#536/#537 exposed the race by
dropping the waitForElement guard.

Ship the token synchronously in the inline ms3.config block, before the Vue module runs:
- manager.class.php: new addVueConfig() helper injects token = getUserToken($contextKey)
- customers/notifications/order/orders/settings/utilities: use addVueConfig()
- request.js getModAuthToken(): read ms3.config.token first, fall back to MODx.siteId

Covers all 6 Ext-less Vue pages. No permission/session change.
@Ibochkarev

Copy link
Copy Markdown
Member

Thermo-nuclear review

Вердикт: не approve. Направление фикса верное: один addVueConfig вместо шести копий var ms3, токен в inline-config. Но миграция на клиенте обрезана на полпути, а регресс никто не ловит автотестом.

1. Структурный регресс: второй путь auth жив

request.js читает ms3.config.token. Соседние write-site того же заголовка — нет:

  • vueManager/src/composables/useGalleryApi.js — локальный getModAuthToken() → только window.MODx?.siteId || ''
  • vueManager/src/components/gallery/GalleryUploader.vueHTTP_MODAUTH: window.MODx?.siteId || ''

После появления канонического источника токена два параллельных правила для HTTP_MODAUTH — это не nit. Та же модель гонки, которую PR убивает для orders, остаётся в gallery-пути.

Remedy: один хелпер (getModAuthToken / resolveModAuthToken в utils/modx.js), оба gallery-callsite на него. Smoke: запретить голый MODx.siteId под vueManager/src вне этого хелпера.

2. Soft-fail пустым token

$config['token'] = $this->modx->user
    ? (string) $this->modx->user->getUserToken($contextKey)
    : '';

На mgr после getUser('', true) user должен быть. Пустая строка тихо уезжает в HTML, клиент падает на MODx.siteId, гонка снова возможна. Лучше задавать токен напрямую (или падать громко), без ветки «отдадим страницу без токена».

3. Нет regression-теста

В PR: php -l, ESLint, ручной DEV. Нет проверки, что:

  • addVueConfig кладёт token через getUserToken
  • getModAuthToken() предпочитает ms3.config.token

Интермиттентный баг без автогейта вернётся незаметно. Минимальный smoke по исходникам + unit на приоритет токена закрывают AC #544.

4. Имя config.token

В проекте token уже означает customer/session/cart. HTTP_MODAUTH под тем же ключом — перегруженный контракт. Issue просит token, так что это не блокер merge, но modAuth / httpModAuth читается яснее. Если оставляете token — одна строка в PHPDoc: «mgr CSRF, не customer token».

5. Комментарии-эссе

PHPDoc у addVueConfig и блок в getModAuthToken пересказывают #544. Достаточно короткой отсылки к issue. Длинный нарратив устареет быстрее кода.

Что уже хорошо

Шесть копий inject схлопнуты в один helper. Порядок на request.js (ms3.config.tokenMODx.siteId) совпадает с диагнозом #544. PHP-сторона покрывает все шесть Ext-less страниц из issue. Файлы не раздуваются. Права не тронуты.

Approval bar

Блокер: gallery/useGalleryApi в обход нового источника токена.
Сильно желательно до merge: regression smoke/unit, убрать soft '' без user.
Опционально: явное имя ключа, короче комментарии.

Product/category inline-config без addVueConfig — вне scope #544 (Ext-страницы), но helper уже есть: следующий cleanup должен идти через него, а не плодить третий стиль inject.

Moving the ms3.config emission into the base addVueConfig() helper took the
`var ms3` literal out of the page controllers, so the *VueEntryTest smoke guards
that grep each controller for it failed. Switch the required pattern to
`addVueConfig`, and add a base-controller guard in CustomersNotificationsVueEntryTest
asserting controllers/manager.class.php ships `var ms3` + getUserToken (the #544
token injection that must not regress).
@Ibochkarev
Ibochkarev self-requested a review August 12, 2026 17:53
@biz87
biz87 merged commit 0b19184 into beta Aug 12, 2026
3 checks passed
@biz87
biz87 deleted the fix/544-mgr-token-race branch August 12, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants