X-Git-Url: https://git.sesse.net/?p=pr0n;a=blobdiff_plain;f=perl%2FSesse%2Fpr0n%2FUpload.pm;h=6f44f7ac12a32b69ec5345f109b0e21a358db045;hp=a9d1023aa4bacccd34c8105ebb03b064ac60e8cd;hb=3b2c7786062de33fd427f8b30556570cab9d4349;hpb=fb1421cd30d9e888d738012b826761cc418082da diff --git a/perl/Sesse/pr0n/Upload.pm b/perl/Sesse/pr0n/Upload.pm index a9d1023..6f44f7a 100644 --- a/perl/Sesse/pr0n/Upload.pm +++ b/perl/Sesse/pr0n/Upload.pm @@ -1,40 +1,130 @@ -# Shows the upload dialog. - package Sesse::pr0n::Upload; use strict; use warnings; use Sesse::pr0n::Common qw(error dberror); +use Digest::SHA; +use MIME::Base64; sub handler { my $r = shift; my $dbh = Sesse::pr0n::Common::get_dbh(); - # Fix common error: pr0n.sesse.net/upload/event -> pr0n.sesse.net/upload/event/ - if ($r->path_info !~ /\/$/) { - my $res = Plack::Response->new(301); - $res->header('Location' => $r->path_info . "/"); + my $res = Plack::Response->new(200); + my $io = IO::String->new; + + my ($user,$takenby) = Sesse::pr0n::Common::check_access($r); + return Sesse::pr0n::Common::generate_401($r) if (!defined($user)); + + # Just "ping, are you alive" + if ($r->method eq "OPTIONS") { + $res->content_type('text/plain; charset="utf-8"'); return $res; } - $r->path_info =~ /^\/upload\/([a-zA-Z0-9-]+)\/?$/ - or return error($r, "Could not extract event"); - my $event = $1; + + if ($r->method eq "PUT") { + if ($r->path_info !~ m#^/upload/([a-zA-Z0-9-]+)/(autorename/)?(.{1,250})$#) { + $res->status(403); + $res->content_type('text/plain; charset=utf-8'); + $res->body("No access"); + return $res; + } + + my ($event, $autorename, $filename) = ($1, $2, $3); + my $size = $r->header('content-length'); + my $orig_filename = $filename; - my $res = Plack::Response->new(200); - $res->content_type("text/html; charset=utf-8"); - my $io = IO::String->new; + # Remove evil characters + if ($filename =~ /[^a-zA-Z0-9._()-]/) { + if (defined($autorename) && $autorename eq "autorename/") { + $filename =~ tr/a-zA-Z0-9.()-/_/c; + } else { + $res->status(403); + $res->content_type('text/plain; charset=utf-8'); + $res->body("Illegal characters in filename"); + return $res; + } + } + + # Get the new ID + my $ref = $dbh->selectrow_hashref("SELECT NEXTVAL('imageid_seq') AS id;"); + my $newid = $ref->{'id'}; + if (!defined($newid)) { + return dberror($r, "Couldn't get new ID"); + } + + # Autorename if we need to + $ref = $dbh->selectrow_hashref("SELECT COUNT(*) AS numfiles FROM images WHERE vhost=? AND event=? AND filename=?", + undef, Sesse::pr0n::Common::get_server_name($r), $event, $filename) + or return dberror($r, "Couldn't check for existing files"); + if ($ref->{'numfiles'} > 0) { + if (defined($autorename) && $autorename eq "autorename/") { + Sesse::pr0n::Common::log_info($r, "Renaming $filename to $newid.jpeg"); + $filename = "$newid.jpeg"; + } else { + $res->status(403); + $res->content_type('text/plain; charset=utf-8'); + $res->body("File $filename already exists in event $event, cannot overwrite"); + return $res; + } + } + + { + # Enable transactions and error raising temporarily + local $dbh->{AutoCommit} = 0; + local $dbh->{RaiseError} = 1; + my $fname; + + # Try to insert this new file + eval { + $dbh->do('INSERT INTO images (id,vhost,event,uploadedby,takenby,filename) VALUES (?,?,?,?,?,?)', + undef, $newid, Sesse::pr0n::Common::get_server_name($r), $event, $user, $takenby, $filename); + Sesse::pr0n::Common::purge_cache($r, $res, "/$event/"); - chomp (my $title = Sesse::pr0n::Templates::fetch_template($r, 'upload-title')); - Sesse::pr0n::Common::header($r, $io, $title); - Sesse::pr0n::Templates::print_template($r, $io, 'upload', { - event => $event - }); - Sesse::pr0n::Common::footer($r, $io); + # Now save the file to disk + Sesse::pr0n::Common::ensure_disk_location_exists($r, $newid); + $fname = Sesse::pr0n::Common::get_disk_location($r, $newid); - $io->setpos(0); - $res->body($io); + open NEWFILE, ">", $fname + or die "$fname: $!"; + print NEWFILE $r->content; + close NEWFILE or die "close($fname): $!"; + + # Orient stuff correctly + system("/usr/bin/exifautotran", $fname) == 0 + or die "/usr/bin/exifautotran: $!"; + + # Make cache while we're at it. + # FIXME: Ideally we'd want to ensure cache of -1x-1 here as well (for NEFs), but that would + # preclude mipmapping in its current form. + Sesse::pr0n::Common::ensure_cached($r, $filename, $newid, undef, undef, 320, 256); + + # OK, we got this far, commit + $dbh->commit; + + Sesse::pr0n::Common::log_info($r, "Successfully wrote $event/$filename to $fname"); + }; + if ($@) { + # Some error occurred, rollback and bomb out + $dbh->rollback; + unlink($fname); + return error($r, "Transaction aborted because $@"); + } + } + + $res->content_type('text/plain; charset="utf-8"'); + $res->status(201); + $res->body("OK"); + return $res; + } + + $res->content_type('text/plain; charset=utf-8'); + Sesse::pr0n::Common::log_error($r, "unknown method " . $r->method); + $res->status(500); + $res->body("Unknown method"); return $res; } - + 1; +