index.cgi 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #!/usr/bin/perl
  2. # Filesystem web share (deprecated -- use the Fast CGI version instead).
  3. use 5.016;
  4. use strict;
  5. use warnings;
  6. #use autodie;
  7. use CGI qw/:standard *table -utf8/;
  8. use CGI::Carp qw(fatalsToBrowser);
  9. use autouse 'HTML::Entities' => qw(encode_entities);
  10. use autouse 'Number::Bytes::Human' => qw(format_bytes);
  11. use autouse 'Digest::MD5' => qw(md5_hex);
  12. use autouse 'File::Copy' => qw(copy);
  13. use autouse 'File::Basename' => qw(basename);
  14. use autouse 'URI::Escape' => qw(uri_escape);
  15. use List::Util qw(max);
  16. use File::Spec::Functions qw(catfile catdir splitdir);
  17. require URI;
  18. require URI::QueryParam;
  19. state $share_root = "SHARE"; # edit this path
  20. state $root = $ENV{DOCUMENT_ROOT};
  21. $root // die;
  22. state $DB_DIR = 'db';
  23. state $DB_FILE = catfile($DB_DIR, 'visits.db');
  24. state $img_dir = 'img';
  25. state $folder_icon = catfile($img_dir, qw(folder.png));
  26. my $u = URI->new("", "http");
  27. $u->query($ENV{QUERY_STRING} || "path=$share_root");
  28. mkdir($DB_DIR) if not -d $DB_DIR;
  29. open my $db_h, '>>', $DB_FILE;
  30. sub wrap_text {
  31. my ($text, $len, $max_len) = @_;
  32. $max_len = $max_len - ($max_len % 10) + 10;
  33. $text .= " " x ($max_len - $len) if ($len < $max_len);
  34. $text =~ s{(?:&#?\w+;|\X){10}\K}{<br />}gs;
  35. return $text;
  36. }
  37. sub print_tr_td {
  38. my ($a_href, $name, $size) = @_;
  39. state $x = 0;
  40. print q{<td width="90">} . $a_href . br . small(wrap_text(encode_entities($name), length($name), $size)) . "</td>";
  41. print q{</tr><tr>} if ++$x % 13 == 0;
  42. # print Tr({-align => 'left'}, [q{<td width="1%">} . $a_href . th({}, small(encode_entities $name))]);
  43. }
  44. sub hash_to_query {
  45. my ($opts) = @_;
  46. return join(q{&} => map $_ . q{=} . uri_escape($opts->{$_}), grep defined $opts->{$_}, keys %{$opts});
  47. }
  48. sub make_a_href {
  49. my ($hash_ref) = @_;
  50. return a(
  51. {
  52. href => "$ENV{SCRIPT_NAME}?" . hash_to_query($hash_ref->{query}),
  53. exists $hash_ref->{size} ? (class => "popup") : ()
  54. },
  55. (exists $hash_ref->{size} ? small((span("Size: " . format_bytes($hash_ref->{size})))) : ()),
  56. img(
  57. {
  58. src => $hash_ref->{icon},
  59. alt => ($hash_ref->{query}{file} ? "file" : "folder"),
  60. width => 64,
  61. height => 64,
  62. }
  63. )
  64. );
  65. }
  66. sub get_thumbnail {
  67. my ($file) = @_;
  68. state $home_dir = $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7] || `echo -n ~`;
  69. state $srv_thumbs_dir = catdir($root, 'thumbnails');
  70. state $thumbs_dir = catdir($home_dir, qw(.thumbnails normal));
  71. $file =~ s{^\Q$share_root\E}{file://$home_dir};
  72. my $md5 = md5_hex($file);
  73. my $thumbnail = catfile($thumbs_dir, "$md5.png");
  74. if (-e $thumbnail) {
  75. my $srv_thumb = catfile($srv_thumbs_dir, "$md5.png");
  76. copy($thumbnail, $srv_thumb) or die $!;
  77. $srv_thumb =~ s{^\Q$root\E}{};
  78. return $srv_thumb;
  79. }
  80. else {
  81. return;
  82. }
  83. }
  84. if (defined(my $path = $u->query_param_delete('path'))) {
  85. my $fullpath = $path; #catdir($root, $path);
  86. if ($path =~ m{/\.\./} or $path =~ m{/\.\.} or not $path =~ m{^\Q$share_root\E(?:/|\z)}) {
  87. print header, start_html(
  88. -style => {'src' => 'styles/style.css'},
  89. -meta => {
  90. 'viewport' => 'width=device-width, initial-scale=1.0',
  91. },
  92. -BGCOLOR => 'black'
  93. ),
  94. h1("You're not allowed to see this directory!"), end_html;
  95. print {$db_h} <<"EOT";
  96. <hack> IP="$ENV{REMOTE_ADDR}" AGENT="$ENV{HTTP_USER_AGENT}" FILE="\Q$path\E" PORT="$ENV{REMOTE_PORT}" REFERER="\Q$ENV{HTTP_REFERER}\E" QUERY="$ENV{QUERY_STRING}"
  97. EOT
  98. close $db_h;
  99. exit;
  100. }
  101. if ($u->query_param_delete('file')) {
  102. my $name = basename($path);
  103. print {$db_h} <<"EOT";
  104. <download> IP="$ENV{REMOTE_ADDR}" AGENT="$ENV{HTTP_USER_AGENT}" FILE="\Q$path\E" BASENAME="\Q$name\E" PORT="$ENV{REMOTE_PORT}" REFERER="\Q$ENV{HTTP_REFERER}\E" QUERY="$ENV{QUERY_STRING}"
  105. EOT
  106. close $db_h;
  107. sysopen my $fh, $fullpath, 0;
  108. print header(
  109. -type => 'application/octet-stream',
  110. -expires => '+3d',
  111. -Content_length => (-s $fullpath),
  112. -attachment => $name
  113. );
  114. state $size = 1024 * 1024 * 2; # 2 MB
  115. while (defined(my $chunk_size = sysread($fh, (my $chunk), $size))) {
  116. print $chunk;
  117. last if $chunk_size < $size;
  118. }
  119. close $fh;
  120. }
  121. else {
  122. print header,
  123. start_html(
  124. -title => 'HFSS - Happy file-sharing system',
  125. -author => 'Daniel Șuteu',
  126. -meta => {
  127. 'keywords' => 'trizen',
  128. 'copyright' => 'Copyright 2012 Trizen',
  129. 'viewport' => 'width=device-width, initial-scale=1.0',
  130. },
  131. -style => {src => 'styles/style.css'},
  132. -head => Link(
  133. {
  134. -rel => 'shortcut icon',
  135. -type => 'image/x-icon',
  136. -href => 'images/tux.png',
  137. }
  138. ),
  139. -BGCOLOR => 'black',
  140. );
  141. print <<'SCRIPT';
  142. <script type="text/javascript">
  143. function gotoDir(path){
  144. window.location.href=path
  145. }
  146. </script>
  147. SCRIPT
  148. my $referrer = $ENV{HTTP_REFERER} // '';
  149. print {$db_h} <<"EOT";
  150. <view> IP="$ENV{REMOTE_ADDR}" AGENT="$ENV{HTTP_USER_AGENT}" FILE="\Q$path\E" PORT="$ENV{REMOTE_PORT}" REFERER="\Q$referrer\E" QUERY="$ENV{QUERY_STRING}"
  151. EOT
  152. close $db_h;
  153. my @dirs = grep { defined && /\S/ } splitdir($path);
  154. $dirs[0] = "/";
  155. print start_table(
  156. {
  157. border => "",
  158. width => "1%"
  159. }
  160. );
  161. my $name = $share_root;
  162. print Tr(
  163. {-align => 'left'},
  164. map {
  165. td(
  166. {width => "5%"},
  167. button(
  168. -value => $_,
  169. -onClick => 'gotoDir(src)',
  170. -src => "$ENV{SCRIPT_NAME}?" . hash_to_query({path => $name = catdir($name, $_)}),
  171. )
  172. )
  173. } @dirs
  174. );
  175. print end_table;
  176. my $full_img_dir = $img_dir;
  177. if (-d -r $fullpath) {
  178. opendir(my $dir_h, $fullpath);
  179. my @files;
  180. while (defined(my $file = readdir($dir_h))) {
  181. next if chr ord $file eq q{.};
  182. my $fullname = catfile($fullpath, $file);
  183. my $name = catfile($path, $file);
  184. push @files,
  185. -d $fullname ? {dir => 1, name => $name}
  186. : (-f _) ? {dir => 0, name => $name, size => (-s _)}
  187. : next;
  188. }
  189. my $max_len = max(map { length(basename($_->{name})) } @files);
  190. if (@files) {
  191. print q{<table><tr>};
  192. foreach my $file ((sort { fc($a->{name}) cmp fc($b->{name}) } grep { $_->{dir} } @files),
  193. sort { fc($a->{name}) cmp fc($b->{name}) } grep { !$_->{dir} } @files) {
  194. my $name = basename($file->{name});
  195. if ($file->{dir}) {
  196. my $a_href = make_a_href({icon => $folder_icon, query => {path => $file->{name}}});
  197. utf8::decode($name);
  198. print_tr_td($a_href, $name, $max_len);
  199. }
  200. else {
  201. my $format = 'file';
  202. $format = lc($1) if $file->{name} =~ /\.(\w+)\z/;
  203. my $file_icon = get_thumbnail($file->{name}) // (
  204. (-e catfile($full_img_dir, "$format.png"))
  205. ? catfile($img_dir, "$format.png")
  206. : catfile($img_dir, "file.png")
  207. );
  208. my $a_href =
  209. make_a_href(
  210. {
  211. icon => $file_icon,
  212. query => {path => $file->{name}, file => 1},
  213. size => $file->{size}
  214. }
  215. );
  216. utf8::decode($name);
  217. print_tr_td($a_href, $name, $max_len);
  218. }
  219. }
  220. print "</tr></table>";
  221. }
  222. else {
  223. print h1("Empty directory!");
  224. }
  225. }
  226. else {
  227. print h1("This directory doesn't exist!");
  228. }
  229. print end_html;
  230. }
  231. }
  232. else {
  233. print header, start_html, h1("No path specified!"), end_html;
  234. }