#!/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 "Skipping CSP header updates (disabled)"

echo "CSP hashes updated successfully!"
echo "To apply changes, restart the server using: ./caddy.sh" 