117 lines
4.5 KiB
JavaScript
117 lines
4.5 KiB
JavaScript
const https = require('https');
|
|
const config = require('../config');
|
|
|
|
/**
|
|
* Express middleware — извлекает контекст из сессии.
|
|
* При 401 от IAM — чистит сессию и редиректит на логин (SSO).
|
|
*/
|
|
async function resolveContext(req, res, next) {
|
|
const u = req.session && req.session.user;
|
|
if (!u) return res.redirect('/v2/login');
|
|
|
|
const token = req.session && req.session.token;
|
|
if (token) {
|
|
try {
|
|
await checkImpersonation(token, req, u);
|
|
} catch (e) {
|
|
const msg = (e.message || '');
|
|
// 401 — токен протух, чистим сессию → SSO даст свежий
|
|
if (msg.startsWith('401')) {
|
|
req.session.destroy(() => res.redirect('/v2/login'));
|
|
return;
|
|
}
|
|
// Другие ошибки IAM — игнорируем, используем старые данные
|
|
}
|
|
}
|
|
|
|
applyContext(req, u);
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* Запрашивает IAM и обновляет сессию если имперсонация изменилась.
|
|
* Бросает ошибку при 401 — вызывающий обработает.
|
|
*/
|
|
async function checkImpersonation(token, req, u) {
|
|
const url = config.iamApiBase + '/auth/user';
|
|
const uObj = new URL(url);
|
|
const data = await new Promise((resolve, reject) => {
|
|
https.get({
|
|
hostname: uObj.hostname, port: 443, path: uObj.pathname,
|
|
headers: { Authorization: 'Bearer ' + token, Accept: 'application/json' },
|
|
}, res => {
|
|
let d = '';
|
|
res.on('data', c => d += c);
|
|
res.on('end', () => {
|
|
if (res.statusCode !== 200) return reject(new Error(res.statusCode + ': ' + d.slice(0, 200)));
|
|
try { resolve(JSON.parse(d)); } catch (e) { reject(e); }
|
|
});
|
|
}).on('error', reject);
|
|
});
|
|
|
|
const imp = data.impersonation || {};
|
|
const newIsImp = !!(imp.is_impersonated);
|
|
const oldIsImp = !!(u.originalUserEmail && u.impersonatedCompanyId);
|
|
|
|
// Статус не изменился — ничего не делаем
|
|
if (newIsImp === oldIsImp) return;
|
|
|
|
if (newIsImp) {
|
|
// Имперсонация началась — обновляем сессию данными таргета
|
|
const profiles = data.profiles || [];
|
|
const activeProfile = profiles.find(p => p.is_active_profile) || profiles[0] || {};
|
|
const ui = data.userInfo || {};
|
|
|
|
req.session.user = {
|
|
...u,
|
|
email: ui.email || '',
|
|
clientId: ui.clientID || activeProfile.client_id || '',
|
|
allClientIds: profiles.map(p => p.client_id).filter(Boolean),
|
|
activeClientId: ui.clientID || activeProfile.client_id || '',
|
|
activeProfileId: activeProfile.id || null,
|
|
companyId: ui.companyId || '',
|
|
companyName: ui.company || activeProfile.company_name || '',
|
|
isAdmin: !!ui.isAdmin,
|
|
isImpersonated: true,
|
|
impersonationType: imp.type || null,
|
|
impersonatedCompanyId: imp.impersonatedCompanyId || '',
|
|
originalUserEmail: imp.originalUserEmail || u.originalUserEmail || '',
|
|
originalUserFullName: imp.originalUserFullName || u.originalUserFullName || '',
|
|
originalUserCompany: imp.originalUserCompany || u.originalUserCompany || '',
|
|
fio: ui.fio || null,
|
|
profiles,
|
|
};
|
|
} else {
|
|
// Имперсонация завершилась — убираем флаги, восстанавливаем оригинальные данные
|
|
req.session.user = {
|
|
...u,
|
|
isImpersonated: false,
|
|
impersonationType: null,
|
|
impersonatedCompanyId: null,
|
|
originalUserEmail: null,
|
|
originalUserFullName: null,
|
|
originalUserCompany: null,
|
|
};
|
|
}
|
|
}
|
|
|
|
function applyContext(req, u) {
|
|
const isImpersonated = !!(u.originalUserEmail && u.impersonatedCompanyId);
|
|
|
|
req.email = u.email || '';
|
|
req.clientId = isImpersonated
|
|
? (u.activeClientId || u.impersonatedCompanyId || u.clientId || '')
|
|
: (u.activeClientId || u.clientId || '');
|
|
req.companyName = u.companyName || req.clientId;
|
|
const allCids = u.allClientIds || [u.clientId || ''];
|
|
req.canAdmin = allCids.includes('WZ01112') || u.clientId === 'WZ01112' || !!u.isAdmin || u.email === (process.env.ADMIN_EMAIL || '');
|
|
req.adminMode = req.canAdmin;
|
|
req.isAdmin = req.canAdmin;
|
|
req.isImpersonated = isImpersonated;
|
|
req.impersonatedBy = isImpersonated ? u.originalUserEmail : null;
|
|
req.allClientIds = allCids;
|
|
req.profiles = u.profiles || [];
|
|
}
|
|
|
|
module.exports = { resolveContext };
|