108 lines
3.9 KiB
JavaScript
108 lines
3.9 KiB
JavaScript
import './setup.mjs';
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { load } from './setup.mjs';
|
|
|
|
const { parseIntunewin } = await load('../services/intunewinParser.js');
|
|
|
|
// --- Minimal stored-method (no compression) ZIP builder for fixtures --------
|
|
|
|
function crc32(buf) {
|
|
let crc = 0xffffffff;
|
|
for (let i = 0; i < buf.length; i++) {
|
|
crc ^= buf[i];
|
|
for (let j = 0; j < 8; j++) crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
|
|
}
|
|
return (crc ^ 0xffffffff) >>> 0;
|
|
}
|
|
|
|
function makeStoredZip(entries) {
|
|
const locals = [];
|
|
const centrals = [];
|
|
let offset = 0;
|
|
for (const { name, data } of entries) {
|
|
const nameBuf = Buffer.from(name, 'utf8');
|
|
const crc = crc32(data);
|
|
const local = Buffer.alloc(30);
|
|
local.writeUInt32LE(0x04034b50, 0);
|
|
local.writeUInt16LE(20, 4);
|
|
local.writeUInt16LE(0, 8); // method = stored
|
|
local.writeUInt32LE(crc, 14);
|
|
local.writeUInt32LE(data.length, 18);
|
|
local.writeUInt32LE(data.length, 22);
|
|
local.writeUInt16LE(nameBuf.length, 26);
|
|
const localRecord = Buffer.concat([local, nameBuf, data]);
|
|
|
|
const central = Buffer.alloc(46);
|
|
central.writeUInt32LE(0x02014b50, 0);
|
|
central.writeUInt16LE(20, 4);
|
|
central.writeUInt16LE(20, 6);
|
|
central.writeUInt16LE(0, 10); // method = stored
|
|
central.writeUInt32LE(crc, 16);
|
|
central.writeUInt32LE(data.length, 20);
|
|
central.writeUInt32LE(data.length, 24);
|
|
central.writeUInt16LE(nameBuf.length, 28);
|
|
central.writeUInt32LE(offset, 42);
|
|
centrals.push(Buffer.concat([central, nameBuf]));
|
|
|
|
locals.push(localRecord);
|
|
offset += localRecord.length;
|
|
}
|
|
const cd = Buffer.concat(centrals);
|
|
const localsBuf = Buffer.concat(locals);
|
|
const eocd = Buffer.alloc(22);
|
|
eocd.writeUInt32LE(0x06054b50, 0);
|
|
eocd.writeUInt16LE(entries.length, 8);
|
|
eocd.writeUInt16LE(entries.length, 10);
|
|
eocd.writeUInt32LE(cd.length, 12);
|
|
eocd.writeUInt32LE(localsBuf.length, 16);
|
|
return Buffer.concat([localsBuf, cd, eocd]);
|
|
}
|
|
|
|
const detectionXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
<ApplicationInfo ToolVersion="1.8.6">
|
|
<Name>Contoso VPN</Name>
|
|
<UnencryptedContentSize>2048</UnencryptedContentSize>
|
|
<FileName>IntunePackage.intunewin</FileName>
|
|
<SetupFile>ContosoVpnSetup.exe</SetupFile>
|
|
<EncryptionInfo>
|
|
<EncryptionKey>QUJDRA==</EncryptionKey>
|
|
<MacKey>RUZHSA==</MacKey>
|
|
<InitializationVector>SUpLTA==</InitializationVector>
|
|
<Mac>TU5PUA==</Mac>
|
|
<ProfileIdentifier>ProfileVersion1</ProfileIdentifier>
|
|
<FileDigest>UVJTVA==</FileDigest>
|
|
<FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
|
|
</EncryptionInfo>
|
|
</ApplicationInfo>`;
|
|
|
|
const encryptedPayload = Buffer.from('this-stands-in-for-the-encrypted-intunewin-bytes');
|
|
|
|
const fixture = makeStoredZip([
|
|
{ name: 'IntuneWinPackage/Metadata/Detection.xml', data: Buffer.from(detectionXml, 'utf8') },
|
|
{ name: 'IntuneWinPackage/Contents/IntunePackage.intunewin', data: encryptedPayload }
|
|
]);
|
|
|
|
test('parses setup file, sizes, and encrypted payload', () => {
|
|
const parsed = parseIntunewin(fixture);
|
|
assert.equal(parsed.setupFile, 'ContosoVpnSetup.exe');
|
|
assert.equal(parsed.unencryptedContentSize, 2048);
|
|
assert.equal(parsed.encryptedContentSize, encryptedPayload.length);
|
|
assert.ok(parsed.encryptedContent.equals(encryptedPayload));
|
|
});
|
|
|
|
test('maps EncryptionInfo to Graph fileEncryptionInfo', () => {
|
|
const { fileEncryptionInfo } = parseIntunewin(fixture);
|
|
assert.equal(fileEncryptionInfo.encryptionKey, 'QUJDRA==');
|
|
assert.equal(fileEncryptionInfo.macKey, 'RUZHSA==');
|
|
assert.equal(fileEncryptionInfo.initializationVector, 'SUpLTA==');
|
|
assert.equal(fileEncryptionInfo.mac, 'TU5PUA==');
|
|
assert.equal(fileEncryptionInfo.profileIdentifier, 'ProfileVersion1');
|
|
assert.equal(fileEncryptionInfo.fileDigest, 'UVJTVA==');
|
|
assert.equal(fileEncryptionInfo.fileDigestAlgorithm, 'SHA256');
|
|
});
|
|
|
|
test('rejects a non-.intunewin buffer', () => {
|
|
assert.throws(() => parseIntunewin(Buffer.from('not a zip at all')));
|
|
});
|