240 lines
8.6 KiB
Bash
Executable File
240 lines
8.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# =====================================================================
|
|
# update-csp-hashes.sh - Update Content Security Policy hashes
|
|
# =====================================================================
|
|
# This script updates the CSP hashes for:
|
|
# 1. All JavaScript and CSS files
|
|
# 2. All inline style attributes in HTML files
|
|
# 3. Adds CSP meta tags to HTML files
|
|
# After running this script, restart the server using:
|
|
# ./caddy.sh
|
|
# =====================================================================
|
|
|
|
set -e
|
|
|
|
echo "Updating CSP hashes for all JavaScript, CSS files, and inline styles..."
|
|
|
|
# Directory containing the files
|
|
BASE_DIR="$(pwd)"
|
|
# Check if we're in a Docker environment
|
|
if [ -f "/etc/caddy/Caddyfile" ]; then
|
|
CADDYFILE="/etc/caddy/Caddyfile"
|
|
else
|
|
CADDYFILE="$BASE_DIR/Caddyfile"
|
|
fi
|
|
TEMP_INLINE_HASHES_FILE=$(mktemp)
|
|
|
|
# Arrays to store hashes
|
|
SCRIPT_HASHES=()
|
|
STYLE_HASHES=()
|
|
|
|
# Calculate hash for a file
|
|
calculate_hash() {
|
|
local file=$1
|
|
sha256sum "$file" | awk '{print $1}' | xxd -r -p | base64
|
|
}
|
|
|
|
# Calculate hash for inline style
|
|
calculate_inline_hash() {
|
|
local style_content=$1
|
|
echo -n "$style_content" | sha256sum | awk '{print $1}' | xxd -r -p | base64
|
|
}
|
|
|
|
# Process JavaScript files
|
|
echo "Processing JavaScript files..."
|
|
for js_file in $(find "$BASE_DIR" -name "*.js" -type f); do
|
|
echo "Processing $js_file"
|
|
file_name=$(basename "$js_file")
|
|
hash=$(calculate_hash "$js_file")
|
|
SCRIPT_HASHES+=("'sha256-$hash'")
|
|
|
|
# Update HTML files that reference this JS file
|
|
for html_file in $(find "$BASE_DIR" -name "*.html" -type f); do
|
|
if grep -q "$file_name" "$html_file"; then
|
|
echo "Updating $file_name in $html_file"
|
|
|
|
# Create a temporary file for the replacement
|
|
tmp_file=$(mktemp)
|
|
|
|
# For files with existing integrity attribute
|
|
if grep -q "$file_name.*integrity" "$html_file"; then
|
|
# Use awk for safer text processing
|
|
awk -v fname="$file_name" -v newhash="$hash" '
|
|
{
|
|
if ($0 ~ fname && $0 ~ /integrity/) {
|
|
gsub(/integrity="sha256-[^"]*"/, "integrity=\"sha256-" newhash "\"");
|
|
}
|
|
print;
|
|
}' "$html_file" > "$tmp_file"
|
|
else
|
|
# Add integrity attribute if it doesn't exist
|
|
awk -v fname="$file_name" -v newhash="$hash" '
|
|
{
|
|
if ($0 ~ fname && $0 ~ /src/ && !($0 ~ /integrity/)) {
|
|
gsub(/src="[^"]*"/, "&" " integrity=\"sha256-" newhash "\"");
|
|
}
|
|
print;
|
|
}' "$html_file" > "$tmp_file"
|
|
fi
|
|
|
|
# Replace original file with modified content
|
|
mv "$tmp_file" "$html_file"
|
|
fi
|
|
done
|
|
done
|
|
|
|
# Process CSS files
|
|
echo "Processing CSS files..."
|
|
for css_file in $(find "$BASE_DIR" -name "*.css" -type f); do
|
|
echo "Processing $css_file"
|
|
file_name=$(basename "$css_file")
|
|
hash=$(calculate_hash "$css_file")
|
|
STYLE_HASHES+=("'sha256-$hash'")
|
|
|
|
# Update HTML files that reference this CSS file
|
|
for html_file in $(find "$BASE_DIR" -name "*.html" -type f); do
|
|
if grep -q "$file_name" "$html_file"; then
|
|
echo "Updating $file_name in $html_file"
|
|
|
|
# Create a temporary file for the replacement
|
|
tmp_file=$(mktemp)
|
|
|
|
# For files with existing integrity attribute
|
|
if grep -q "$file_name.*integrity" "$html_file"; then
|
|
# Use awk for safer text processing
|
|
awk -v fname="$file_name" -v newhash="$hash" '
|
|
{
|
|
if ($0 ~ fname && $0 ~ /integrity/) {
|
|
gsub(/integrity="sha256-[^"]*"/, "integrity=\"sha256-" newhash "\"");
|
|
}
|
|
print;
|
|
}' "$html_file" > "$tmp_file"
|
|
else
|
|
# Add integrity attribute if it doesn't exist
|
|
awk -v fname="$file_name" -v newhash="$hash" '
|
|
{
|
|
if ($0 ~ fname && $0 ~ /href/ && !($0 ~ /integrity/)) {
|
|
gsub(/href="[^"]*"/, "&" " integrity=\"sha256-" newhash "\"");
|
|
}
|
|
print;
|
|
}' "$html_file" > "$tmp_file"
|
|
fi
|
|
|
|
# Replace original file with modified content
|
|
mv "$tmp_file" "$html_file"
|
|
fi
|
|
done
|
|
done
|
|
|
|
# Find and process inline styles - using a more thorough approach
|
|
echo "Processing HTML files for inline styles..."
|
|
find "$BASE_DIR" -name "*.html" -type f | while read -r html_file; do
|
|
echo "Processing $html_file for inline styles..."
|
|
|
|
# Use a more comprehensive grep pattern to catch all inline styles
|
|
# This includes both style="..." and style = "..." patterns
|
|
grep -o 'style\s*=\s*"[^"]*"' "$html_file" | sed 's/style\s*=\s*"\(.*\)"/\1/' | while read -r style_content; do
|
|
if [ -n "$style_content" ]; then
|
|
hash=$(calculate_inline_hash "$style_content")
|
|
echo "Found inline style: '$style_content'"
|
|
echo "Calculated hash: sha256-$hash"
|
|
echo "'sha256-$hash'" >> "$TEMP_INLINE_HASHES_FILE"
|
|
fi
|
|
done
|
|
done
|
|
|
|
# Sort and remove duplicates from inline style hashes
|
|
if [ -f "$TEMP_INLINE_HASHES_FILE" ]; then
|
|
sort -u "$TEMP_INLINE_HASHES_FILE" > "${TEMP_INLINE_HASHES_FILE}.sorted"
|
|
mv "${TEMP_INLINE_HASHES_FILE}.sorted" "$TEMP_INLINE_HASHES_FILE"
|
|
|
|
# Add inline style hashes to the STYLE_HASHES array
|
|
while read -r hash; do
|
|
STYLE_HASHES+=("$hash")
|
|
done < "$TEMP_INLINE_HASHES_FILE"
|
|
|
|
# Clean up
|
|
rm -f "$TEMP_INLINE_HASHES_FILE"
|
|
fi
|
|
|
|
# Combine all hashes for CSP
|
|
echo "Updating Caddyfile CSP headers..."
|
|
SCRIPT_HASHES_STR=$(printf " %s" "${SCRIPT_HASHES[@]}")
|
|
STYLE_HASHES_STR=$(printf " %s" "${STYLE_HASHES[@]}")
|
|
|
|
# Create the CSP string
|
|
CSP_STRING="default-src 'none'; script-src 'self'$SCRIPT_HASHES_STR; style-src 'self'$STYLE_HASHES_STR; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none';"
|
|
|
|
# Check if Caddyfile exists before attempting to modify it
|
|
if [ -f "$CADDYFILE" ]; then
|
|
# Create a temporary file for the Caddyfile update
|
|
tmp_file=$(mktemp)
|
|
|
|
# Update CSP in Caddyfile using awk for more reliable text processing
|
|
awk -v csp_string="$CSP_STRING" '
|
|
{
|
|
if ($0 ~ /Content-Security-Policy/) {
|
|
gsub(/Content-Security-Policy "[^"]*"/, "Content-Security-Policy \"" csp_string "\"");
|
|
}
|
|
print;
|
|
}' "$CADDYFILE" > "$tmp_file"
|
|
|
|
# Replace original Caddyfile with modified content
|
|
mv "$tmp_file" "$CADDYFILE"
|
|
else
|
|
echo "Warning: Caddyfile not found at $CADDYFILE"
|
|
fi
|
|
|
|
# Also update Caddyfile.local if it exists
|
|
if [ -f "$BASE_DIR/Caddyfile.local" ]; then
|
|
echo "Updating Caddyfile.local CSP headers..."
|
|
tmp_file=$(mktemp)
|
|
|
|
awk -v csp_string="$CSP_STRING" '
|
|
{
|
|
if ($0 ~ /Content-Security-Policy/) {
|
|
gsub(/Content-Security-Policy "[^"]*"/, "Content-Security-Policy \"" csp_string "\"");
|
|
}
|
|
print;
|
|
}' "$BASE_DIR/Caddyfile.local" > "$tmp_file"
|
|
|
|
# Replace original Caddyfile.local with modified content
|
|
mv "$tmp_file" "$BASE_DIR/Caddyfile.local"
|
|
fi
|
|
|
|
# Add CSP meta tags to HTML files
|
|
echo "Adding CSP meta tags to HTML files..."
|
|
for html_file in $(find "$BASE_DIR" -name "*.html" -type f); do
|
|
echo "Adding CSP meta tag to $html_file"
|
|
|
|
# Create a temporary file for the replacement
|
|
tmp_file=$(mktemp)
|
|
|
|
# Check if the file already has a CSP meta tag
|
|
if grep -q '<meta http-equiv="Content-Security-Policy"' "$html_file"; then
|
|
# Update existing CSP meta tag
|
|
awk -v csp_string="$CSP_STRING" '
|
|
{
|
|
if ($0 ~ /<meta http-equiv="Content-Security-Policy"/) {
|
|
gsub(/<meta http-equiv="Content-Security-Policy" content="[^"]*"/, "<meta http-equiv=\"Content-Security-Policy\" content=\"" csp_string "\"");
|
|
}
|
|
print;
|
|
}' "$html_file" > "$tmp_file"
|
|
else
|
|
# Add CSP meta tag after the last meta tag
|
|
awk -v csp_string="$CSP_STRING" '
|
|
{
|
|
print;
|
|
if ($0 ~ /<\/head>/ && !added_csp) {
|
|
print " <meta http-equiv=\"Content-Security-Policy\" content=\"" csp_string "\">";
|
|
added_csp = 1;
|
|
}
|
|
}' "$html_file" > "$tmp_file"
|
|
fi
|
|
|
|
# Replace original file with modified content
|
|
mv "$tmp_file" "$html_file"
|
|
done
|
|
|
|
echo "CSP hashes updated successfully!"
|
|
echo "To apply changes, restart the server using: ./caddy.sh" |