This commit is contained in:
2026-06-25 12:05:53 -05:00
commit b58e50e423
141 changed files with 28190 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
import { Router } from 'express';
import { checkAll, checkUpdate, create, destroy, importFromTenant, index, show, update } from '../controllers/applicationController.js';
import { requireAdmin, requireAuth } from '../middleware/auth.js';
export const applicationRoutes = Router();
// Phase 5 application catalog: groups versioned deployments + tracks upstream
// version state and adoption of existing tenant apps.
applicationRoutes.get('/', requireAuth, index);
applicationRoutes.post('/', requireAuth, create);
applicationRoutes.post('/check-all', requireAuth, requireAdmin, checkAll);
applicationRoutes.post('/import', requireAuth, importFromTenant);
applicationRoutes.get('/:id', requireAuth, show);
applicationRoutes.put('/:id', requireAuth, update);
applicationRoutes.delete('/:id', requireAuth, destroy);
applicationRoutes.post('/:id/check-update', requireAuth, checkUpdate);

View File

@@ -0,0 +1,38 @@
import { Router } from 'express';
import {
assetFolders,
assetLinks,
assets,
createAssetAction,
createAssetFolderAction,
createAssetLinkAction,
deleteAssetAction,
deleteAssetFolderAction,
deleteAssetLinkAction,
downloadAssetAction,
getAssetAction,
updateAssetAction,
updateAssetFolderAction,
viewAssetAction
} from '../controllers/assetController.js';
import { requireAuth } from '../middleware/auth.js';
import { assetUpload } from '../middleware/upload.js';
export const assetRoutes = Router();
// Asset routes stay API-first: UI upload, package builders, and external clients share this surface.
assetRoutes.get('/folders', requireAuth, assetFolders);
assetRoutes.post('/folders', requireAuth, createAssetFolderAction);
assetRoutes.put('/folders/:id', requireAuth, updateAssetFolderAction);
assetRoutes.delete('/folders/:id', requireAuth, deleteAssetFolderAction);
assetRoutes.delete('/links/:linkId', requireAuth, deleteAssetLinkAction);
assetRoutes.get('/', requireAuth, assets);
assetRoutes.post('/', requireAuth, assetUpload.single('file'), createAssetAction);
assetRoutes.get('/:id/download', requireAuth, downloadAssetAction);
assetRoutes.get('/:id/view', requireAuth, viewAssetAction);
assetRoutes.get('/:id/links', requireAuth, assetLinks);
assetRoutes.post('/:id/links', requireAuth, createAssetLinkAction);
assetRoutes.get('/:id', requireAuth, getAssetAction);
assetRoutes.put('/:id', requireAuth, updateAssetAction);
assetRoutes.delete('/:id', requireAuth, deleteAssetAction);

View File

@@ -0,0 +1,18 @@
import { Router } from 'express';
import { entraCallback, entraLogin, login, me, password, profile, theme } from '../controllers/authController.js';
import { requireAuth } from '../middleware/auth.js';
import { rateLimit } from '../middleware/rateLimit.js';
export const authRoutes = Router();
// Throttle credential-guessing against the public login endpoint.
const loginLimiter = rateLimit({ windowMs: 60_000, max: 10, keyPrefix: 'login' });
// Session/profile endpoints. Local login is public; profile mutations require a valid JWT.
authRoutes.post('/login', loginLimiter, login);
authRoutes.get('/entra/login', entraLogin);
authRoutes.get('/entra/callback', entraCallback);
authRoutes.get('/me', requireAuth, me);
authRoutes.put('/profile', requireAuth, profile);
authRoutes.put('/theme', requireAuth, theme);
authRoutes.post('/change-password', requireAuth, password);

8
server/routes/bootstrapRoutes.js vendored Normal file
View File

@@ -0,0 +1,8 @@
import { Router } from 'express';
import { bootstrap, health } from '../controllers/bootstrapController.js';
import { requireAuth } from '../middleware/auth.js';
export const bootstrapRoutes = Router();
bootstrapRoutes.get('/health', health);
bootstrapRoutes.get('/bootstrap', requireAuth, bootstrap);

View File

@@ -0,0 +1,10 @@
import { Router } from 'express';
import { create, destroy, index, update } from '../controllers/credentialController.js';
import { requireAuth } from '../middleware/auth.js';
export const credentialRoutes = Router();
credentialRoutes.get('/', requireAuth, index);
credentialRoutes.post('/', requireAuth, create);
credentialRoutes.put('/:id', requireAuth, update);
credentialRoutes.delete('/:id', requireAuth, destroy);

