From d0d449e45110c030269269c62895836e92982c94 Mon Sep 17 00:00:00 2001 From: David Dworken Date: Fri, 2 May 2025 11:27:03 -0700 Subject: [PATCH 01/45] Add SRI (Subresource Integrity) hash to CDN script tags When include_plotlyjs='cdn', the generated HTML now includes an integrity attribute with a SHA256 hash of the bundled plotly.js content. This provides enhanced security by ensuring the browser verifies the integrity of the CDN-served file. - Added _generate_sri_hash() function to create SHA256 hashes - Modified CDN script tag generation to include integrity and crossorigin attributes - Added comprehensive tests to verify SRI functionality - Updated existing tests to account for new script tag format --- plotly/io/_html.py | 20 +++++++++-- tests/test_core/test_offline/test_offline.py | 2 +- tests/test_io/test_html.py | 36 ++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/plotly/io/_html.py b/plotly/io/_html.py index dbec1fc83b7..2bf7b12b156 100644 --- a/plotly/io/_html.py +++ b/plotly/io/_html.py @@ -1,6 +1,8 @@ import uuid from pathlib import Path import webbrowser +import hashlib +import base64 from _plotly_utils.optional_imports import get_module from plotly.io._utils import validate_coerce_fig_to_dict, plotly_cdn_url @@ -9,6 +11,14 @@ _json = get_module("json") +def _generate_sri_hash(content): + """Generate SHA256 hash for SRI (Subresource Integrity)""" + if isinstance(content, str): + content = content.encode('utf-8') + sha256_hash = hashlib.sha256(content).digest() + return 'sha256-' + base64.b64encode(sha256_hash).decode('utf-8') + + # Build script to set global PlotlyConfig object. This must execute before # plotly.js is loaded. _window_plotly_config = """\ @@ -252,11 +262,17 @@ def to_html( load_plotlyjs = "" if include_plotlyjs == "cdn": + # Generate SRI hash from the bundled plotly.js content + plotlyjs_content = get_plotlyjs() + sri_hash = _generate_sri_hash(plotlyjs_content) + load_plotlyjs = """\ {win_config} - \ + \ """.format( - win_config=_window_plotly_config, cdn_url=plotly_cdn_url() + win_config=_window_plotly_config, + cdn_url=plotly_cdn_url(), + integrity=sri_hash ) elif include_plotlyjs == "directory": diff --git a/tests/test_core/test_offline/test_offline.py b/tests/test_core/test_offline/test_offline.py index d0a9c80e1cb..afcf1f2e492 100644 --- a/tests/test_core/test_offline/test_offline.py +++ b/tests/test_core/test_offline/test_offline.py @@ -37,7 +37,7 @@ """ -cdn_script = ''.format( +cdn_script = '\n " ' ' + + '" integrity="sha256-oy6Be7Eh6eiQFs5M7oXuPxxm9qbJXEtTpfSI93dW16Q=" crossorigin="anonymous"> ' '
\n " ' ' + + '" integrity="sha256-oy6Be7Eh6eiQFs5M7oXuPxxm9qbJXEtTpfSI93dW16Q=" crossorigin="anonymous"> ' '
\ """.format( - win_config=_window_plotly_config, + win_config=_window_plotly_config, cdn_url=plotly_cdn_url(), - integrity=sri_hash + integrity=sri_hash, ) elif include_plotlyjs == "directory": diff --git a/tests/test_core/test_offline/test_offline.py b/tests/test_core/test_offline/test_offline.py index afcf1f2e492..53912ef45f2 100644 --- a/tests/test_core/test_offline/test_offline.py +++ b/tests/test_core/test_offline/test_offline.py @@ -37,9 +37,7 @@ """ -cdn_script = '\n " ' ' + + '" integrity="' + + sri_hash + + '" crossorigin="anonymous"> ' '
""" -cdn_script = '""" -cdn_script = ''.format(cdn_url=plotly_cdn_url(), js_hash=_generate_sri_hash(get_plotlyjs())) +cdn_script = ''.format( + cdn_url=plotly_cdn_url(), js_hash=_generate_sri_hash(get_plotlyjs()) +) directory_script = '' pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy