import { createHash } from 'node:crypto'; import type { GpoDriveMapPreferenceValue, GpoPolicyObservation, GpoPreferenceContext } from '../../src/domain/gpo-policy'; import { gpoPolicyObservationValidationErrors } from '../../src/domain/gpo-policy'; import type { GpoPolicyScope } from '../../src/domain/gpo-ingestion'; import { xmlElementStartLines } from './xml-source-lines'; export const GPP_DRIVE_MAPS_REDUCER = { id: 'gpo-preferences-drive-maps-reducer', version: '1.0.0' } as const; const drivesClsid = '8fddcc1a-0c3c-43cd-a6b4-71a6df20da8c'; const driveClsid = '935d1b74-9cb8-4e3c-9914-7dd559b7a417'; const guidPattern = /^\{?([a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12})\}?$/i; type Operation = Exclude; type Targeting = GpoPreferenceContext['targeting']; export interface GppDriveMapInstruction { version: 1; cse: 'drive-maps'; uid: string; sequence: number; line: number; operation: Operation; disabled: boolean; removePolicy: boolean; applyOnce: boolean; targeting: Targeting; value: GpoDriveMapPreferenceValue; } export interface DriveMapsPreferenceDocument { version: 1; parser: { id: string; version: string }; sourcePath: string; sourceSha256: string; scope: GpoPolicyScope; preferenceType: 'drive-maps'; status: 'complete' | 'partial' | 'invalid'; secretIndicatorStatus: 'not-detected' | 'present'; instructions: GppDriveMapInstruction[]; diagnosticCodes: string[]; } export interface DriveMapsParseContext { root: Element; text: string; scope: GpoPolicyScope; parser: { id: string; version: string }; sourcePath: string; sourceSha256: string; secretIndicatorStatus: 'not-detected' | 'present'; diagnostics: Set; summarizeTargeting: (item: Element, diagnostics: Set) => Targeting | undefined; } const visibilityValues = { NOCHANGE: 'no-change', HIDE: 'hide', SHOW: 'show' } as const; const allowedPropertyAttributes = new Set([ 'action', 'thisdrive', 'alldrives', 'username', 'cpassword', 'path', 'label', 'persistent', 'useletter', 'letter' ]); function attribute(element: Element, name: string): string | undefined { const normalized = name.toLocaleLowerCase('en-US'); return [...element.attributes].find(candidate => candidate.localName.toLocaleLowerCase('en-US') === normalized)?.value; } function canonicalGuid(value: string | undefined): string | undefined { return value ? guidPattern.exec(value.trim())?.[1].toLocaleLowerCase('en-US') : undefined; } function booleanAttribute(element: Element, name: string, diagnostics: Set): boolean | undefined { const value = attribute(element, name); if (value === undefined || value === '0') return false; if (value === '1') return true; diagnostics.add('gpo-preference-boolean-invalid'); return undefined; } function operation(value: string | undefined): Operation | undefined { const code = (value ?? 'U').toLocaleUpperCase('en-US'); return ({ C: 'create', D: 'delete', R: 'replace', U: 'update' } as const)[code as 'C' | 'D' | 'R' | 'U']; } function visibilityAttribute( element: Element, name: string, diagnostics: Set ): GpoDriveMapPreferenceValue['thisDrive'] | undefined { const key = (attribute(element, name) ?? 'NOCHANGE').toLocaleUpperCase('en-US') as keyof typeof visibilityValues; if (Object.hasOwn(visibilityValues, key)) return visibilityValues[key]; diagnostics.add('gpo-preference-drive-visibility-invalid'); return undefined; } function isUncPath(value: string): boolean { if (!value.startsWith('\\\\') || value.includes('/') || /[\u0000-\u001f]/.test(value)) return false; const segments = value.slice(2).split('\\'); return segments.length >= 2 && Boolean(segments[0].trim()) && Boolean(segments[1].trim()); } function validUserName(value: string): boolean { if (!value) return true; const separator = value.indexOf('\\'); return separator > 0 && separator === value.lastIndexOf('\\') && separator < value.length - 1 && !value.includes('/'); } function selectionMode(operationValue: Operation, useLetter: boolean): GpoDriveMapPreferenceValue['selectionMode'] { if (useLetter) return 'exact'; if (operationValue === 'delete') return 'delete-range'; if (operationValue === 'create') return 'first-available'; return 'first-mapped-in-range'; } function directChildren(element: Element, name: string): Element[] { const normalized = name.toLocaleLowerCase('en-US'); return [...element.children].filter(child => child.localName.toLocaleLowerCase('en-US') === normalized); } function itemLines(text: string): number[] { return xmlElementStartLines(text, /<(?:[A-Za-z_][\w.-]*:)?Drive(?=[\s/>])/g); } function parseDriveValue( properties: Element, operationValue: Operation, diagnostics: Set ): GpoDriveMapPreferenceValue | undefined { const letter = attribute(properties, 'letter')?.trim().toLocaleUpperCase('en-US'); if (!letter || !/^[A-Z]$/.test(letter)) diagnostics.add('gpo-preference-drive-letter-invalid'); const useLetter = booleanAttribute(properties, 'useLetter', diagnostics); const persistent = booleanAttribute(properties, 'persistent', diagnostics); const thisDrive = visibilityAttribute(properties, 'thisDrive', diagnostics); const allDrives = visibilityAttribute(properties, 'allDrives', diagnostics); const path = attribute(properties, 'path'); const pathRequired = operationValue === 'create' || operationValue === 'replace'; if ((pathRequired && !path) || (path && !isUncPath(path))) diagnostics.add('gpo-preference-drive-path-invalid'); const userName = attribute(properties, 'userName'); if (userName !== undefined && !validUserName(userName)) diagnostics.add('gpo-preference-drive-user-invalid'); if (!letter || useLetter === undefined || persistent === undefined || !thisDrive || !allDrives) return undefined; return { kind: 'drive-map-preference', path, label: attribute(properties, 'label'), persistent, userName, passwordAttributePresent: [...properties.attributes] .some(candidate => candidate.localName.toLocaleLowerCase('en-US') === 'cpassword'), letter, useLetter, selectionMode: selectionMode(operationValue, useLetter), thisDrive, allDrives }; } export function parseDriveMapsPreference(context: DriveMapsParseContext): DriveMapsPreferenceDocument { const { root, diagnostics } = context; const rootDisabled = booleanAttribute(root, 'disabled', diagnostics) ?? false; if (canonicalGuid(attribute(root, 'clsid')) !== drivesClsid) diagnostics.add('gpo-preference-drives-root-invalid'); const items = directChildren(root, 'Drive'); const unsupportedScope = context.scope !== 'user'; const unsupportedRootChild = [...root.children].some(child => child.localName.toLocaleLowerCase('en-US') !== 'drive'); let partial = unsupportedScope || unsupportedRootChild; if (unsupportedScope) diagnostics.add('gpo-preference-drives-scope-unsupported'); if (unsupportedRootChild) diagnostics.add('gpo-preference-drive-item-unsupported'); const lines = itemLines(context.text); if (lines.length !== items.length) diagnostics.add('gpo-preference-line-provenance-invalid'); let invalid = diagnostics.has('gpo-preference-attribute-limit') || diagnostics.has('gpo-preference-drives-root-invalid') || diagnostics.has('gpo-preference-line-provenance-invalid') || diagnostics.has('gpo-preference-boolean-invalid'); const instructions: GppDriveMapInstruction[] = []; items.forEach((item, sequence) => { const before = diagnostics.size; const uid = canonicalGuid(attribute(item, 'uid')); if (!uid || canonicalGuid(attribute(item, 'clsid')) !== driveClsid) diagnostics.add('gpo-preference-drive-item-invalid'); const properties = directChildren(item, 'Properties'); const allowedItemChildren = [...item.children].every(child => ['properties', 'filters'].includes(child.localName.toLocaleLowerCase('en-US'))); if (properties.length !== 1 || !allowedItemChildren) diagnostics.add('gpo-preference-drive-item-invalid'); const props = properties[0]; const unsupportedShape = props && (props.children.length > 0 || [...props.attributes] .some(candidate => !allowedPropertyAttributes.has(candidate.localName.toLocaleLowerCase('en-US')))); if (unsupportedShape) { diagnostics.add('gpo-preference-drive-item-unsupported'); partial = true; return; } const operationValue = props ? operation(attribute(props, 'action')) : undefined; if (!operationValue) diagnostics.add('gpo-preference-action-invalid'); const removePolicy = booleanAttribute(item, 'removePolicy', diagnostics) ?? false; const applyOnce = booleanAttribute(item, 'applyOnce', diagnostics) ?? false; const itemDisabled = booleanAttribute(item, 'disabled', diagnostics) ?? false; const itemTargeting = context.summarizeTargeting(item, diagnostics); if (operationValue === 'delete' && removePolicy) diagnostics.add('gpo-preference-remove-policy-invalid'); const value = props && operationValue ? parseDriveValue(props, operationValue, diagnostics) : undefined; if (diagnostics.size !== before || !uid || !operationValue || !itemTargeting || !value) { invalid = true; return; } instructions.push({ version: 1, cse: 'drive-maps', uid, sequence, line: lines[sequence] ?? 1, operation: operationValue, disabled: rootDisabled || itemDisabled, removePolicy, applyOnce, targeting: itemTargeting, value }); }); if (diagnostics.has('gpo-preference-boolean-invalid') || diagnostics.has('gpo-preference-drive-visibility-invalid') || diagnostics.has('gpo-preference-drive-letter-invalid') || diagnostics.has('gpo-preference-drive-path-invalid') || diagnostics.has('gpo-preference-drive-user-invalid')) invalid = true; return { version: 1, parser: context.parser, sourcePath: context.sourcePath, sourceSha256: context.sourceSha256, scope: context.scope, preferenceType: 'drive-maps', status: invalid ? 'invalid' : partial ? 'partial' : 'complete', secretIndicatorStatus: context.secretIndicatorStatus, instructions: invalid || unsupportedScope ? [] : instructions, diagnosticCodes: [...diagnostics].sort() }; } export function reduceDriveMapsPreferences( document: DriveMapsPreferenceDocument, context: { backupInstanceId: string; sourceArtifactId: string; artifactId: string } ): GpoPolicyObservation[] { if (document.status === 'invalid' || document.scope !== 'user') return []; return document.instructions.map(instruction => { const id = `gpo-policy-${createHash('sha256').update([ context.backupInstanceId, context.artifactId, document.sourceSha256, instruction.uid, String(instruction.sequence), GPP_DRIVE_MAPS_REDUCER.version ].join('\0')).digest('hex').slice(0, 32)}`; const diagnostics = new Set(); if (instruction.targeting.status === 'present') diagnostics.add('gpo-preference-targeting-unevaluated'); if (instruction.value.passwordAttributePresent) diagnostics.add('gpo-secret-indicator-present'); const observation: GpoPolicyObservation = { version: 1, id, backupInstanceId: context.backupInstanceId, sourceArtifactId: context.sourceArtifactId, artifactId: context.artifactId, sourcePath: document.sourcePath, sourceSha256: document.sourceSha256, scope: 'user', deliveryMechanism: 'group-policy-preference', parser: document.parser, reducer: GPP_DRIVE_MAPS_REDUCER, identity: { status: 'unresolved', namespace: 'group-policy-preference', section: 'drive map', key: `${instruction.value.letter}:${instruction.value.selectionMode}` }, state: 'instruction', values: [instruction.value], preference: { cse: 'drive-maps', itemUid: instruction.uid, operation: instruction.operation, sequence: instruction.sequence, disabled: instruction.disabled, removePolicy: instruction.removePolicy, applyOnce: instruction.applyOnce, targeting: instruction.targeting }, sourceLines: [instruction.line], effectiveState: 'unknown', diagnosticCodes: [...diagnostics].sort() }; const errors = gpoPolicyObservationValidationErrors(observation); if (errors.length) throw new Error(`Intern ungültige Drive-Maps-Beobachtung: ${errors.join(' ')}`); return observation; }); }