This commit is contained in:
2026-05-22 17:05:39 +07:00
parent 582960cc32
commit 9e6f57be35
12 changed files with 4084 additions and 60 deletions

View File

@@ -18,6 +18,11 @@ const agentPackageDir = path.resolve(process.env.AGENT_PACKAGE_DIR || path.join(
const authCookieName = 'robot_installer_session';
const sessionMaxAgeMs = Number(process.env.SESSION_MAX_AGE_MS || 1000 * 60 * 60 * 8);
const authSecret = process.env.AUTH_SECRET || process.env.SESSION_SECRET || 'robot-installer-dev-secret';
const publicApiCorsOrigins = getCsvEnv(process.env.WEB_CLIENT_ORIGINS || process.env.PUBLIC_API_CORS_ORIGINS, [
'https://robot.installer',
'http://localhost:5173',
'http://localhost:4173'
]);
const agentVersionCollator = new Intl.Collator('en', {
numeric: true,
sensitivity: 'base'
@@ -99,6 +104,7 @@ app.set('views', path.join(__dirname, 'views'));
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/vendor/notiflix', express.static(path.join(__dirname, 'node_modules/notiflix/dist')));
app.use(applyPublicApiCors);
app.get('/packages/agent/latest.deb', asyncRoute(async (req, res) => {
const arch = normalizeAgentArch(req.query.arch);
const latestPackage = await findLatestAgentPackage(arch);
@@ -142,6 +148,44 @@ function helpers() {
};
}
function getCsvEnv(value, fallback) {
if (!value) return fallback;
return String(value)
.split(',')
.map((item) => item.trim())
.filter(Boolean);
}
function isPublicApiCorsPath(pathname) {
return pathname === '/api/apps'
|| pathname.startsWith('/api/apps/')
|| pathname === '/install-agent.sh';
}
function applyPublicApiCors(req, res, next) {
if (!isPublicApiCorsPath(req.path)) {
next();
return;
}
const origin = req.headers.origin;
const allowAnyOrigin = publicApiCorsOrigins.includes('*');
if (origin && (allowAnyOrigin || publicApiCorsOrigins.includes(origin))) {
res.setHeader('Access-Control-Allow-Origin', allowAnyOrigin ? '*' : origin);
res.setHeader('Vary', 'Origin');
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Accept, Content-Type');
}
if (req.method === 'OPTIONS') {
res.sendStatus(204);
return;
}
next();
}
function getVisibleNavItems(user) {
return navItems.filter((item) => !item.adminOnly || (user && user.role === 'Admin'));
}