Skip to content

Commit 7443631

Browse files
authored
fix(release): validate Windows icon before packaging (#30)
Adds an early ICO validation guard and ships a production Windows icon with a 256x256 frame.
1 parent 7379bbc commit 7443631

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

assets/prod/okcode-windows.ico

278 KB
Binary file not shown.

scripts/build-desktop-artifact.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,42 @@ function stageLinuxIcons(stageResourcesDir: string) {
349349
});
350350
}
351351

352+
function icoContains256Frame(bytes: Uint8Array): boolean {
353+
if (bytes.byteLength < 6) {
354+
return false;
355+
}
356+
357+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
358+
const reserved = view.getUint16(0, true);
359+
const imageType = view.getUint16(2, true);
360+
const imageCount = view.getUint16(4, true);
361+
362+
if (reserved !== 0 || imageType !== 1 || imageCount <= 0) {
363+
return false;
364+
}
365+
366+
const directoryEnd = 6 + imageCount * 16;
367+
if (directoryEnd > bytes.byteLength) {
368+
return false;
369+
}
370+
371+
for (let index = 0; index < imageCount; index += 1) {
372+
const entryOffset = 6 + index * 16;
373+
const widthRaw = bytes[entryOffset];
374+
const heightRaw = bytes[entryOffset + 1];
375+
if (widthRaw === undefined || heightRaw === undefined) {
376+
return false;
377+
}
378+
const width = widthRaw === 0 ? 256 : widthRaw;
379+
const height = heightRaw === 0 ? 256 : heightRaw;
380+
if (width >= 256 && height >= 256) {
381+
return true;
382+
}
383+
}
384+
385+
return false;
386+
}
387+
352388
function stageWindowsIcons(stageResourcesDir: string) {
353389
return Effect.gen(function* () {
354390
const fs = yield* FileSystem.FileSystem;
@@ -360,6 +396,16 @@ function stageWindowsIcons(stageResourcesDir: string) {
360396
});
361397
}
362398

399+
const iconBytes = yield* fs.readFile(iconSource);
400+
if (!icoContains256Frame(iconBytes)) {
401+
return yield* new BuildScriptError({
402+
message:
403+
`Production Windows icon at ${iconSource} must include a 256x256 frame. ` +
404+
`Regenerate ${BRAND_ASSET_PATHS.productionWindowsIconIco} with multi-size ICO entries ` +
405+
`(for example 16,32,48,64,128,256) before packaging.`,
406+
});
407+
}
408+
363409
const iconPath = path.join(stageResourcesDir, "icon.ico");
364410
yield* fs.copyFile(iconSource, iconPath);
365411
});

0 commit comments

Comments
 (0)