diff --git a/_config.yml b/_config.yml
index 531e3c622aea..4f3a456326da 100644
--- a/_config.yml
+++ b/_config.yml
@@ -418,6 +418,8 @@ enable_video_embedding: false # enables video embedding for bibtex entries. If f
# -----------------------------------------------------------------------------
# Add the url, version and integrity hash of the libraries you use in your site.
+# The integrity hash is used to ensure that the library is not tampered with.
+# Integrity hashes not provided by the libraries were generated using https://www.srihash.org/
third_party_libraries:
download: false # if true, download the versions of the libraries specified below and use the downloaded files
bootstrap-table:
@@ -429,6 +431,8 @@ third_party_libraries:
js: "https://cdn.jsdelivr.net/npm/bootstrap-table@{{version}}/dist/bootstrap-table.min.js"
version: "1.22.4"
chartjs:
+ integrity:
+ js: "sha256-0q+JdOlScWOHcunpUk21uab1jW7C1deBQARHtKMcaB4="
url:
js: "https://cdn.jsdelivr.net/npm/chart.js@{{version}}/dist/chart.umd.min.js"
version: "4.4.1"
@@ -476,9 +480,14 @@ third_party_libraries:
js: https://cdn.jsdelivr.net/npm/imagesloaded@{{version}}/imagesloaded.pkgd.min.js
version: "5.0.0"
img-comparison-slider:
+ integrity:
+ css: "sha256-3qTIuuUWIFnnU3LpQMjqiXc0p09rvd0dmj+WkpQXSR8="
+ js: "sha256-EXHg3x1K4oIWdyohPeKX2ZS++Wxt/FRPH7Nl01nat1o="
+ map: "sha256-3wfqS2WU5kGA/ePcgFzJXl5oSN1QsgZI4/edprTgX8w="
url:
css: "https://cdn.jsdelivr.net/npm/img-comparison-slider@{{version}}/dist/styles.min.css"
js: "https://cdn.jsdelivr.net/npm/img-comparison-slider@{{version}}/dist/index.min.js"
+ map: "https://cdn.jsdelivr.net/npm/img-comparison-slider@{{version}}/dist/index.js.map"
version: "8.0.6"
jquery:
integrity:
@@ -488,15 +497,20 @@ third_party_libraries:
version: "3.6.0"
leaflet:
integrity:
- css: "sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
- js: "sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
+ css: "sha256-q9ba7o845pMPFU+zcAll8rv+gC+fSovKsOoNQ6cynuQ="
+ js: "sha256-MgH13bFTTNqsnuEoqNPBLDaqxjGH+lCpqrukmXc8Ppg="
js_map: "sha256-YAoQ3FzREN4GmVENMir8vgHHypC0xfSK3CAxTHCqx1M="
+ local:
+ images: "images/"
url:
- css: "https://cdn.jsdelivr.net/npm/leaflet@{{version}}/dist/leaflet.css"
- js: "https://cdn.jsdelivr.net/npm/leaflet@{{version}}/dist/leaflet.js"
+ css: "https://cdn.jsdelivr.net/npm/leaflet@{{version}}/dist/leaflet.min.css"
+ images: "https://cdn.jsdelivr.net/npm/leaflet@{{version}}/dist/images/"
+ js: "https://cdn.jsdelivr.net/npm/leaflet@{{version}}/dist/leaflet.min.js"
js_map: "https://cdn.jsdelivr.net/npm/leaflet@{{version}}/dist/leaflet.js.map"
version: "1.9.4"
mathjax:
+ integrity:
+ js: "sha256-rjmgmaB99riUNcdlrDtcAiwtLIojSxNyUFdl+Qh+rB4="
local:
fonts: "output/chtml/fonts/woff-v2/"
url:
@@ -538,6 +552,9 @@ third_party_libraries:
js: "https://cdnjs.cloudflare.com/polyfill/v{{version}}/polyfill.min.js?features=es6"
version: "3"
pseudocode:
+ integrity:
+ css: "sha256-VwMV//xgBPDyRFVSOshhRhzJRDyBmIACniLPpeXNUdc="
+ js: "sha256-aVkDxqyzrB+ExUsOY9PdyelkDhn/DfrjWu08aVpqNlo="
url:
css: "https://cdn.jsdelivr.net/npm/pseudocode@{{version}}/build/pseudocode.min.css"
js: "https://cdn.jsdelivr.net/npm/pseudocode@{{version}}/build/pseudocode.min.js"
@@ -546,9 +563,11 @@ third_party_libraries:
integrity:
css: "sha256-yUoNxsvX+Vo8Trj3lZ/Y5ZBf8HlBFsB6Xwm7rH75/9E="
js: "sha256-BPrwikijIybg9OQC5SYFFqhBjERYOn97tCureFgYH1E="
+ map: "sha256-lbF5CsospW93otqvWOIbbhj80CjazrZXvamD7nC7TBI="
url:
css: "https://cdn.jsdelivr.net/npm/swiper@{{version}}/swiper-bundle.min.css"
js: "https://cdn.jsdelivr.net/npm/swiper@{{version}}/swiper-element-bundle.min.js"
+ map: "https://cdn.jsdelivr.net/npm/swiper@{{version}}/swiper-element-bundle.min.js.map"
version: "11.0.5"
swiper-map:
integrity:
diff --git a/_includes/head.liquid b/_includes/head.liquid
index fc316baec30d..b4f32b06ecce 100644
--- a/_includes/head.liquid
+++ b/_includes/head.liquid
@@ -52,6 +52,7 @@
defer
rel="stylesheet"
href="{{ site.third_party_libraries.pseudocode.url.css }}"
+ integrity="{{ site.third_party_libraries.pseudocode.integrity.css }}"
crossorigin="anonymous"
>
{% endif %}
@@ -127,6 +128,8 @@
defer
rel="stylesheet"
href="{{ site.third_party_libraries.img-comparison-slider.url.css }}"
+ integrity="{{ site.third_party_libraries.img-comparison-slider.integrity.css }}"
+ crossorigin="anonymous"
>
{% endif %}
diff --git a/_includes/scripts/chartjs.liquid b/_includes/scripts/chartjs.liquid
index c64bdd3dcf68..bb21be2292ee 100644
--- a/_includes/scripts/chartjs.liquid
+++ b/_includes/scripts/chartjs.liquid
@@ -1,5 +1,10 @@
{% if page.chart and page.chart.chartjs %}
-
+
+
{% endif %}
{% if page.images.slider %}
+
-
{% endunless %}
{% endif %}
diff --git a/_includes/scripts/pseudocode.liquid b/_includes/scripts/pseudocode.liquid
index 0db4ca897fde..5e9458b2559d 100644
--- a/_includes/scripts/pseudocode.liquid
+++ b/_includes/scripts/pseudocode.liquid
@@ -20,10 +20,14 @@
type="text/javascript"
id="MathJax-script"
src="{{ site.third_party_libraries.mathjax.url.js }}"
+ integrity="{{ site.third_party_libraries.mathjax.integrity.js }}"
+ crossorigin="anonymous"
>
+
{% endif %}
diff --git a/_plugins/download-3rd-party.rb b/_plugins/download-3rd-party.rb
index 12dd9ad7467a..30bc1c6f9edb 100644
--- a/_plugins/download-3rd-party.rb
+++ b/_plugins/download-3rd-party.rb
@@ -6,6 +6,54 @@
require 'open-uri'
require 'uri'
+ font_file_types = ['otf', 'ttf', 'woff', 'woff2']
+ image_file_types = ['.gif', '.jpg', '.jpeg', '.png', '.webp']
+
+ def download_and_change_rule_set_url(rule_set, rule, dest, dirname, config, file_types)
+ # check if the rule has a url
+ if rule_set[rule].include?('url(')
+ # get the file url
+ url = rule_set[rule].split('url(').last.split(')').first
+
+ # remove quotes from the url
+ if url.start_with?('"') || url.start_with?("'")
+ url = url[1..-2]
+ end
+
+ file_name = url.split('/').last.split('?').first
+
+ # verify if the file is of the correct type
+ if file_name.end_with?(*file_types)
+ # fix the url if it is not an absolute url
+ unless url.start_with?('https://')
+ url = URI.join(url, url).to_s
+ end
+
+ # download the file
+ download_file(url, File.join(dest, file_name))
+
+ # change the url to the local file, considering baseurl
+ previous_rule = rule_set[rule]
+ if config['baseurl']
+ # add rest of the src attribute if it exists
+ if rule_set[rule].split(' ').length > 1
+ rule_set[rule] = "url(#{File.join(config['baseurl'], 'assets', 'libs', dirname, file_name)}) #{rule_set[rule].split(' ').last}"
+ else
+ rule_set[rule] = "url(#{File.join(config['baseurl'], 'assets', 'libs', dirname, file_name)})"
+ end
+ else
+ # add rest of the src attribute if it exists
+ if rule_set[rule].split(' ').length > 1
+ rule_set[rule] = "url(#{File.join('/assets', 'libs', dirname, file_name)}) #{rule_set[rule].split(' ').last}"
+ else
+ rule_set[rule] = "url(#{File.join('/assets', 'libs', dirname, file_name)})"
+ end
+ end
+ puts "Changed #{previous_rule} to #{rule_set[rule]}"
+ end
+ end
+ end
+
def download_file(url, dest)
# only try to download the file if url doesn't start with | for security reasons
if url.start_with?('|')
@@ -34,7 +82,7 @@ def download_file(url, dest)
end
end
- def download_fonts(url, dest)
+ def download_fonts(url, dest, file_types)
# only try to download the file if url doesn't start with | for security reasons
if url.start_with?('|')
return
@@ -50,7 +98,7 @@ def download_fonts(url, dest)
file_name = link['href'].split('/').last.split('?').first
# verify if the file is a font file
- if file_name.end_with?('.woff', '.woff2', '.ttf', '.otf')
+ if file_name.end_with?(*file_types)
# download the file and change the url to the local file
download_file(URI.join(url, link['href']).to_s, File.join(dest, file_name))
end
@@ -58,7 +106,31 @@ def download_fonts(url, dest)
end
end
- def download_fonts_from_css(config, url, dest)
+ def download_images(url, dest, file_types)
+ # only try to download the file if url doesn't start with | for security reasons
+ if url.start_with?('|')
+ return
+ end
+
+ # only download images if the directory doesn't exist or is empty
+ unless File.directory?(dest) && !Dir.empty?(dest)
+ puts "Downloading images from #{url} to #{dest}"
+ # get available fonts from the url
+ doc = Nokogiri::HTML(URI.open(url, "User-Agent" => "Ruby/#{RUBY_VERSION}"))
+ doc.xpath('/html/body/div/div[3]/table/tbody/tr/td[1]/a').each do |link|
+ # get the file name from the url
+ file_name = link['href'].split('/').last.split('?').first
+
+ # verify if the file is a font file
+ if file_name.end_with?(*file_types)
+ # download the file and change the url to the local file
+ download_file(URI.join(url, link['href']).to_s, File.join(dest, file_name))
+ end
+ end
+ end
+ end
+
+ def download_fonts_from_css(config, url, dest, lib_name, file_types)
# only try to download the file if url doesn't start with | for security reasons
if url.start_with?('|')
return
@@ -83,48 +155,11 @@ def download_fonts_from_css(config, url, dest)
# get the font-face rules
css.each_rule_set do |rule_set|
# check if the rule set has a url
- if rule_set['src'].include?('url(')
- # get the font file url
- font_url = rule_set['src'].split('url(').last.split(')').first
-
- # remove quotes from the url
- if font_url.start_with?('"') || font_url.start_with?("'")
- font_url = font_url[1..-2]
- end
-
- font_file_name = font_url.split('/').last.split('?').first
-
- # verify if the file is a font file
- if font_file_name.end_with?('.woff', '.woff2', '.ttf', '.otf')
- # fix the font url if it is not an absolute url
- unless font_url.start_with?('https://')
- font_url = URI.join(url, font_url).to_s
- end
-
- # download the file
- download_file(font_url, File.join(dest, 'fonts', font_file_name))
-
- # change the font url to the local file, considering baseurl
- if config['baseurl']
- # add rest of the src attribute if it exists
- if rule_set['src'].split(' ').length > 1
- rule_set['src'] = "url(#{File.join(config['baseurl'], 'assets', 'libs', 'fonts', font_file_name)}) #{rule_set['src'].split(' ').last}"
- else
- rule_set['src'] = "url(#{File.join(config['baseurl'], 'assets', 'libs', 'fonts', font_file_name)})"
- end
- else
- # add rest of the src attribute if it exists
- if rule_set['src'].split(' ').length > 1
- rule_set['src'] = "url(#{File.join('/assets', 'libs', 'fonts', font_file_name)}) #{rule_set['src'].split(' ').last}"
- else
- rule_set['src'] = "url(#{File.join('/assets', 'libs', 'fonts', font_file_name)})"
- end
- end
- end
- end
+ download_and_change_rule_set_url(rule_set, 'src', File.join(dest, 'fonts'), File.join(lib_name, 'fonts'), config, file_types)
end
# save the modified css file
+ puts "Saving modified css file to #{File.join(dest, file_name)}"
File.write(File.join(dest, file_name), css.to_s)
end
@@ -164,13 +199,13 @@ def download_fonts_from_css(config, url, dest)
# get the file name from the url
file_name = url2.split('/').last.split('?').first
# download the file and change the url to the local file
- dest = File.join(site.source, 'assets', 'libs', file_name)
+ dest = File.join(site.source, 'assets', 'libs', key, file_name)
download_file(url2, dest)
# change the url to the local file, considering baseurl
if site.config['baseurl']
- site.config['third_party_libraries'][key]['url'][type][type2] = File.join(site.config['baseurl'], 'assets', 'libs', file_name)
+ site.config['third_party_libraries'][key]['url'][type][type2] = File.join(site.config['baseurl'], 'assets', 'libs', key, file_name)
else
- site.config['third_party_libraries'][key]['url'][type][type2] = File.join('/assets', 'libs', file_name)
+ site.config['third_party_libraries'][key]['url'][type][type2] = File.join('/assets', 'libs', key, file_name)
end
end
@@ -181,29 +216,33 @@ def download_fonts_from_css(config, url, dest)
if file_name.end_with?('css')
# if the file is a css file, download the css file, the fonts from it, and change information on the css file
- file_name = download_fonts_from_css(site.config, url, File.join(site.source, 'assets', 'libs'))
+ file_name = download_fonts_from_css(site.config, url, File.join(site.source, 'assets', 'libs', key), key, font_file_types)
# change the url to the local file, considering baseurl
if site.config['baseurl']
- site.config['third_party_libraries'][key]['url'][type] = File.join(site.config['baseurl'], 'assets', 'libs', file_name)
+ site.config['third_party_libraries'][key]['url'][type] = File.join(site.config['baseurl'], 'assets', 'libs', key, file_name)
else
- site.config['third_party_libraries'][key]['url'][type] = File.join('/assets', 'libs', file_name)
+ site.config['third_party_libraries'][key]['url'][type] = File.join('/assets', 'libs', key, file_name)
end
else
# download the font files and change the url to the local file
- download_fonts(url, File.join(site.source, 'assets', 'libs', site.config['third_party_libraries'][key]['local']['fonts']))
+ download_fonts(url, File.join(site.source, 'assets', 'libs', key, site.config['third_party_libraries'][key]['local'][type]), font_file_types)
end
+ elsif type == 'images'
+ # download the font files and change the url to the local file
+ download_images(url, File.join(site.source, 'assets', 'libs', key, site.config['third_party_libraries'][key]['local'][type]), image_file_types)
+
else
# get the file name from the url
file_name = url.split('/').last.split('?').first
# download the file and change the url to the local file
- dest = File.join(site.source, 'assets', 'libs', file_name)
+ dest = File.join(site.source, 'assets', 'libs', key, file_name)
download_file(url, dest)
# change the url to the local file, considering baseurl
if site.config['baseurl']
- site.config['third_party_libraries'][key]['url'][type] = File.join(site.config['baseurl'], 'assets', 'libs', file_name)
+ site.config['third_party_libraries'][key]['url'][type] = File.join(site.config['baseurl'], 'assets', 'libs', key, file_name)
else
- site.config['third_party_libraries'][key]['url'][type] = File.join('/assets', 'libs', file_name)
+ site.config['third_party_libraries'][key]['url'][type] = File.join('/assets', 'libs', key, file_name)
end
end
end