@trops/dash-core 0.1.231 → 0.1.233
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/electron/index.js +116 -55
- package/dist/electron/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -32248,7 +32248,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
|
|
|
32248
32248
|
|
|
32249
32249
|
const contentType = response.headers.get("content-type") || "";
|
|
32250
32250
|
const arrayBuffer = await response.arrayBuffer();
|
|
32251
|
-
|
|
32251
|
+
let zipBuffer = Buffer.from(arrayBuffer);
|
|
32252
32252
|
console.log(`${TAG} [3/5 Download] size=${zipBuffer.length} bytes`);
|
|
32253
32253
|
|
|
32254
32254
|
if (zipBuffer.length === 0) {
|
|
@@ -32258,74 +32258,135 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
|
|
|
32258
32258
|
};
|
|
32259
32259
|
}
|
|
32260
32260
|
|
|
32261
|
-
//
|
|
32262
|
-
if (
|
|
32263
|
-
contentType.includes("text/html") ||
|
|
32264
|
-
contentType.includes("application/json")
|
|
32265
|
-
) {
|
|
32261
|
+
// Reject HTML error pages
|
|
32262
|
+
if (contentType.includes("text/html")) {
|
|
32266
32263
|
const body = zipBuffer.toString("utf-8").slice(0, 200);
|
|
32267
|
-
console.log(
|
|
32268
|
-
`${TAG} [3/5 Download] FAIL — unexpected content type "${contentType}": ${body}`,
|
|
32269
|
-
);
|
|
32264
|
+
console.log(`${TAG} [3/5 Download] FAIL — HTML response: ${body}`);
|
|
32270
32265
|
return {
|
|
32271
32266
|
success: false,
|
|
32272
|
-
error: `Download failed: registry returned
|
|
32267
|
+
error: `Download failed: registry returned an HTML page instead of theme data.`,
|
|
32273
32268
|
};
|
|
32274
32269
|
}
|
|
32275
32270
|
|
|
32276
|
-
// Stage 4: ZIP
|
|
32277
|
-
let
|
|
32278
|
-
|
|
32279
|
-
|
|
32280
|
-
|
|
32271
|
+
// Stage 4: Extract theme data (JSON or ZIP)
|
|
32272
|
+
let themeData;
|
|
32273
|
+
|
|
32274
|
+
if (contentType.includes("application/json")) {
|
|
32275
|
+
// Registry returns JSON with a downloadUrl pointing to the actual ZIP
|
|
32281
32276
|
console.log(
|
|
32282
|
-
`${TAG} [
|
|
32277
|
+
`${TAG} [3/5 Download] JSON response — checking for downloadUrl`,
|
|
32283
32278
|
);
|
|
32284
|
-
|
|
32285
|
-
|
|
32286
|
-
|
|
32287
|
-
}
|
|
32279
|
+
let jsonData;
|
|
32280
|
+
try {
|
|
32281
|
+
jsonData = JSON.parse(zipBuffer.toString("utf-8"));
|
|
32282
|
+
} catch (parseErr) {
|
|
32283
|
+
return {
|
|
32284
|
+
success: false,
|
|
32285
|
+
error: `Download failed: registry returned invalid JSON (${parseErr.message}).`,
|
|
32286
|
+
};
|
|
32287
|
+
}
|
|
32288
|
+
if (jsonData.error) {
|
|
32289
|
+
console.log(
|
|
32290
|
+
`${TAG} [3/5 Download] FAIL — JSON error: ${jsonData.error}`,
|
|
32291
|
+
);
|
|
32292
|
+
return {
|
|
32293
|
+
success: false,
|
|
32294
|
+
error: `Download failed: ${jsonData.error}`,
|
|
32295
|
+
};
|
|
32296
|
+
}
|
|
32297
|
+
if (jsonData.downloadUrl) {
|
|
32298
|
+
// Follow the pre-signed URL to get the actual ZIP
|
|
32299
|
+
console.log(`${TAG} [3/5 Download] following downloadUrl to fetch ZIP`);
|
|
32300
|
+
let zipResponse;
|
|
32301
|
+
try {
|
|
32302
|
+
zipResponse = await fetch(jsonData.downloadUrl);
|
|
32303
|
+
} catch (fetchErr) {
|
|
32304
|
+
return {
|
|
32305
|
+
success: false,
|
|
32306
|
+
error: `Download failed: could not fetch ZIP from storage (${fetchErr.message}).`,
|
|
32307
|
+
};
|
|
32308
|
+
}
|
|
32309
|
+
if (!zipResponse.ok) {
|
|
32310
|
+
return {
|
|
32311
|
+
success: false,
|
|
32312
|
+
error: `Download failed: storage returned ${zipResponse.status} ${zipResponse.statusText}`,
|
|
32313
|
+
};
|
|
32314
|
+
}
|
|
32315
|
+
const zipArrayBuffer = await zipResponse.arrayBuffer();
|
|
32316
|
+
zipBuffer = Buffer.from(zipArrayBuffer);
|
|
32317
|
+
console.log(
|
|
32318
|
+
`${TAG} [3/5 Download] ZIP fetched, size=${zipBuffer.length} bytes`,
|
|
32319
|
+
);
|
|
32320
|
+
if (zipBuffer.length === 0) {
|
|
32321
|
+
return {
|
|
32322
|
+
success: false,
|
|
32323
|
+
error: "Download failed: storage returned an empty ZIP file.",
|
|
32324
|
+
};
|
|
32325
|
+
}
|
|
32326
|
+
} else {
|
|
32327
|
+
// No downloadUrl — treat as direct theme data
|
|
32328
|
+
console.log(
|
|
32329
|
+
`${TAG} [4/5 Extract] JSON response with no downloadUrl — using as theme data`,
|
|
32330
|
+
);
|
|
32331
|
+
themeData = jsonData.data || jsonData.theme || jsonData;
|
|
32332
|
+
}
|
|
32288
32333
|
}
|
|
32289
|
-
const entries = zip.getEntries();
|
|
32290
|
-
const entryNames = entries.map((e) => e.entryName);
|
|
32291
|
-
const themeEntry = entries.find((entry) =>
|
|
32292
|
-
entry.entryName.endsWith(".theme.json"),
|
|
32293
|
-
);
|
|
32294
|
-
console.log(
|
|
32295
|
-
`${TAG} [4/5 ZIP Extraction] files=[${entryNames.join(", ")}] hasThemeJson=${!!themeEntry}`,
|
|
32296
|
-
);
|
|
32297
32334
|
|
|
32298
|
-
if (!
|
|
32335
|
+
if (!themeData) {
|
|
32336
|
+
// ZIP response — extract .theme.json from archive
|
|
32337
|
+
let zip;
|
|
32338
|
+
try {
|
|
32339
|
+
zip = new AdmZip$1(zipBuffer);
|
|
32340
|
+
} catch (zipErr) {
|
|
32341
|
+
console.log(
|
|
32342
|
+
`${TAG} [4/5 ZIP Extraction] FAIL — invalid ZIP: ${zipErr.message}`,
|
|
32343
|
+
);
|
|
32344
|
+
return {
|
|
32345
|
+
success: false,
|
|
32346
|
+
error: `ZIP extraction failed: the downloaded file is not a valid ZIP archive (${zipErr.message}).`,
|
|
32347
|
+
};
|
|
32348
|
+
}
|
|
32349
|
+
const entries = zip.getEntries();
|
|
32350
|
+
const entryNames = entries.map((e) => e.entryName);
|
|
32351
|
+
const themeEntry = entries.find((entry) =>
|
|
32352
|
+
entry.entryName.endsWith(".theme.json"),
|
|
32353
|
+
);
|
|
32299
32354
|
console.log(
|
|
32300
|
-
`${TAG} [4/5 ZIP Extraction]
|
|
32355
|
+
`${TAG} [4/5 ZIP Extraction] files=[${entryNames.join(", ")}] hasThemeJson=${!!themeEntry}`,
|
|
32301
32356
|
);
|
|
32302
|
-
return {
|
|
32303
|
-
success: false,
|
|
32304
|
-
error: `ZIP extraction failed: no .theme.json file found in archive. Files present: [${entryNames.join(", ")}]`,
|
|
32305
|
-
};
|
|
32306
|
-
}
|
|
32307
32357
|
|
|
32308
|
-
|
|
32309
|
-
|
|
32310
|
-
|
|
32311
|
-
|
|
32312
|
-
|
|
32313
|
-
|
|
32314
|
-
|
|
32315
|
-
|
|
32316
|
-
}
|
|
32317
|
-
}
|
|
32358
|
+
if (!themeEntry) {
|
|
32359
|
+
console.log(
|
|
32360
|
+
`${TAG} [4/5 ZIP Extraction] FAIL — no .theme.json in archive`,
|
|
32361
|
+
);
|
|
32362
|
+
return {
|
|
32363
|
+
success: false,
|
|
32364
|
+
error: `ZIP extraction failed: no .theme.json file found in archive. Files present: [${entryNames.join(", ")}]`,
|
|
32365
|
+
};
|
|
32366
|
+
}
|
|
32318
32367
|
|
|
32319
|
-
|
|
32320
|
-
|
|
32321
|
-
|
|
32322
|
-
|
|
32323
|
-
|
|
32324
|
-
|
|
32325
|
-
|
|
32326
|
-
|
|
32327
|
-
|
|
32328
|
-
|
|
32368
|
+
// Validate entry path (security: prevent path traversal)
|
|
32369
|
+
if (
|
|
32370
|
+
themeEntry.entryName.includes("..") ||
|
|
32371
|
+
path$2.isAbsolute(themeEntry.entryName)
|
|
32372
|
+
) {
|
|
32373
|
+
return {
|
|
32374
|
+
success: false,
|
|
32375
|
+
error:
|
|
32376
|
+
"ZIP extraction failed: invalid file path detected in archive.",
|
|
32377
|
+
};
|
|
32378
|
+
}
|
|
32379
|
+
|
|
32380
|
+
// Parse theme data from ZIP entry
|
|
32381
|
+
const themeJson = themeEntry.getData().toString("utf-8");
|
|
32382
|
+
try {
|
|
32383
|
+
themeData = JSON.parse(themeJson);
|
|
32384
|
+
} catch (parseErr) {
|
|
32385
|
+
return {
|
|
32386
|
+
success: false,
|
|
32387
|
+
error: `ZIP extraction failed: ${themeEntry.entryName} contains invalid JSON (${parseErr.message}).`,
|
|
32388
|
+
};
|
|
32389
|
+
}
|
|
32329
32390
|
}
|
|
32330
32391
|
|
|
32331
32392
|
// Add registry metadata
|