|
Lines 46-88
is violated. This endpoint logs those reports for administrator review.
Link Here
|
| 46 |
sub add { |
46 |
sub add { |
| 47 |
my $c = shift->openapi->valid_input or return; |
47 |
my $c = shift->openapi->valid_input or return; |
| 48 |
|
48 |
|
| 49 |
my $report = $c->req->json; |
|
|
| 50 |
|
| 51 |
# CSP reports come wrapped in a 'csp-report' key |
| 52 |
my $csp_report = $report->{'csp-report'} // $report->{'body'} // $report; |
| 53 |
|
| 54 |
my $logger = Koha::Logger->get( { interface => 'csp' } ); |
49 |
my $logger = Koha::Logger->get( { interface => 'csp' } ); |
| 55 |
|
50 |
|
| 56 |
# Extract key fields for logging |
51 |
my @reports = (); |
| 57 |
my $document_uri = $csp_report->{'document-uri'} // 'unknown'; |
52 |
my $reports_from_json = $c->req->json; |
| 58 |
my $violated_dir = $csp_report->{'violated-directive'} // 'unknown'; |
53 |
if ( ref $reports_from_json eq 'ARRAY' ) { |
| 59 |
my $blocked_uri = $csp_report->{'blocked-uri'} // 'unknown'; |
|
|
| 60 |
my $source_file = $csp_report->{'source-file'} // ''; |
| 61 |
my $line_number = $csp_report->{'line-number'} // ''; |
| 62 |
my $column_number = $csp_report->{'column-number'} // ''; |
| 63 |
|
| 64 |
# Build location string if available |
| 65 |
my $location = ''; |
| 66 |
if ($source_file) { |
| 67 |
$location = " at $source_file"; |
| 68 |
$location .= ":$line_number" if $line_number; |
| 69 |
$location .= ":$column_number" if $column_number; |
| 70 |
} |
| 71 |
|
54 |
|
| 72 |
$logger->warn( |
55 |
#FIXME: We could just take the top X number of reports... |
| 73 |
sprintf( |
56 |
push( @reports, @$reports_from_json ); |
| 74 |
"CSP violation: '%s' blocked '%s' on page '%s'%s", |
57 |
} elsif ( ref $reports_from_json eq 'HASH' ) { |
| 75 |
$violated_dir, |
58 |
push( @reports, $reports_from_json ); |
| 76 |
$blocked_uri, |
59 |
} |
| 77 |
$document_uri, |
|
|
| 78 |
$location |
| 79 |
) |
| 80 |
); |
| 81 |
|
60 |
|
| 82 |
# Log full report at debug level for detailed analysis |
61 |
# CSP reports come wrapped in a 'csp-report' key |
| 83 |
if ( $logger->is_debug ) { |
62 |
foreach my $report (@reports) { |
| 84 |
require JSON; |
63 |
my $csp_report = $report->{'csp-report'} // $report->{body}; |
| 85 |
$logger->debug( "CSP report details: " . JSON::encode_json($csp_report) ); |
64 |
|
|
|
65 |
# Extract key fields for logging |
| 66 |
my $document_uri = $csp_report->{'documentURL'} // $csp_report->{'document-uri'} // 'unknown'; |
| 67 |
my $violated_dir = $csp_report->{'effectiveDirective'} // $csp_report->{'effective-directive'} // 'unknown'; |
| 68 |
my $blocked_uri = $csp_report->{'blockedURL'} // $csp_report->{'blocked-uri'} // 'unknown'; |
| 69 |
my $source_file = $csp_report->{'sourceFile'} // $csp_report->{'source-file'} // ''; |
| 70 |
my $line_number = $csp_report->{'lineNumber'} // $csp_report->{'line-number'} // ''; |
| 71 |
my $column_number = $csp_report->{'columnNumber'} // $csp_report->{'column-number'} // ''; |
| 72 |
|
| 73 |
# Build location string if available |
| 74 |
my $location = ''; |
| 75 |
if ($source_file) { |
| 76 |
$location = " at $source_file"; |
| 77 |
$location .= ":$line_number" if $line_number; |
| 78 |
$location .= ":$column_number" if $column_number; |
| 79 |
} |
| 80 |
|
| 81 |
$logger->warn( |
| 82 |
sprintf( |
| 83 |
"CSP violation: '%s' blocked '%s' on page '%s'%s", |
| 84 |
$violated_dir, |
| 85 |
$blocked_uri, |
| 86 |
$document_uri, |
| 87 |
$location |
| 88 |
) |
| 89 |
); |
| 90 |
|
| 91 |
# Log full report at debug level for detailed analysis |
| 92 |
if ( $logger->is_debug ) { |
| 93 |
require JSON; |
| 94 |
$logger->debug( "CSP report details: " . JSON::encode_json($csp_report) ); |
| 95 |
} |
| 86 |
} |
96 |
} |
| 87 |
|
97 |
|
| 88 |
return $c->render( |
98 |
return $c->render( |