View File

@@ -0,0 +1,19 @@
import { Router } from 'express';
import {
approveChangeRequest,
auditExport,
changeRequests,
reportingOverview,
rejectChangeRequest
} from '../controllers/governanceController.js';
import { requireAuth } from '../middleware/auth.js';
export const governanceRoutes = Router();
// Phase 6 governance & reporting for Intune tenant write-back. Approve/reject
// authorize admins or named approvers inside the controller.
governanceRoutes.get('/change-requests', requireAuth, changeRequests);
governanceRoutes.post('/change-requests/:id/approve', requireAuth, approveChangeRequest);
governanceRoutes.post('/change-requests/:id/reject', requireAuth, rejectChangeRequest);
governanceRoutes.get('/reporting/overview', requireAuth, reportingOverview);
governanceRoutes.get('/deployments/:id/audit/export', requireAuth, auditExport);

View File

@@ -0,0 +1,13 @@
import { Router } from 'express';
import { create, destroy, index, mobileApps, test, update } from '../controllers/graphController.js';
import { requireAuth } from '../middleware/auth.js';
export const graphRoutes = Router();
// Microsoft Graph environments for Intune app publishing/status tracking.
graphRoutes.get('/connections', requireAuth, index);
graphRoutes.post('/connections', requireAuth, create);
graphRoutes.put('/connections/:id', requireAuth, update);
graphRoutes.delete('/connections/:id', requireAuth, destroy);
graphRoutes.post('/connections/:id/test', requireAuth, test);
graphRoutes.get('/connections/:id/mobile-apps', requireAuth, mobileApps);

View File

@@ -0,0 +1,8 @@
import { Router } from 'express';
import { create, index } from '../controllers/groupController.js';
import { requireAdmin, requireAuth } from '../middleware/auth.js';
export const groupRoutes = Router();
groupRoutes.get('/', requireAuth, index);
groupRoutes.post('/', requireAuth, requireAdmin, create);

View File

@@ -0,0 +1,9 @@
import { Router } from 'express';
import { index, show } from '../controllers/helpController.js';
import { requireAuth } from '../middleware/auth.js';
export const helpRoutes = Router();
// Searchable in-app help library for operators and API automation clients.
helpRoutes.get('/', requireAuth, index);
helpRoutes.get('/:id', requireAuth, show);

View File

@@ -0,0 +1,10 @@
import { Router } from 'express';
import { create, destroy, index, update } from '../controllers/hostController.js';
import { requireAuth } from '../middleware/auth.js';
export const hostRoutes = Router();
hostRoutes.get('/', requireAuth, index);
hostRoutes.post('/', requireAuth, create);
hostRoutes.put('/:id', requireAuth, update);
hostRoutes.delete('/:id', requireAuth, destroy);

44
server/routes/index.js Normal file
View File

@@ -0,0 +1,44 @@
import { Router } from 'express';
import { applicationRoutes } from './applicationRoutes.js';
import { assetRoutes } from './assetRoutes.js';
import { authRoutes } from './authRoutes.js';
import { bootstrapRoutes } from './bootstrapRoutes.js';
import { credentialRoutes } from './credentialRoutes.js';
import { folderRoutes, scriptRoutes } from './libraryRoutes.js';
import { governanceRoutes } from './governanceRoutes.js';
import { groupRoutes } from './groupRoutes.js';
import { graphRoutes } from './graphRoutes.js';
import { helpRoutes } from './helpRoutes.js';
import { hostRoutes } from './hostRoutes.js';
import { jobRoutes } from './jobRoutes.js';
import { logRoutes } from './logRoutes.js';
import { packagingRoutes } from './packagingRoutes.js';
import { psadtRoutes } from './psadtRoutes.js';
import { runPlanRoutes } from './runPlanRoutes.js';
import { settingsRoutes } from './settingsRoutes.js';
import { userRoutes } from './userRoutes.js';
import { variableRoutes } from './variableRoutes.js';
export const apiRoutes = Router();
// Central API composition keeps individual route modules small and domain-focused.
apiRoutes.use(bootstrapRoutes);
apiRoutes.use('/auth', authRoutes);
apiRoutes.use('/settings', settingsRoutes);
apiRoutes.use('/users', userRoutes);
apiRoutes.use('/groups', groupRoutes);
apiRoutes.use('/graph', graphRoutes);
apiRoutes.use('/help', helpRoutes);
apiRoutes.use('/assets', assetRoutes);
apiRoutes.use('/credentials', credentialRoutes);
apiRoutes.use('/hosts', hostRoutes);
apiRoutes.use('/folders', folderRoutes);
apiRoutes.use('/scripts', scriptRoutes);
apiRoutes.use('/variables', variableRoutes);
apiRoutes.use('/psadt', psadtRoutes);
apiRoutes.use('/packaging', packagingRoutes);
apiRoutes.use('/intune/applications', applicationRoutes);
apiRoutes.use('/intune', governanceRoutes);
apiRoutes.use('/runplans', runPlanRoutes);
apiRoutes.use('/jobs', jobRoutes);
apiRoutes.use('/logs', logRoutes);

