once.pl
changeset 57 4edd34dee93d
parent 56 39c4a5f4ac33
child 58 adf016ea4348
equal deleted inserted replaced
56:39c4a5f4ac33 57:4edd34dee93d
    92     #       |-STORE----------------------------|
    92     #       |-STORE----------------------------|
    93     # …     |-PATH--------------------------------------|
    93     # …     |-PATH--------------------------------------|
    94     if ($ENV{PATH_INFO} =~
    94     if ($ENV{PATH_INFO} =~
    95         m{/(?<path>(?<store>(?<view>$rxVIEW)/$rxFILE)/(?<base>.*))})
    95         m{/(?<path>(?<store>(?<view>$rxVIEW)/$rxFILE)/(?<base>.*))})
    96     {
    96     {
    97 #        use Data::Dumper;
    97         #        use Data::Dumper;
    98 #        die Dumper \%+;
    98         #        die Dumper \%+;
    99         my $view  = deslash realpath catfile $ONCE_VAR, $+{view};
    99         my $view  = deslash realpath catfile $ONCE_VAR, $+{view};
   100         my $store = deslash realpath catfile $ONCE_VAR, $+{store};
   100         my $store = deslash realpath catfile $ONCE_VAR, $+{store};
   101         my $file  = deslash realpath catfile $ONCE_VAR, $+{path};
   101         my $file  = deslash realpath catfile $ONCE_VAR, $+{path};
   102         my $base  = $+{base};
   102         my $base  = $+{base};
   103 
   103 
   133 
   133 
   134     -x -w $ONCE_VAR
   134     -x -w $ONCE_VAR
   135       or die "Can't write to $ONCE_VAR: $!\n";
   135       or die "Can't write to $ONCE_VAR: $!\n";
   136 
   136 
   137     my ($view, $user_dir) = do {
   137     my ($view, $user_dir) = do {
       
   138 
   138         # view: display name
   139         # view: display name
   139         #       anonymous | hans | …
   140         #       anonymous | hans | …
   140         # user_dir: the directory name, becomes part of the
   141         # user_dir: the directory name, becomes part of the
   141         #           link, later
   142         #           link, later
   142         #       /var/lib/once/1AaIF9-1KF
   143         #       /var/lib/once/1AaIF9-1KF
   149         # to adapt the patterns $rxVIEW and $rxFILE at the beginning of
   150         # to adapt the patterns $rxVIEW and $rxFILE at the beginning of
   150         # the script.
   151         # the script.
   151         #
   152         #
   152         my ($v, $d);
   153         my ($v, $d);
   153         if ($ENV{REMOTE_USER} =~ /^\s*(.+)\s*$/) {
   154         if ($ENV{REMOTE_USER} =~ /^\s*(.+)\s*$/) {
       
   155 
   154             # Known users get a directory name based user name.
   156             # Known users get a directory name based user name.
   155             # Yes, if somebody can guess the user names, they can guess
   157             # Yes, if somebody can guess the user names, they can guess
   156             # the directory names too. But they can't guess the
   158             # the directory names too. But they can't guess the
   157             # completly randomly named files in there.
   159             # completly randomly named files in there.
   158             $d = join '-' => base62(time), md5_base62($1);
   160             $d = join '-' => base62(time), md5_base62($1);
   185     if (length(my $file = param('upload'))) {
   187     if (length(my $file = param('upload'))) {
   186         my $uuid = gen_uuid();
   188         my $uuid = gen_uuid();
   187         my ($delete, $expires, $days) = do {
   189         my ($delete, $expires, $days) = do {
   188             my ($d, $e);
   190             my ($d, $e);
   189             my $days = param('expires');
   191             my $days = param('expires');
       
   192 
   190             # sanitize expires
   193             # sanitize expires
   191             $days =~ /.*?([+-]?\d+).*/;
   194             $days =~ /.*?([+-]?\d+).*/;
   192             $days = $1 // 10;
   195             $days = $1 // 10;
   193             $e = base62 time + $days * 86400;
   196             $e = base62 time + $days * 86400;
   194 
   197 
   195             if ($days == 0) { $d = 'd' }       # at first [d]ownload
   198             if    ($days == 0) { $d = 'd' }    # at first [d]ownload
   196             elsif ($days < 0) { $d = 'm' }     # only [m]anually
   199             elsif ($days < 0)  { $d = 'm' }    # only [m]anually
   197             else { $d = 'e' }                  # if expired
   200             else               { $d = 'e' }    # if expired
   198             ($d, $e, $days);
   201             ($d, $e, $days);
   199         };
   202         };
   200 
   203 
   201         # sanitize the filename
   204         # sanitize the filename
   202         my $filename = do {
   205         my $filename = do {
   241             my ($file, $dir) = fileparse($_);
   244             my ($file, $dir) = fileparse($_);
   242             $dir = substr $dir,
   245             $dir = substr $dir,
   243               length $ONCE_VAR;    # make it relative to $ONCE_VAR
   246               length $ONCE_VAR;    # make it relative to $ONCE_VAR
   244 
   247 
   245             # FIXME: use the rx* patterns from above
   248             # FIXME: use the rx* patterns from above
   246             $dir =~ m{/(?<expires>[a-z\d]{6})-(?<hash>[a-z\d]+)-(?<delete>.)}i or next;
   249             $dir =~ m{/(?<expires>[a-z\d]{6})-(?<hash>[a-z\d]+)-(?<delete>.)}i
       
   250               or next;
   247             my ($hash, $expires, $delete) = @{+}{qw/hash expires delete/};
   251             my ($hash, $expires, $delete) = @{+}{qw/hash expires delete/};
   248             if (${expires} <= time and $delete eq 'e') {
   252             if (${expires} <= time and $delete eq 'e') {
   249                 /(.*)/;
   253                 /(.*)/;
   250                 unlink $_  or die "Can't unlik $_: $!\n";
   254                 unlink $_  or die "Can't unlik $_: $!\n";
   251                 rmdir $dir or die "Can't rmdir $dir: $!\n";
   255                 rmdir $dir or die "Can't rmdir $dir: $!\n";
   289       end_table,
   293       end_table,
   290       end_multipart_form,
   294       end_multipart_form,
   291       @footer,
   295       @footer,
   292       end_html;
   296       end_html;
   293 
   297 
   294       return 0;
   298     return 0;
   295 }
   299 }
   296 
   300 
   297 sub deletedir {
   301 sub deletedir {
   298     remove_tree
   302     remove_tree
   299       map  { /^(\/.*)/ }
   303       map  { /^(\/.*)/ }
   359 }
   363 }
   360 
   364 
   361 sub base62 {
   365 sub base62 {
   362     my $n = shift // $_;
   366     my $n = shift // $_;
   363     die 'input is >MAXINT' if $n == $n - 1 or $n == $n + 1;
   367     die 'input is >MAXINT' if $n == $n - 1 or $n == $n + 1;
   364     state $digits = [0..9, 'a'..'z', 'A'..'Z'];
   368     state $digits = [0 .. 9, 'a' .. 'z', 'A' .. 'Z'];
   365     state $base = @$digits;
   369     state $base = @$digits;
   366     my @result;
   370     my @result;
   367 
   371 
   368     for (;$n >= $base; $n = int($n/$base)) {
   372     for (; $n >= $base ; $n = int($n / $base)) {
   369         my $mod = $n % $base;
   373         my $mod = $n % $base;
   370         unshift @result, $digits->[$mod];
   374         unshift @result, $digits->[$mod];
   371     }
   375     }
   372     unshift @result, $digits->[$n];
   376     unshift @result, $digits->[$n];
   373     join '', @result;
   377     join '', @result;
   374 }
   378 }
   375 
   379 
   376 
       
   377 sub gen_uuid {
   380 sub gen_uuid {
       
   381 
   378     #open my $f, '/dev/urandom' or croak;
   382     #open my $f, '/dev/urandom' or croak;
   379     #read $f, my($_), 128/8;
   383     #read $f, my($_), 128/8;
   380     #/^(.*)$/;
   384     #/^(.*)$/;
   381     #die join '-', map { base62 $_ } unpack 'Q*', $1;
   385     #die join '-', map { base62 $_ } unpack 'Q*', $1;
   382     return base62 int rand(2**64);
   386     return base62 int rand(2**64);