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