View File

@@ -0,0 +1,8 @@
import { Router } from 'express';
import { index, show } from '../controllers/jobController.js';
import { requireAuth } from '../middleware/auth.js';
export const jobRoutes = Router();
jobRoutes.get('/', requireAuth, index);
jobRoutes.get('/:id', requireAuth, show);

View File

@@ -0,0 +1,36 @@
import { Router } from 'express';
import {
cloneScriptAction,
createFolderAction,
createScriptAction,
deleteFolderAction,
deleteScriptAction,
folders,
getScriptAction,
scriptUsageAction,
scripts,
scriptVersions,
testRunScriptAction,
updateFolderAction,
updateScriptAction
} from '../controllers/libraryController.js';
import { requireAuth } from '../middleware/auth.js';
export const folderRoutes = Router();
export const scriptRoutes = Router();
// Folders and scripts are split for clean URLs while sharing library visibility rules.
folderRoutes.get('/', requireAuth, folders);
folderRoutes.post('/', requireAuth, createFolderAction);
folderRoutes.put('/:id', requireAuth, updateFolderAction);
folderRoutes.delete('/:id', requireAuth, deleteFolderAction);
scriptRoutes.get('/', requireAuth, scripts);
scriptRoutes.post('/', requireAuth, createScriptAction);
scriptRoutes.get('/:id/usage', requireAuth, scriptUsageAction);
scriptRoutes.post('/:id/clone', requireAuth, cloneScriptAction);
scriptRoutes.post('/:id/test-run', requireAuth, testRunScriptAction);
scriptRoutes.get('/:id', requireAuth, getScriptAction);
scriptRoutes.put('/:id', requireAuth, updateScriptAction);
scriptRoutes.delete('/:id', requireAuth, deleteScriptAction);
scriptRoutes.get('/:id/versions', requireAuth, scriptVersions);

View File

@@ -0,0 +1,8 @@
import { Router } from 'express';
import { systemLogs } from '../controllers/logController.js';
import { requireAdmin, requireAuth } from '../middleware/auth.js';
export const logRoutes = Router();
// System logs can expose operational internals, so access is admin-only.
logRoutes.get('/system', requireAuth, requireAdmin, systemLogs);

View File

@@ -0,0 +1,11 @@
import { Router } from 'express';
import { analyze, detection, installerTypes } from '../controllers/packagingController.js';
import { requireAuth } from '../middleware/auth.js';
export const packagingRoutes = Router();
// Phase 1 installer intelligence: detect technology, recommend silent commands,
// and generate detection rules.
packagingRoutes.get('/installer-types', requireAuth, installerTypes);
packagingRoutes.post('/analyze', requireAuth, analyze);
packagingRoutes.post('/detection', requireAuth, detection);

View File

