upload.pl 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/perl
  2. # Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
  3. # This program is free software: you can redistribute it and/or modify it under
  4. # the terms of the GNU General Public License as published by the Free Software
  5. # Foundation, either version 3 of the License, or (at your option) any later
  6. # version.
  7. #
  8. # This program is distributed in the hope that it will be useful, but WITHOUT
  9. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License along with
  13. # this program. If not, see <http://www.gnu.org/licenses/>.
  14. use strict;
  15. use v5.10;
  16. use CGI;
  17. #use CGI::Carp qw ( fatalsToBrowser );
  18. use File::Basename;
  19. AddModuleDescription('upload.pl');
  20. $CGI::POST_MAX = 1024 * 100000;
  21. my $filenameWhitelist = 'a-zA-Z0-9_.-';
  22. my @additionalChars = ('A'..'Z', 'a'..'z', '0'..'9');
  23. my $urlStart = 'http://files.YOURDOMAIN.org/'; # CHANGE THIS
  24. my $uploadDir = '../upload/';
  25. my $logFile = '../upload.log';
  26. my %keys = qw(justletmeupload you); # CHANGE THIS
  27. sub squeak {
  28. say shift;
  29. die;
  30. }
  31. my $q = new CGI;
  32. print $q->header();
  33. if (not exists $keys{$q->param("key")}) {
  34. squeak 'Error: Not authorized to upload';
  35. }
  36. if (not $q->param("fileToUpload0")) {
  37. squeak 'Error: There was a problem uploading your file (try a smaller file)';
  38. }
  39. for (my $i=0; $q->param("fileToUpload$i"); $i++) {
  40. if ($i >= 100) { # Uploading more than 100 files? What?
  41. squeak 'Error: Cannot upload more than 100 files at once';
  42. }
  43. my $curFilename = substr $q->param("fileToUpload$i"), -100;
  44. my($name, $path, $extension) = fileparse($curFilename, '\..*');
  45. $name =~ tr/ /_/;
  46. $name =~ s/[^$filenameWhitelist]//g;
  47. $extension =~ tr/ /_/;
  48. $extension =~ s/[^$filenameWhitelist]//g;
  49. $curFilename = $name . $extension;
  50. while (IsFile("$uploadDir/$curFilename")) { # keep adding random characters until we get unique filename
  51. squeak 'Error: Cannot save file with such filename' if length $curFilename >= 150; # cannot find available filename after so many attempts
  52. $name .= $additionalChars[rand @additionalChars];
  53. $curFilename = $name . $extension;
  54. }
  55. if ($curFilename =~ /^([$filenameWhitelist]+)$/) { # filename is already safe, but we have to untaint it
  56. $curFilename = $1;
  57. } else {
  58. squeak 'Error: Filename contains invalid characters'; # this should not happen
  59. }
  60. open(my $LOGFILE, '>>', encode_utf8($logFile)) or squeak "$!";
  61. print $LOGFILE $q->param("key") . ' ' . $ENV{REMOTE_ADDR} . ' ' . $curFilename . "\n";
  62. close $LOGFILE;
  63. my $uploadFileHandle = $q->upload("fileToUpload$i");
  64. open(my $UPLOADFILE, '>', encode_utf8("$uploadDir/$curFilename")) or squeak "$!";
  65. binmode $UPLOADFILE;
  66. while (<$uploadFileHandle>) {
  67. print $UPLOADFILE;
  68. }
  69. close $UPLOADFILE;
  70. if ($q->param("nameOnly")) {
  71. print "$curFilename\n";
  72. } else {
  73. print "$urlStart$curFilename\n";
  74. }
  75. }