@mushi-mushi/web 1.7.7 → 1.7.8

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/index.cjs CHANGED
@@ -3660,18 +3660,18 @@ function createScreenshotCapture(options = {}) {
3660
3660
  const url = URL.createObjectURL(blob);
3661
3661
  return new Promise((resolve) => {
3662
3662
  img.onload = () => {
3663
- ctx.drawImage(img, 0, 0, width, height);
3664
- URL.revokeObjectURL(url);
3665
3663
  try {
3666
- const dataUrl = canvas.toDataURL("image/jpeg", 0.7);
3667
- resolve(dataUrl);
3664
+ ctx.drawImage(img, 0, 0, width, height);
3665
+ URL.revokeObjectURL(url);
3666
+ resolve(canvas.toDataURL("image/jpeg", 0.7));
3668
3667
  } catch {
3669
- resolve(null);
3668
+ URL.revokeObjectURL(url);
3669
+ resolve(buildDegradedScreenshot(width, height));
3670
3670
  }
3671
3671
  };
3672
3672
  img.onerror = () => {
3673
3673
  URL.revokeObjectURL(url);
3674
- resolve(null);
3674
+ resolve(buildDegradedScreenshot(width, height));
3675
3675
  };
3676
3676
  img.src = url;
3677
3677
  });
@@ -3693,6 +3693,7 @@ var DEFAULT_REDACT_SELECTORS = [
3693
3693
  function buildPrivacySafeDocument(privacy) {
3694
3694
  const clone = document.documentElement.cloneNode(true);
3695
3695
  clone.querySelector("#mushi-mushi-widget")?.remove();
3696
+ stripTaintSources(clone);
3696
3697
  const redactSelectors = privacy?.redactSelectors !== void 0 ? privacy.redactSelectors : DEFAULT_REDACT_SELECTORS;
3697
3698
  for (const selector of redactSelectors) {
3698
3699
  for (const el of safeQueryAll(clone, selector)) {
@@ -3731,6 +3732,46 @@ function redactElement(el) {
3731
3732
  el.setAttribute("data-mushi-redacted", "true");
3732
3733
  while (el.firstChild) el.removeChild(el.firstChild);
3733
3734
  }
3735
+ function stripTaintSources(root) {
3736
+ const pageOrigin = typeof location !== "undefined" ? location.origin : "";
3737
+ for (const el of root.querySelectorAll("img, video, iframe, object, embed, picture")) {
3738
+ el.remove();
3739
+ }
3740
+ for (const link of root.querySelectorAll('link[rel="stylesheet"], link[as="style"]')) {
3741
+ const href = link.getAttribute("href");
3742
+ if (!href || isCrossOriginUrl(href, pageOrigin)) link.remove();
3743
+ }
3744
+ for (const script of root.querySelectorAll("script")) {
3745
+ script.remove();
3746
+ }
3747
+ }
3748
+ function isCrossOriginUrl(raw, pageOrigin) {
3749
+ if (!raw || raw.startsWith("data:") || raw.startsWith("blob:")) return false;
3750
+ try {
3751
+ const resolved = new URL(raw, typeof location !== "undefined" ? location.href : "http://localhost/");
3752
+ return Boolean(pageOrigin) && resolved.origin !== pageOrigin;
3753
+ } catch {
3754
+ return true;
3755
+ }
3756
+ }
3757
+ function buildDegradedScreenshot(width, height) {
3758
+ const canvas = document.createElement("canvas");
3759
+ const ctx = canvas.getContext("2d");
3760
+ if (!ctx) return null;
3761
+ canvas.width = width;
3762
+ canvas.height = height;
3763
+ ctx.fillStyle = "#111827";
3764
+ ctx.fillRect(0, 0, width, height);
3765
+ ctx.fillStyle = "#e5e7eb";
3766
+ ctx.font = "13px system-ui, sans-serif";
3767
+ ctx.fillText("Screenshot: layout captured (external media stripped)", 16, 28);
3768
+ ctx.fillText(`${width}\xD7${height}px`, 16, 48);
3769
+ try {
3770
+ return canvas.toDataURL("image/jpeg", 0.7);
3771
+ } catch {
3772
+ return null;
3773
+ }
3774
+ }
3734
3775
  function maskElement(el) {
3735
3776
  if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
3736
3777
  el.value = "";