@@ -0,0 +1,68 @@
import { Router } from 'express';
import {
catalog,
create,
destroy,
index,
intuneCreate,
intuneDestroy,
intuneGraphAssign,
intuneGraphAudit,
intuneGraphDrift,
intuneGraphLink,
intuneGraphPublish,
intuneGraphRelationships,
intuneBuild,
intuneBuilderStatus,
intuneGraphReconcile,
intuneGraphStatus,
intuneGraphSync,
intuneGraphUploadContent,
intuneIndex,
intuneNewVersion,
intunePromote,
intuneShow,
intuneUpdate,
migrationApply,
migrationPlan,
render,
rules,
show,
update,
validate
} from '../controllers/psadtController.js';
import { requireAuth } from '../middleware/auth.js';
export const psadtRoutes = Router();
// PSADT Workbench APIs expose reference support plus persistent deployment profiles.
psadtRoutes.get('/catalog', requireAuth, catalog);
psadtRoutes.get('/validation-rules', requireAuth, rules);
psadtRoutes.post('/validate', requireAuth, validate);
psadtRoutes.post('/migration/plan', requireAuth, migrationPlan);
psadtRoutes.post('/migration/apply', requireAuth, migrationApply);
psadtRoutes.get('/intune/deployments', requireAuth, intuneIndex);
psadtRoutes.post('/intune/deployments', requireAuth, intuneCreate);
psadtRoutes.get('/intune/deployments/:id', requireAuth, intuneShow);
psadtRoutes.put('/intune/deployments/:id', requireAuth, intuneUpdate);
psadtRoutes.delete('/intune/deployments/:id', requireAuth, intuneDestroy);
psadtRoutes.get('/intune/deployments/:id/graph/status', requireAuth, intuneGraphStatus);
psadtRoutes.post('/intune/deployments/:id/graph/link', requireAuth, intuneGraphLink);
psadtRoutes.post('/intune/deployments/:id/graph/sync', requireAuth, intuneGraphSync);
psadtRoutes.post('/intune/deployments/:id/graph/publish', requireAuth, intuneGraphPublish);
psadtRoutes.post('/intune/deployments/:id/graph/assign', requireAuth, intuneGraphAssign);
psadtRoutes.post('/intune/deployments/:id/graph/relationships', requireAuth, intuneGraphRelationships);
psadtRoutes.post('/intune/deployments/:id/graph/upload-content', requireAuth, intuneGraphUploadContent);
psadtRoutes.post('/intune/deployments/:id/graph/drift', requireAuth, intuneGraphDrift);
psadtRoutes.post('/intune/deployments/:id/graph/reconcile', requireAuth, intuneGraphReconcile);
psadtRoutes.get('/intune/builder/status', requireAuth, intuneBuilderStatus);
psadtRoutes.post('/intune/deployments/:id/build', requireAuth, intuneBuild);
psadtRoutes.post('/intune/deployments/:id/new-version', requireAuth, intuneNewVersion);
psadtRoutes.post('/intune/deployments/:id/promote', requireAuth, intunePromote);
psadtRoutes.get('/intune/deployments/:id/graph/audit', requireAuth, intuneGraphAudit);
psadtRoutes.get('/profiles', requireAuth, index);
psadtRoutes.post('/profiles', requireAuth, create);
psadtRoutes.get('/profiles/:id', requireAuth, show);
psadtRoutes.put('/profiles/:id', requireAuth, update);
psadtRoutes.delete('/profiles/:id', requireAuth, destroy);
psadtRoutes.get('/profiles/:id/render', requireAuth, render);

View File

@@ -0,0 +1,13 @@
import { Router } from 'express';
import { create, destroy, execute, index, show, update } from '../controllers/runPlanController.js';
import { requireAuth } from '../middleware/auth.js';
export const runPlanRoutes = Router();
// RunPlan metadata is CRUD; execution is an explicit action endpoint.
runPlanRoutes.get('/', requireAuth, index);
runPlanRoutes.post('/', requireAuth, create);
runPlanRoutes.get('/:id', requireAuth, show);
runPlanRoutes.put('/:id', requireAuth, update);
runPlanRoutes.delete('/:id', requireAuth, destroy);
runPlanRoutes.post('/:id/execute', requireAuth, execute);

View File

@@ -0,0 +1,9 @@
import { Router } from 'express';
import { listSettings, saveSettings } from '../controllers/settingsController.js';
import { requireAdmin, requireAuth } from '../middleware/auth.js';
export const settingsRoutes = Router();
// Settings are readable by operators but writable only by admins.
settingsRoutes.get('/', requireAuth, listSettings);
settingsRoutes.put('/', requireAuth, requireAdmin, saveSettings);

View File

@@ -0,0 +1,8 @@
import { Router } from 'express';
import { create, index } from '../controllers/userController.js';
import { requireAdmin, requireAuth } from '../middleware/auth.js';
export const userRoutes = Router();
userRoutes.get('/', requireAuth, requireAdmin, index);
userRoutes.post('/', requireAuth, requireAdmin, create);

View File

@@ -0,0 +1,12 @@
import { Router } from 'express';
import { catalog, createCustom, customIndex, destroyCustom, updateCustom } from '../controllers/variableController.js';
import { requireAuth } from '../middleware/auth.js';
export const variableRoutes = Router();
// Variables expose the PSADT/POSHManager catalog plus user-managed runtime values for scripts.
variableRoutes.get('/catalog', requireAuth, catalog);
variableRoutes.get('/custom', requireAuth, customIndex);
variableRoutes.post('/custom', requireAuth, createCustom);
variableRoutes.put('/custom/:id', requireAuth, updateCustom);
variableRoutes.delete('/custom/:id', requireAuth, destroyCustom);