From 9fec793abe0a73e5cd502a1d1e935e2413b85079 Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sun, 28 Dec 2025 21:17:30 +0800 Subject: Search via CGI script. --- cgi-bin/find.cgi | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 cgi-bin/find.cgi (limited to 'cgi-bin') diff --git a/cgi-bin/find.cgi b/cgi-bin/find.cgi new file mode 100644 index 0000000..bad12e7 --- /dev/null +++ b/cgi-bin/find.cgi @@ -0,0 +1,141 @@ +#!/usr/bin/perl + +use File::Find; + +sub escape_html { + my $str = shift; + $str =~ s/&/&/g; + $str =~ s//>/g; + $str =~ s/"/"/g; + $str =~ s/'/'/g; + return $str; +} + +my %params; +if ($ENV{QUERY_STRING}) { + foreach my $pair (split /&/, $ENV{QUERY_STRING}) { + my ($key, $value) = split /=/, $pair; + $value =~ tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + $params{$key} = $value; + } +} + +my $search_text = $params{'q'} || ''; +$search_text = substr($search_text, 0, 64); +$search_text =~ s/[^a-zA-Z0-9 ]//g; + +my $directory = '../log/'; +my @results; + +my %excluded_files = ( + 'index.html' => 1, # /log/index.html +); + +if ($search_text =~ /\S/) { + find({ + wanted => sub { + # Ignore directories and only process index.html + return unless -f $_ && $_ eq 'index.html'; + + # Calculate the relative path for the URL (prevents leaking server file structure) + my $rel_path = $File::Find::name; + $rel_path =~ s|^\Q$directory\E/?||; + return if $excluded_files{$rel_path}; + + if (open my $fh, '<', $_) { + my $content = do { local $/; <$fh> }; + close $fh; + + if ($content =~ /\Q$search_text\E/i) { + + # Extract Title + my ($title) = $content =~ /(.*?)<\/title>/is; + $title = $title ? escape_html($title) : $rel_path; + + # Extract the first <p> tag content + my ($p_content) = $content =~ /<p[^>]*>(.*?)<\/p>/is; + + # Process the snippet + my $snippet = $p_content || ""; + $snippet =~ s/<[^>]*>//g; # Remove internal tags + $snippet =~ s/\s+/ /g; # Collapse whitespace + + # Escape HTML entities AFTER stripping tags + # but BEFORE sending to the user to prevent XSS. + $snippet = escape_html(substr($snippet, 0, 50)); + $snippet .= "..." if length($p_content || "") > 50; + + push @results, { + path => $File::Find::name, + title => $title, + snippet => $snippet + }; + } + } + }, + no_chdir => 0, + follow => 0, + }, $directory); +} + +print "Content-Type: text/html\n\n"; + +my $list; +if ($search_text eq '') { + $list = "<p>Please enter a search term above.</p>"; +} elsif (@results == 0) { + $list = "<p>No results found for \"<b>$search_text</b>\".</p>"; +} else { + $list = "<ul>"; + foreach my $res (@results) { + my $url = $res->{path}; + $list .= "<li><a href=\"/$url\">$res->{title}</a><br><small>$res->{snippet}</small></li>"; + } + $list .= "</ul>"; +} + +my $safe_search_text = escape_html($search_text); + +print <<"HTML"; +<!DOCTYPE html> +<html lang="en-us"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search + + + + + +
+
+

Search

+
+ + +
+ $list +
+
+ + + +HTML -- cgit v1.2.3