diff options
| author | Sadeep Madurange <sadeep@asciimx.com> | 2025-12-28 21:17:30 +0800 |
|---|---|---|
| committer | Sadeep Madurange <sadeep@asciimx.com> | 2025-12-30 21:46:51 +0800 |
| commit | 9fec793abe0a73e5cd502a1d1e935e2413b85079 (patch) | |
| tree | df5827fbc7032d982c07c06f6d9783751cc6b62d /_site/cgi-bin/find.cgi | |
| parent | 06c5dc32086a1aaae6e6f48c017ea9b5e331cdf3 (diff) | |
| download | www-9fec793abe0a73e5cd502a1d1e935e2413b85079.tar.gz | |
Search via CGI script.
Diffstat (limited to '_site/cgi-bin/find.cgi')
| -rw-r--r-- | _site/cgi-bin/find.cgi | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/_site/cgi-bin/find.cgi b/_site/cgi-bin/find.cgi new file mode 100644 index 0000000..bad12e7 --- /dev/null +++ b/_site/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; + $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>(.*?)<\/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</title> + <link rel="stylesheet" href="/assets/css/main.css"> + <link rel="stylesheet" href="/assets/css/skeleton.css"> +</head> +<body> + <div id="nav-container" class="container"> + <ul id="navlist" class="left"> + <li><a href="/" class="link-decor-none">hme</a></li> + <li><a href="/log/" class="link-decor-none">log</a></li> + <li><a href="/projects/" class="link-decor-none">poc</a></li> + <li><a href="/about/" class="link-decor-none">abt</a></li> + <li class="active"><a href="/cgi-bin/find.cgi" class="link-decor-none">sws</a></li> + <li><a href="/feed.xml" class="link-decor-none">rss</a></li> + </ul> + </div> + <main class="container" id="main"> + <div class="container"> + <h2>Search</h2> + <form action="" method="GET"> + <input id="search-box" type="text" name="q" value="$safe_search_text"> + <input id="search-btn" type="submit" value="Search"> + </form> + $list + </div> + </main> + <div class="footer"> + <div class="container"> + <div class="twelve columns right container-2"> + <p id="footer-text">© ASCIIMX - 2025</p> + </div> + </div> + </div> +</body> +</html> +HTML |
