@auth0/auth0-checkmate 1.6.16 → 1.6.17

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.
@@ -1,5 +1,9 @@
1
+ const fs = require("fs");
1
2
  const i18n = require("i18n");
3
+ const path = require("path");
2
4
  const _ = require("lodash");
5
+ const Handlebars = require("handlebars");
6
+ const puppeteer = require("puppeteer");
3
7
  const listOfAnalyser = require("./lib/listOfAnalyser");
4
8
  const {
5
9
  getAccessToken,
@@ -24,7 +28,31 @@ const {
24
28
 
25
29
  const logger = require("./lib/logger");
26
30
  const { getSummaryReport } = require("./tools/summary");
27
- const { convertToTitleCase, tranformReport } = require("./tools/utils");
31
+ const { convertToTitleCase, tranformReport, getToday } = require("./tools/utils");
32
+ const { version } = require("../package.json");
33
+
34
+ i18n.configure({
35
+ defaultLocale: "en",
36
+ objectNotation: true,
37
+ directory: path.join(__dirname, "../locales")
38
+ });
39
+
40
+ Handlebars.registerHelper("chooseFont", function (locale) {
41
+ if (locale === "ja") return "Noto Sans JP, sans-serif";
42
+ if (locale === "ko") return "Noto Sans KR, sans-serif";
43
+ return "DM Sans, sans-serif";
44
+ });
45
+ Handlebars.registerHelper("replace", function (str, search, replace) {
46
+ return str.replace(search, replace);
47
+ });
48
+ Handlebars.registerHelper("and", (a, b) => a && b);
49
+ Handlebars.registerHelper("inc", (a) => parseInt(a) + 1);
50
+
51
+ const templateData = fs.readFileSync(
52
+ path.join(__dirname, "../views/pdf_cli_report.handlebars"),
53
+ "utf8"
54
+ );
55
+
28
56
  async function runProductionChecks(tenant, validators) {
29
57
  try {
30
58
  logger.log("info", "Checking your configuration...");
@@ -170,7 +198,7 @@ async function generateReport(locale, tenantConfig, config) {
170
198
  cd.message = i18n.__(`checkEmailTemplates.${cd.field}`, cd.value);
171
199
  });
172
200
  break;
173
- case "checkErrorPageTemplate":
201
+ case "checkErrorPageTemplate":
174
202
  report.details.forEach((cd) => {
175
203
  cd.message = i18n.__(`checkErrorPageTemplate.${cd.field}`, cd.value);
176
204
  });
@@ -307,7 +335,7 @@ async function generateReport(locale, tenantConfig, config) {
307
335
  });
308
336
  });
309
337
  break;
310
- case "checkPasswordResetMFA":
338
+ case "checkPasswordResetMFA":
311
339
  case "checkPreRegistrationUserEnumeration":
312
340
  case "checkActionsHardCodedValues":
313
341
  case "checkDASHardCodedValues":
@@ -334,7 +362,7 @@ async function generateReport(locale, tenantConfig, config) {
334
362
  return `<li>${message}</li>`;
335
363
  }).join("\n");
336
364
  const dasTitle = i18n.__(`${report.name}.action_script_title`,
337
- scriptName);
365
+ scriptName);
338
366
  return `<p>${dasTitle}<p>\n<ul>\n${listItems}\n</ul>`;
339
367
  });
340
368
 
@@ -401,6 +429,84 @@ async function generateReport(locale, tenantConfig, config) {
401
429
  }
402
430
  }
403
431
 
