--- loncom/homework/daxeopen.pm 2023/08/23 22:57:39 1.12 +++ loncom/homework/daxeopen.pm 2023/08/28 18:58:44 1.13 @@ -1,7 +1,7 @@ # The LearningOnline Network # Opening converted problems and directory listings for Daxe # -# $Id: daxeopen.pm,v 1.12 2023/08/23 22:57:39 raeburn Exp $ +# $Id: daxeopen.pm,v 1.13 2023/08/28 18:58:44 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,6 +53,8 @@ sub handler { return directory_listing($uri, $request); } elsif ($uri =~ m{^/priv/.*\.(task|problem|exam|quiz|assess|survey|library|xml|html|htm|xhtml|xhtm)$}) { return convert_problem($uri, $request); + } elsif ($uri =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/.*\.(html|htm|xhtml|xhtm)$}) { + return convert_problem($uri, $request); } else { # Apache should send other files directly $request->status(406); @@ -69,11 +71,35 @@ sub convert_problem { $request->status(403); return OK; } + } elsif ($uri =~ m{^/uploaded/($match_domain)/($match_courseid)/}) { + my ($posscdom,$posscnum) = ($1,$2); + my $allowed; + if ($env{'request.course.id'}) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if (($posscdom eq $cdom) && ($posscnum eq $cnum)) { + if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { + $allowed = 1; + } + } + } + unless ($allowed) { + $request->content_type('text/plain'); + $request->print(&mt('Forbidden URI: [_1]',$uri)); + $request->status(403); + return OK; + } } my $file = &Apache::lonnet::filelocation('', $uri); - &Apache::lonnet::repcopy($file); - if (! -e $file) { - $request->status(404); + if (&Apache::lonnet::repcopy($file) eq 'ok') { + if (! -e $file) { + $request->print(&mt('Not found: [_1]',$uri)); + $request->status(404); + return OK; + } + } else { + $request->print(&mt('Forbidden URI: [_1]',$uri)); + $request->status(403); return OK; } try { @@ -101,11 +127,97 @@ sub convert_problem { sub directory_listing { my ($uri, $request) = @_; my $res = ''."\n"; + my $referrer = $request->headers_in->{'Referer'}; + my ($cdom,$cnum); + if ($env{'request.course.id'}) { + $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + } if ($uri eq '/') { - # root: let users browse /res $res .= "\n"; - $res .= "\n"; - $res .= "\n"; + if (($env{'request.course.id'}) && + ($referrer =~ m{\Qfile=/daxeopen/uploaded/$cdom/$cnum/\E(docs|supplemental)/(default|\d+)/(\d+)/})) { + $res .= "\n"; + } else { + # root: let users browse /res + $res .= "\n"; + $res .= "\n"; + } + } elsif ($uri =~ m{^/uploaded/(.*)$}) { + my $rem = $1; + $rem =~ s{/$}{}; + if (($env{'request.course.id'}) && + ($referrer =~ m{\Qfile=/daxeopen/uploaded/$cdom/$cnum/\E(docs|supplemental)/(default|\d+)/(\d+)/})) { + my ($type,$folder,$rid) = ($1,$2,$3); + if ($rem eq '') { + $res .= "\n"; + $res .= "\n"; + } else { + my @expected = ($cdom,$cnum,$type,$folder,$rid); + my @rest = split(/\//,$rem); + my $valid = 1; + for (my $i=0; $i<@rest; $i++) { + unless ($rest[$i] eq $expected[$i]) { + $valid = 0; + last; + } + } + if ($valid) { + my $dirname = $rest[-1]; + $res .= "\n"; + if (scalar(@rest) == scalar(@expected)) { + my $subdir = "/userfiles/$type/$folder/$rid"; + my ($listref, $listerror) = &Apache::lonnet::dirlist($subdir,$cdom,$cnum,'',1); + if ($listerror) { + $request->content_type('text/plain'); + $request->print(&mt('listing error: [_1]',$listerror)); + $request->status(406); + return OK; + } elsif (scalar(@{$listref}) == 0) { + $request->content_type('text/plain'); + $request->print(&mt('Not found: [_1]',$uri)); + $request->status(404); + return OK; + } else { + my @lines = @{$listref}; + my $dirpath = &LONCAPA::propath($cdom,$cnum).'/userfiles'; + my $dirname = $uri; + $dirname =~ s{^.*/([^/]*)$}{$1}; + foreach my $line (@lines) { + my ($path,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime) = split(/\&/,$line,12); + my $isdir = ($testdir & 16384); + $path =~ s{^$dirpath}{}; + next if ($path eq '.' || $path eq '..'); + $path =~ s{/$}{}; + my $name = $path; + if ($isdir) { + $res .= "\n"; + } else { + next if ($name =~ /\.bak$/); + my $dt = DateTime->from_epoch(epoch => $mtime); + my $modified = $dt->iso8601().'Z'; + $res .= "\n"; + } + } + } + } else { + my $nextidx = scalar(@rest); + my $subdir = $expected[$nextidx]; + $res .= ""."\n"; + } + } else { + $request->content_type('text/plain'); + $request->print(&mt('Forbidden URI: [_1]',$uri)); + $request->status(403); + return OK; + } + } + } else { + $request->content_type('text/plain'); + $request->print(&mt('Forbidden URI: [_1]',$uri)); + $request->status(403); + return OK; + } } elsif ($uri !~ m{^/(priv|res)/}) { $request->content_type('text/plain'); $request->print(&mt('Not found: [_1]',$uri)); @@ -183,7 +295,6 @@ sub directory_listing { } } } elsif ($uri eq '/priv/') { - my $referrer = $request->headers_in->{'Referer'}; my $defdom = &get_defdom($referrer); if (!defined $defdom) { $request->content_type('text/plain'); @@ -195,7 +306,6 @@ sub directory_listing { $res .= "\n"; } elsif ($uri =~ m{^/priv/($match_domain)/$}) { my $domain = $1; - my $referrer = $request->headers_in->{'Referer'}; my $defdom = &get_defdom($referrer); if ($domain ne $defdom) { $request->content_type('text/plain');