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

331
server/forms/schemas.js Normal file
View File

@@ -0,0 +1,331 @@
import { z } from 'zod';
import { isAllowedAuthorityHost, isAllowedGraphHost } from '../data/graphHosts.js';
export const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(1)
});
export const profileSchema = z.object({
email: z.string().email().optional(),
displayName: z.string().min(1).max(120),
jobTitle: z.string().max(120).optional().default(''),
phone: z.string().max(60).optional().default(''),
timezone: z.string().max(80).optional().default(''),
avatarUrl: z.string().url().or(z.literal('')).optional().default('')
});
export const themeSchema = z.object({
theme: z.string().min(1).max(48).regex(/^[a-z0-9_-]+$/)
});
export const passwordChangeSchema = z.object({
currentPassword: z.string().optional().default(''),
newPassword: z.string().optional().default('')
});
export const visibilitySchema = z.enum(['personal', 'shared', 'group']);
export const userSchema = z.object({
email: z.string().email(),
displayName: z.string().min(1),
password: z.string().min(8).optional(),
role: z.enum(['admin', 'user']).default('user'),
groupIds: z.array(z.string()).default([])
});
export const groupSchema = z.object({
name: z.string().min(1),
description: z.string().optional(),
userIds: z.array(z.string()).default([])
});
export const credentialSchema = z.object({
name: z.string().min(1),
kind: z.enum(['username_password', 'api_key']),
username: z.string().optional(),
secret: z.string().min(1),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const hostSchema = z.object({
name: z.string().min(1),
fqdn: z.string().optional(),
address: z.string().min(1),
osFamily: z.string().default('windows'),
transport: z.enum(['winrm', 'ssh', 'local', 'api']).default('winrm'),
port: z.number().int().nullable().optional(),
credentialId: z.string().nullable().optional(),
tags: z.array(z.string()).default([]),
notes: z.string().optional(),
visibility: visibilitySchema.default('shared'),
groupId: z.string().nullable().optional()
});
export const folderSchema = z.object({
parentId: z.string().nullable().optional(),
name: z.string().min(1),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const assetFolderSchema = z.object({
parentId: z.string().nullable().optional(),
name: z.string().min(1).max(180),
description: z.string().max(600).optional().default(''),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const assetUploadSchema = z.object({
folderId: z.string().nullable().optional(),
name: z.string().min(1).max(220),
originalName: z.string().min(1).max(260).optional(),
description: z.string().max(1200).optional().default(''),
mimeType: z.string().max(160).optional(),
packagePath: z.string().max(500).optional().default(''),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const assetUpdateSchema = z.object({
folderId: z.string().nullable().optional(),
name: z.string().min(1).max(220).optional(),
description: z.string().max(1200).optional(),
packagePath: z.string().max(500).optional(),
visibility: visibilitySchema.optional(),
groupId: z.string().nullable().optional()
});
export const assetLinkSchema = z.object({
targetType: z.enum(['script', 'runplan', 'psadt_profile', 'intune_deployment']).default('script'),
targetId: z.string().min(1),
linkRole: z.enum(['reference', 'package-file', 'installer', 'support-file', 'icon', 'detection-script']).default('reference'),
packagePath: z.string().max(500).optional().default('')
});
export const variableNameSchema = z.string().min(1).max(80).regex(/^[A-Za-z_][A-Za-z0-9_]*$/);
export const customVariableSchema = z.object({
name: variableNameSchema,
description: z.string().max(500).optional().default(''),
category: z.string().min(1).max(80).optional().default('Custom'),
value: z.string().optional().default(''),
valueType: z.enum(['string', 'number', 'boolean', 'json']).default('string'),
sensitive: z.boolean().or(z.number()).optional().default(false),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const psadtProfileSchema = z.object({
name: z.string().min(1).max(160),
appVendor: z.string().max(120).optional().default(''),
appName: z.string().max(160).optional().default(''),
appVersion: z.string().max(80).optional().default(''),
appArch: z.enum(['x64', 'x86', 'neutral']).optional().default('x64'),
appLang: z.string().max(40).optional().default('EN'),
appRevision: z.string().max(40).optional().default('01'),
toolkitVersion: z.enum(['v4', 'v3-compatible']).optional().default('v4'),
templateVersion: z.enum(['v4', 'v3']).optional().default('v4'),
deploymentType: z.enum(['Install', 'Uninstall', 'Repair']).optional().default('Install'),
deployMode: z.enum(['Auto', 'Interactive', 'Silent', 'NonInteractive']).optional().default('Auto'),
requireAdmin: z.boolean().or(z.number()).optional().default(true),
zeroConfig: z.boolean().or(z.number()).optional().default(false),
suppressReboot: z.boolean().or(z.number()).optional().default(false),
closeProcesses: z.array(z.object({
name: z.string().min(1),
description: z.string().optional().default('')
})).optional().default([]),
installTasks: z.array(z.object({
type: z.enum(['exe', 'msi', 'msp', 'script']).default('exe'),
phase: z.enum(['Pre-Install', 'Install', 'Post-Install', 'Pre-Uninstall', 'Uninstall', 'Post-Uninstall', 'Pre-Repair', 'Repair', 'Post-Repair']).default('Install'),
filePath: z.string().min(1),
arguments: z.string().optional().default(''),
secureArguments: z.boolean().or(z.number()).optional().default(false)
})).optional().default([]),
uiPlan: z.record(z.string(), z.any()).optional().default({}),
configPlan: z.record(z.string(), z.any()).optional().default({}),
admxPlan: z.record(z.string(), z.any()).optional().default({}),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const psadtValidationSchema = z.object({
content: z.string().optional().default(''),
scriptId: z.string().optional(),
profileId: z.string().optional(),
platform: z.enum(['intune', 'configmgr', 'gpo', 'manual']).optional().default('intune')
});
export const psadtMigrationSchema = z.object({
content: z.string().optional().default(''),
scriptId: z.string().optional(),
targetVersion: z.string().optional().default('4.2.0'),
createScript: z.boolean().or(z.number()).optional().default(false),
nameSuffix: z.string().max(80).optional().default('PSADT 4.2 migrated')
});
export const intuneDeploymentSchema = z.object({
name: z.string().min(1).max(160),
profileId: z.string().nullable().optional(),
scriptId: z.string().nullable().optional(),
applicationId: z.string().nullable().optional(),
sourceFolder: z.string().max(500).optional().default(''),
intunewinFile: z.string().max(500).optional().default(''),
appType: z.string().min(1).max(80).optional().default('Windows app (Win32)'),
commandStyle: z.enum(['v4', 'legacy-v3']).optional().default('v4'),
installBehavior: z.enum(['system', 'user']).optional().default('system'),
restartBehavior: z.enum(['return-code', 'suppress', 'intune']).optional().default('return-code'),
uiMode: z.enum(['native-v4', 'serviceui-legacy', 'silent']).optional().default('native-v4'),
requirements: z.object({
architecture: z.enum(['x64', 'x86', 'both']).optional().default('x64'),
minOs: z.string().max(80).optional().default('Windows 10 22H2'),
diskSpaceMb: z.number().or(z.string()).optional().default(0),
runAs32Bit: z.boolean().or(z.number()).optional().default(false)
}).optional().default({}),
installCommand: z.string().max(500).optional().default(''),
uninstallCommand: z.string().max(500).optional().default(''),
detectionType: z.enum(['msi-product-code', 'file-version', 'registry', 'custom-script']).optional().default('custom-script'),
detectionRule: z.string().max(3000).optional().default(''),
returnCodes: z.array(z.object({
code: z.string().or(z.number()),
type: z.string().min(1).max(40),
meaning: z.string().max(240).optional().default('')
})).optional().default([]),
assignments: z.array(z.object({
ring: z.string().min(1).max(80),
intent: z.enum(['available', 'required', 'uninstall', 'exclude']).optional().default('required'),
groupName: z.string().max(160).optional().default(''),
groupId: z.string().max(120).optional().default(''),
groupMode: z.enum(['group', 'allDevices', 'allUsers']).optional().default('group'),
filterId: z.string().max(120).optional().default(''),
filterType: z.enum(['none', 'include', 'exclude']).optional().default('none'),
autoUpdate: z.boolean().or(z.number()).optional().default(false),
notes: z.string().max(240).optional().default('')
})).optional().default([]),
relationships: z.array(z.object({
kind: z.enum(['supersedence', 'dependency']).default('supersedence'),
targetAppId: z.string().min(1).max(160),
targetName: z.string().max(200).optional().default(''),
mode: z.string().max(40).optional().default('')
})).optional().default([]),
status: z.enum(['draft', 'ready', 'published', 'retired']).optional().default('draft'),
autoPromoteAfterHours: z.number().int().min(0).or(z.string()).optional().default(0),
autoPromoteRing: z.string().max(80).optional().default(''),
autoPromoteIntent: z.enum(['available', 'required', 'uninstall', 'exclude']).optional().default('required'),
graphAppId: z.string().max(160).optional().default(''),
graphConnectionId: z.string().nullable().optional(),
notes: z.string().max(1000).optional().default(''),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const applicationSchema = z.object({
name: z.string().min(1).max(160),
vendor: z.string().max(120).optional().default(''),
publisher: z.string().max(160).optional().default(''),
currentVersion: z.string().max(80).optional().default(''),
latestKnownVersion: z.string().max(80).optional().default(''),
versionSource: z.enum(['manual', 'url', 'winget']).optional().default('manual'),
versionSourceRef: z.string().max(500).optional().default(''),
graphConnectionId: z.string().nullable().optional(),
currentGraphAppId: z.string().max(160).optional().default(''),
autoCheck: z.boolean().or(z.number()).optional().default(false),
notes: z.string().max(1000).optional().default(''),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const applicationImportSchema = z.object({
connectionId: z.string().min(1),
graphAppId: z.string().min(1).max(160),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const graphConnectionSchema = z.object({
name: z.string().min(1).max(160),
tenantId: z.string().min(1).max(120),
clientId: z.string().min(1).max(120),
clientSecret: z.string().optional().default(''),
cloud: z.enum(['global', 'gcc', 'gcchigh', 'dod', 'china', 'custom']).optional().default('global'),
graphBaseUrl: z.string().url().refine(isAllowedGraphHost, {
message: 'graphBaseUrl must be a recognized Microsoft Graph host'
}).optional().default('https://graph.microsoft.com'),
authorityHost: z.string().url().refine(isAllowedAuthorityHost, {
message: 'authorityHost must be a recognized Microsoft login host'
}).optional().default('https://login.microsoftonline.com'),
defaultApiVersion: z.enum(['v1.0', 'beta']).optional().default('v1.0'),
enabled: z.boolean().or(z.number()).optional().default(true),
allowWrite: z.boolean().or(z.number()).optional().default(false),
requireApproval: z.boolean().or(z.number()).optional().default(false),
publisherIds: z.array(z.string()).optional().default([]),
approverIds: z.array(z.string()).optional().default([]),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional()
});
export const graphDeploymentLinkSchema = z.object({
connectionId: z.string().optional().default(''),
graphAppId: z.string().min(1).max(160)
});
export const graphDeploymentSyncSchema = z.object({
connectionId: z.string().optional().default(''),
graphAppId: z.string().optional().default(''),
mode: z.enum(['reports', 'legacy-status', 'both']).optional().default('reports')
});
const scriptPayloadSchema = z.object({
folderId: z.string().nullable().optional(),
folder_id: z.string().nullable().optional(),
name: z.string().min(1),
description: z.string().optional().default(''),
content: z.string().default(''),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional(),
group_id: z.string().nullable().optional()
});
export const scriptTestRunSchema = z.object({
hostId: z.string().min(1),
credentialId: z.string().min(1)
});
const runPlanPayloadSchema = z.object({
name: z.string().min(1),
description: z.string().optional().default(''),
scriptId: z.string().optional(),
script_id: z.string().optional(),
visibility: visibilitySchema.default('personal'),
groupId: z.string().nullable().optional(),
group_id: z.string().nullable().optional(),
parallel: z.boolean().or(z.number()).default(true),
hostIds: z.array(z.string()).optional()
});
export function normalizeScriptPayload(body) {
const parsed = scriptPayloadSchema.parse(body);
return {
folderId: parsed.folderId ?? parsed.folder_id ?? null,
name: parsed.name,
description: parsed.description || '',
content: parsed.content || '',
visibility: parsed.visibility,
groupId: parsed.visibility === 'group' ? parsed.groupId ?? parsed.group_id ?? null : null
};
}
export function normalizeRunPlanPayload(body) {
const parsed = runPlanPayloadSchema.parse(body);
return {
name: parsed.name,
description: parsed.description || '',
scriptId: parsed.scriptId || parsed.script_id,
visibility: parsed.visibility,
groupId: parsed.visibility === 'group' ? parsed.groupId ?? parsed.group_id ?? null : null,
parallel: Boolean(parsed.parallel),
hostIds: parsed.hostIds || []
};
}