432
+ async function generatePdfBuffer(report, auth0Domain, locale) {
433
+ locale = locale || "en";
434
+ const today = await getToday(locale);
435
+
436
+ const data = { report, auth0Domain, today, locale, version, config: {} };
437
+
438
+ const browser = await puppeteer.launch({
439
+ headless: true, // Run in headless mode
440
+ args: [
441
+ "--no-sandbox", // Disable the sandbox
442
+ "--disable-setuid-sandbox", // Disable setuid sandbox
443
+ ],
444
+ });
445
+
446
+ try {
447
+ const template = Handlebars.compile(templateData);
448
+ const htmlContent = template({
449
+ locale: data.locale,
450
+ data,
451
+ preamble: data.report.preamble,
452
+ });
453
+ const page = await browser.newPage();
454
+
455
+ // Disable JS execution in the Puppeteer page. Disabling
456
+ // JS eliminates the browser-side execution surface during PDF rendering.
457
+ await page.setJavaScriptEnabled(false);
458
+
459
+ // Allowlist only the CDN hostnames the template legitimately loads from
460
+ // (Bootstrap, Google Fonts). All other outbound requests — including RFC 1918
461
+ // addresses and cloud metadata endpoints — are aborted to prevent SSRF via
462
+ // passive resource loading (e.g. <img src="http://169.254.169.254/...">) in
463
+ // case tenant-controlled data ever reaches an unescaped template field.
464
+ await page.setRequestInterception(true);
465
+ page.on("request", (req) => {
466
+ const url = new URL(req.url());
467
+ const allowed = [
468
+ "fonts.googleapis.com",
469
+ "fonts.gstatic.com",
470
+ "cdn.jsdelivr.net",
471
+ ];
472
+ if (req.resourceType() === "document" || allowed.includes(url.hostname)) {
473
+ req.continue();
474
+ } else {
475
+ req.abort();
476
+ }
477
+ });
478
+
479
+ await page.setContent(htmlContent, { waitUntil: "networkidle2" });
480
+
481
+ const pdfResult = await page.pdf({
482
+ format: "A4",
483
+ printBackground: true,
484
+ displayHeaderFooter: true,
485
+ headerTemplate: `<div></div>`,
486
+ footerTemplate: `
487
+ <div style="font-size:10px; width:100%; padding:10px 0; display:flex; align-items:center; justify-content:space-between; border-top:1px solid #ddd;">
488
+ <span style="flex:1; text-align:center;">Confidential. For internal evaluation purposes only.</span>
489
+ <span style="flex:1; text-align:right; padding-right:20px;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></span>
490
+ </div>`,
491
+ margin: {
492
+ top: "20px",
493
+ bottom: "60px",
494
+ },
495
+ });
496
+ // Puppeteer v20+ returns Uint8Array, not Buffer. Express's res.send() calls
497
+ // Buffer.isBuffer() and JSON-serialises anything that fails the check,
498
+ // producing {"0":37,"1":80,...} instead of raw binary. Convert explicitly.
499
+
500
+ return Buffer.from(pdfResult);
501
+ } catch (error) {
502
+ logger.log("error", `Error generating PDF: ${error}`);
503
+ throw error;
504
+ } finally {
505
+ await browser.close();
506
+ }
507
+ }
508
+
404
509
  module.exports = {
405
510
  generateReport,
511
+ generatePdfBuffer,
406
512
  };
package/locales/en.json CHANGED
@@ -182,7 +182,7 @@
182
182
  },
183
183
  "no_custom_domains": "This tenant is not configured to use a custom domain. We recommend using custom domains with Universal Login for the most seamless and secure experience for end users. We also highly recommend using custom domains for passkey authentication, given they are tied to a specific domain during enrollment.",
184
184
  "ready": "This tenant is configured to use a custom domain. %s",
185
- "pending_verfification": "The tenant's custom domain configuration is incomplete, %s",
185
+ "pending_verification": "The tenant's custom domain configuration is incomplete, %s",
186
186
  "severity": "High",
187
187
  "status": "red",
188
188
  "severity_message": "Configure a Custom Domain",
@@ -1477,4 +1477,4 @@
1477
1477
  "https://auth0.com/docs/customize/events/event-testing-observability-and-failure-recovery"
1478
1478
  ]
1479
1479
  }
1480
- }
1480
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auth0/auth0-checkmate",
3
- "version": "1.6.16",
3
+ "version": "1.6.17",
4
4
  "description": "A command line tool for checking configuration of your Auth0 tenant",
5
5
  "main": "analyzer/report.js",
6
6
  "scripts": {