Initial
This commit is contained in:
66
server/services/detectionRuleService.js
Normal file
66
server/services/detectionRuleService.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// Generate a "software footprint" detection rule from simple inputs, in the
|
||||
// shape the deployment model already uses (`detectionType` + `detectionRule`).
|
||||
// MSI maps to a product-code rule; file/registry produce Intune-style custom
|
||||
// PowerShell detection scripts so they flow straight through publishing without
|
||||
// extra mapping. Pure + unit-tested.
|
||||
|
||||
function fileDetectionScript({ path, version }) {
|
||||
const lines = [`$path = '${path.replace(/'/g, "''")}'`, 'if (Test-Path -LiteralPath $path) {'];
|
||||
if (version) {
|
||||
lines.push(" $found = (Get-Item -LiteralPath $path).VersionInfo.ProductVersion");
|
||||
lines.push(` if ($found -and [version]$found -ge [version]'${version}') { Write-Output 'Detected'; exit 0 }`);
|
||||
} else {
|
||||
lines.push(" Write-Output 'Detected'; exit 0");
|
||||
}
|
||||
lines.push('}');
|
||||
lines.push('exit 1');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function registryDetectionScript({ keyPath, valueName, valueData }) {
|
||||
const key = keyPath.replace(/'/g, "''");
|
||||
const lines = [`$key = '${key}'`];
|
||||
if (valueName) {
|
||||
lines.push("$value = (Get-ItemProperty -LiteralPath $key -ErrorAction SilentlyContinue).'" + valueName.replace(/'/g, "''") + "'");
|
||||
if (valueData) {
|
||||
lines.push(`if ($value -eq '${valueData.replace(/'/g, "''")}') { Write-Output 'Detected'; exit 0 }`);
|
||||
} else {
|
||||
lines.push("if ($null -ne $value) { Write-Output 'Detected'; exit 0 }");
|
||||
}
|
||||
} else {
|
||||
lines.push("if (Test-Path -LiteralPath $key) { Write-Output 'Detected'; exit 0 }");
|
||||
}
|
||||
lines.push('exit 1');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
export function buildDetectionRule(input = {}) {
|
||||
switch (input.type) {
|
||||
case 'msi': {
|
||||
if (!input.productCode) throw new Error('productCode is required for MSI detection');
|
||||
return {
|
||||
detectionType: 'msi-product-code',
|
||||
detectionRule: input.productCode,
|
||||
description: `MSI product code ${input.productCode}`
|
||||
};
|
||||
}
|
||||
case 'file': {
|
||||
if (!input.path) throw new Error('path is required for file detection');
|
||||
return {
|
||||
detectionType: 'custom-script',
|
||||
detectionRule: fileDetectionScript(input),
|
||||
description: input.version ? `File ${input.path} version ≥ ${input.version}` : `File exists: ${input.path}`
|
||||
};
|
||||
}
|
||||
case 'registry': {
|
||||
if (!input.keyPath) throw new Error('keyPath is required for registry detection');
|
||||
return {
|
||||
detectionType: 'custom-script',
|
||||
detectionRule: registryDetectionScript(input),
|
||||
description: input.valueName ? `Registry ${input.keyPath}\\${input.valueName}` : `Registry key ${input.keyPath}`
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown detection type "${input.type}" (expected msi, file, or registry)`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user