niklasvh / html2canvas

Screenshots with JavaScript
https://html2canvas.hertzen.com/
MIT License
30.27k stars 4.77k forks source link

Problem rendering inline (CSP-protected, nonced) style in Firefox #2760

Open egaillot opened 2 years ago

egaillot commented 2 years ago

Hi,

I'm struggling with an issue that seems to appear only with Firefox (tested on Firefox v95.0b12). I want to render in a PDF a bar of variable width, depending on some value computed by the server. The response has a Content-Security-Policy with a style-src directive set to 'self' 'nonce-XXX'. I use an inline style with that nonce to specify the width of that bar.

When I display the bar in the web page, it works fine. However, when I want to render it as an image through html2canvas, the inline style is blocked in Firefox (as indicated in the web console). The rendering works fine with Safari v15.0 and Chrome v95.0.4638.54. I'm on MacOS Catalina 10.15.7.

Here's a piece of code that I used to reproduce the problem:

index.html :

<!DOCTYPE html>

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'nonce-12345'; script-src 'strict-dynamic' 'nonce-12345'">

<link href="./bars.css" rel="stylesheet">
<script nonce="12345" src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script nonce="12345" src="https://unpkg.com/dompurify/dist/purify.js"></script>
<script nonce="12345" src="https://unpkg.com/html2canvas/dist/html2canvas.js"></script>
<script nonce="12345" src="https://unpkg.com/jspdf@latest/dist/jspdf.umd.js"></script>

<div class="wrapper">
  <div class="bar"></div>
  <style nonce="12345">
    #partial-bar {
      width: 40%;
    }
  </style>
  <div class="partial-bar" id="partial-bar"></div>
</div>

<script nonce="12345">
$(() => {
  html2canvas($('.wrapper')[0])
    .then((canvas) => {
      const img = canvas.toDataURL('image/jpeg');
      const pdf = new jspdf.jsPDF();
      pdf.addImage(img, 'JPEG', 10, 10);
      pdf.save('bars.pdf');
    });
});
</script>

bars.css

.wrapper {
  position: relative;
  display: block;
  width: 100px;
  height: 20px;
}

.wrapper > * {
  position: absolute;
  height: 100%;
}

.bar {
  width: 100%;
  background: #0055aa;
}

.partial-bar {
  background: #55aa55;
}

Any idea what is going on?

chrisphillers commented 2 years ago

I am encountering the exact same issue - it looks like html2canvas doesn't work with nonces.

egaillot commented 2 years ago

it looks like html2canvas doesn't work with nonces.

Well, it works with nonces on Safari & Chrome…

chrisphillers commented 2 years ago

it looks like html2canvas doesn't work with nonces.

Well, it works with nonces on Safari & Chrome…

True - but how do you pass in a nonce prop? Im not sure how it is dealing with nonces on Chrome/FF if you cant pass it a prop.

egaillot commented 2 years ago

@chrisphillers – Not sure I understand your question… 😓

I can (and do) pass the nonce in the following fashion: <style nonce="…">. If I specify the CSP style-src directive to 'self' 'nonce-XXX' and don't pass the nonce property in the style tag, then it doesn't work (as expected) on Chrome and Safari.