leocharre has asked for the wisdom of the Perl Monks concerning the following question:

i have these files to be shared with users online they are sensitive files
i am storing them in a non http accessible location when the user requests a download
a script makes a symbolic link
and i want to have an "at" job schedule symlink deletion according to filesize and connection

(note: i do not take tainted data for this transaction. at this point in my program, the file selected has been already checked for user permissions, etc at a previous step, don't need help with that either)

i can figure out how to pass "at" a job from a text file. but how on earth do i do something like ..

at now + 1 minute rm symlink?

Also, if anybody has any comments about this method, that it is stupid and why, please tell me. I also considered making a named pipe or something.. also considered a script that would stream the file line by line.. but i am sketched out by the variety of files there may be, etc

Replies are listed 'Best First'.
Base for password protected file downloads
by ikegami (Patriarch) on Nov 28, 2005 at 20:24 UTC
    You could start with something like:
    #!/usr/bin/perl -T use strict; use warnings; if ( ... a password was not provided ... ) { ... return HTML login form form ... exit; } if ( ... password is not ok ... ) { ... return HTTP error + HTML error message and login form ... exit; } $file_name = ...; if ( ... insufficient permissions... ) { ... return HTTP error + HTML error message ... exit; } if (!open(my $fh, '<', $file_name)) { ... return HTTP error and/or HTML error message ... exit; } print("Content-Type: application/octect-stream\n"); print("\n"); binmode(STDOUT); binmode($fh); $/ = \1024; # Read in blocks of 1024 bytes; print while <$fh>;

      wow. this is really useful.
      I also used

      Content-Disposition: attachment; filename="$filename"\n

      To set the filename when they get to my script download.cgi

      For sessioning etc I am using a mysql table. The table keeps the user id, the timestamp start time, the timestampt last access time, the session id, the ip the session is valid for, some other details about what the user is doing right now.
      For example, this is where i am keeping their last selected file id.
      They can browse files they have been assigned access to, and if they select the file- the script double checks they have authority to that file and inserts the file id into their session row (in the mysql sessions table).

      This way, if they choose to download, we already know what from a previous step.

      By the way, this app will work via ssl. and I am going to seek out for the app to check that it *is* serving via ssl. Otherwise poop out. I know, to open source this, i have to allow for an override.

      Man.. am I glad I came here for help. You guys rock. I have absolutely no problems with being told where i'm messing up- I bow before you.

      background
      This app is being made to allow business to share their docs with clients. They need some strange customizations for allowing very precise per client access to files and what they can do with them. I want to open source the basic system for everyone to use, and I am struggling to keep any customizations as far appart from the basic thing as possible. I hope to have it up on sourceforge in a few months. I know it will get shot out of the sky for stupidity, but- I trust the process.

Re: at job help ?
by merlyn (Sage) on Nov 28, 2005 at 20:06 UTC
    You don't say if this is for a web setup, and if so, what web server.

    For low performance, your authorization script can return a URL that points at your deliver script, and the delivery script can confirm that the request is not "too old", and if OK, deliver the content.

    For high-performance, you can use mod_perl to handle the delivery URL that simply sets the request filename to the content during the TransHandler phase, provided the timestamp again is not too old, and otherwise returns a 404.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: at job help ?
by davidrw (Prior) on Nov 28, 2005 at 20:09 UTC
    Also, if anybody has any comments about this method, that it is stupid and why, please tell me.
    Two major reasons:
    • not secure -- the symlink puts the file in an http-accesible location .. doesn't matter that it's for a relatively short timeframe; it's still available to whoever..
    • will fail -- you're guessing at when the file can be deleted .. what if the d/l stops 1/2 way through and the user refreshes to start it again? It's going to take a net of at least 50% longer than anticipated.. The longer you make the window to compensate for this the bigger the first issue gets.

    also considered a script that would stream the file line by line.. but i am sketched out by the variety of files there may be, etc
    What's an example of a case where that matters? Because of the content-type header that would need to be sent?

    Also, what kind of sessioning/authentication are you using?
Re: at job help ?
by pileofrogs (Priest) on Nov 28, 2005 at 22:08 UTC

    First, like the others have said, the security of this is pretty bad, so you might want to consider alternatives.

    To answer your question about the at job:

    system("echo \"rm $symlink\" | at now + 1 minute");

    Or something similar should do it.

    -Pileofrogs

      Yes i have abandoned symlink idea- I am doing what ikegami suggested. The octet stream thingie.It works marvelous.

      Here's the chunk of code..

        # the SV hash is non-tainted data, that means at this point the data is     
        # coming from the server, not the client 
        # $SV{file_selected_path} is the path to the file in the document     
        # directory, here there are multiple directories etc
        # here we make ugly/azz/filename.pdf to filename.pdf
        my $filename = $SV{file_selected_path};$filename=~s/^.+\///;
      
      # $DOC has the absolute path on server to the documents directory
      my $FILE;
      if (!open($FILE, '<',"$DOC/$SV{file_selected_path}")) {
         print "Location: $WWW/?sorry\n\n"; 
      	exit;
      }
      
      # the next code line makes it so if you go to download.cgi,
      # the user gets prompted to do what with filename.pdf, cute.
      print(qq|Content-Disposition: attachment; filename="$filename"\n
      Content-Type: application/octect-stream\n\n|);
      
      binmode(STDOUT);
      binmode($FILE);
      $/ = \1024; # Read in blocks of 1024 bytes;
      print while <$FILE>;
      
      exit;