[LON-CAPA-cvs] cvs: loncom / loncapa_apache.conf /auth lonacc.pm /homework daxeopen.pm daxesave.pm
raeburn
raeburn at source.lon-capa.org
Mon Aug 28 14:58:45 EDT 2023
raeburn Mon Aug 28 18:58:45 2023 EDT
Modified files:
/loncom/homework daxeopen.pm daxesave.pm
/loncom/auth lonacc.pm
/loncom loncapa_apache.conf
Log:
- Support use of pop-up browser to insert image files into HTML files
uploaded to Main Content or Supplemental Content areas of a course.
-------------- next part --------------
Index: loncom/homework/daxeopen.pm
diff -u loncom/homework/daxeopen.pm:1.12 loncom/homework/daxeopen.pm:1.13
--- loncom/homework/daxeopen.pm:1.12 Wed Aug 23 22:57:39 2023
+++ loncom/homework/daxeopen.pm Mon Aug 28 18:58:44 2023
@@ -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 @@
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 @@
$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 directory_listing {
my ($uri, $request) = @_;
my $res = '<?xml version="1.0" encoding="UTF-8"?>'."\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 .= "<directory name=\"/\">\n";
- $res .= "<directory name=\"priv\"/>\n";
- $res .= "<directory name=\"res\"/>\n";
+ if (($env{'request.course.id'}) &&
+ ($referrer =~ m{\Qfile=/daxeopen/uploaded/$cdom/$cnum/\E(docs|supplemental)/(default|\d+)/(\d+)/})) {
+ $res .= "<directory name=\"uploaded\"/>\n";
+ } else {
+ # root: let users browse /res
+ $res .= "<directory name=\"priv\"/>\n";
+ $res .= "<directory name=\"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 .= "<directory name=\"uploaded\">\n";
+ $res .= "<directory name=\"$cdom\"/>\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 .= "<directory name=\"$dirname\">\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 .= "<directory name=\"$name\"/>\n";
+ } else {
+ next if ($name =~ /\.bak$/);
+ my $dt = DateTime->from_epoch(epoch => $mtime);
+ my $modified = $dt->iso8601().'Z';
+ $res .= "<file name=\"$name\" size=\"$size\" modified=\"$modified\"/>\n";
+ }
+ }
+ }
+ } else {
+ my $nextidx = scalar(@rest);
+ my $subdir = $expected[$nextidx];
+ $res .= "<directory name=\"$subdir\"/>"."\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 @@
}
}
} 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 @@
$res .= "<directory name=\"$defdom\"/>\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');
Index: loncom/homework/daxesave.pm
diff -u loncom/homework/daxesave.pm:1.6 loncom/homework/daxesave.pm:1.7
--- loncom/homework/daxesave.pm:1.6 Wed Aug 23 20:43:34 2023
+++ loncom/homework/daxesave.pm Mon Aug 28 18:58:44 2023
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Convert and save a problem from Daxe.
#
-# $Id: daxesave.pm,v 1.6 2023/08/23 20:43:34 raeburn Exp $
+# $Id: daxesave.pm,v 1.7 2023/08/28 18:58:44 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -45,14 +45,15 @@
$request->content_type('text/plain');
# path should be in the form "/daxeopen/priv/..."
- # or ^/daxeopen/uploaded/[^/]+/[^/]+/.*html?$
+ # or "/daxeopen/uploaded/$cdom/$cnum/(docs|supplemental)/(default|\d+)/\d+/"
my $path = $env{'form.path'};
$path =~ s/^\/daxeopen//;
my $allowed = 0;
- if ($path =~ /^\/priv/) {
+ my ($cdom,$cnum);
+ if ($path =~ m{^/priv/}) {
my ($ownername,$ownerdom,$ownerhome) =
- &Apache::lonnet::constructaccess($path, 'setpriv');
+ &Apache::lonnet::constructaccess($path);
if (($ownername ne '') && ($ownerdom ne '') && ($ownerhome ne '')) {
unless ($ownerhome eq 'no_host') {
my @hosts = &Apache::lonnet::current_machine_ids();
@@ -61,7 +62,7 @@
}
}
}
- } elsif ($path =~ m|^/uploaded/[^/]+/[^/]+/|) {
+ } elsif ($path =~ m|^/uploaded/|) {
if ($env{'user.name'} ne '' && $env{'user.domain'} ne '' && $env{'request.course.id'}) {
$cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
$cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
@@ -79,33 +80,74 @@
return OK;
}
- my $newpath = &Apache::lonnet::filelocation('', $path);
-
- my $contents = $env{'form.file'};
-
- my $mode;
- if ($path =~ /\.(task|problem|exam|quiz|assess|survey|library|xml|html|htm|xhtml|xhtm)$/) {
- try {
- $contents = &Apache::xml_to_loncapa::convert_file($contents);
- } catch {
- $request->print("error\nconvert failed for $path: $_");
- return OK;
- };
- $mode = '>:encoding(UTF-8)';
- } else {
- $mode = '>';
- }
+ if ($path =~ m{^/priv/}) {
+ my $newpath = &Apache::lonnet::filelocation('', $path);
+ my $contents = $env{'form.file'};
- my $filebak = $newpath.".bak";
- if (-e $newpath) {
- copy($newpath, $filebak); # errors ignored
- }
- if (open(my $out, $mode, $newpath)) {
- print $out $contents;
- close $out;
- $request->print("ok\n");
- } else {
- $request->print("error\nFailed to open file to save $path");
+ my $mode;
+ if ($path =~ /\.(task|problem|exam|quiz|assess|survey|library|xml|html|htm|xhtml|xhtm)$/) {
+ try {
+ $contents = &Apache::xml_to_loncapa::convert_file($contents);
+ } catch {
+ $request->print("error\nconvert failed for $path: $_");
+ return OK;
+ };
+ $mode = '>:encoding(UTF-8)';
+ } else {
+ $mode = '>';
+ }
+
+ my $filebak = $newpath.".bak";
+ if (-e $newpath) {
+ copy($newpath, $filebak); # errors ignored
+ }
+ if (open(my $out, $mode, $newpath)) {
+ print $out $contents;
+ close($out);
+ $request->print("ok\n");
+ } else {
+ $request->print("error\nFailed to open file to save $path");
+ }
+ } elsif ($path =~ m{^/uploaded/}) {
+ my ($unauthorized,$unsupported);
+ if ($path =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental)/(default|\d+)/(\d+)/(.+)$}) {
+ my ($type,$folder,$rid,$fname) = ($1,$2,$3,$4);
+ my $referrer = $request->headers_in->{'Referer'};
+ if ($referrer =~ m{\Qfile=/daxeopen/uploaded/$cdom/$cnum/$type/$folder/$rid/\E}) {
+ if ($fname =~ /\.(html|htm|xhtml|xhtm)$/) {
+ try {
+ $env{'form.file'} = &Apache::xml_to_loncapa::convert_file($env{'form.file'});
+ } catch {
+ $request->print("error\nconvert failed for $fname: $_");
+ return OK;
+ }
+ } elsif ($fname =~ /\.(task|problem|exam|quiz|assess|survey|library|xml)$/) {
+ $unsupported = $1;
+ }
+ unless ($unsupported) {
+ my $url = &Apache::lonnet::finishuserfileupload($cnum,$cdom,'file',
+ "$type/$folder/$rid/$fname");
+ if ($url =~ m{^/uploaded/$cdom/$cnum/$type/$folder/$rid/}) {
+ $request->print("ok\n");
+ } else {
+ $request->print("error\nFailed to save uploaded file: $fname");
+ }
+ }
+ } else {
+ $unauthorized = 1;
+ }
+ } else {
+ $unauthorized = 1;
+ }
+ if ($unauthorized) {
+ $request->log_reason("Unauthorized path: $path", $path);
+ $request->print("error\nUnauthorized path: $path");
+ $request->status(403);
+ } elsif ($unsupported) {
+ $request->log_reason("File extension: $unsupported -- not allowed for upload to course", $path);
+ $request->print("error\nFile extension: $unsupported -- not allowed for upload to course");
+ $request->status(403);
+ }
}
return OK;
}
Index: loncom/auth/lonacc.pm
diff -u loncom/auth/lonacc.pm:1.208 loncom/auth/lonacc.pm:1.209
--- loncom/auth/lonacc.pm:1.208 Fri Jun 2 01:20:26 2023
+++ loncom/auth/lonacc.pm Mon Aug 28 18:58:45 2023
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Cookie Based Access Handler
#
-# $Id: lonacc.pm,v 1.208 2023/06/02 01:20:26 raeburn Exp $
+# $Id: lonacc.pm,v 1.209 2023/08/28 18:58:45 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -891,6 +891,17 @@
return FORBIDDEN;
}
return OK;
+ } elsif (($env{'request.course.id'}) &&
+ (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) &&
+ ($requrl=~m{^(/daxeopen|)(/uploaded/$cdom/$cnum/(?:docs|supplemental)/(?:default|\d+)/\d+/)([^/]+|)$})) {
+ my ($daxe,$path,$file) = ($1,$2,$3);
+ my $referrer;
+ unless ($daxe) {
+ $referrer = $r->headers_in->{'Referer'};
+ }
+ if (($daxe) || ($referrer =~ m{\Qfile=/daxeopen$path\E})) {
+ return OK;
+ }
}
# ---------------------------------------------------------------- Check access
my $now = time;
@@ -964,12 +975,16 @@
}
} else {
my $nodeeplinkcheck;
- if (($check_access) && ($requrl =~ /\.(sequence|page)$/)) {
- unless ($env{'form.navmap'}) {
- if ($r->args ne '') {
- &Apache::loncommon::get_unprocessed_cgi($r->args,['navmap']);
- unless ($env{'form.navmap'}) {
- $nodeeplinkcheck = 1;
+ if ($check_access) {
+ if ($requrl =~ m{^/daxeopen/priv/}) {
+ $nodeeplinkcheck = 1;
+ } elsif ($requrl =~ /\.(sequence|page)$/) {
+ unless ($env{'form.navmap'}) {
+ if ($r->args ne '') {
+ &Apache::loncommon::get_unprocessed_cgi($r->args,['navmap']);
+ unless ($env{'form.navmap'}) {
+ $nodeeplinkcheck = 1;
+ }
}
}
}
Index: loncom/loncapa_apache.conf
diff -u loncom/loncapa_apache.conf:1.281 loncom/loncapa_apache.conf:1.282
--- loncom/loncapa_apache.conf:1.281 Fri Jul 7 03:52:39 2023
+++ loncom/loncapa_apache.conf Mon Aug 28 18:58:45 2023
@@ -2,7 +2,7 @@
## loncapa_apache.conf -- Apache HTTP LON-CAPA configuration file
##
-# $Id: loncapa_apache.conf,v 1.281 2023/07/07 03:52:39 raeburn Exp $
+# $Id: loncapa_apache.conf,v 1.282 2023/08/28 18:58:45 raeburn Exp $
#
# LON-CAPA Section (extensions to httpd.conf daemon configuration)
@@ -509,7 +509,7 @@
PerlAuthzHandler Apache::lonacc
ErrorDocument 403 /adm/login
ErrorDocument 404 /adm/notfound.html
-ErrorDocument 406 /adm/unauthorized
+ErrorDocument 406 /adm/roles
ErrorDocument 500 /adm/errorhandler
</LocationMatch>
@@ -518,7 +518,7 @@
PerlHandler Apache::daxepage
</LocationMatch>
-<LocationMatch "^/daxepage/uploaded/[^/]+/[^/]+/.*html?$">
+<LocationMatch "^/daxepage/uploaded/[^/]+/[^/]+/(docs|supplemental)/.*html?$">
SetHandler perl-script
PerlHandler Apache::daxepage
</LocationMatch>
@@ -533,12 +533,12 @@
PerlHandler Apache::daxeopen
</LocationMatch>
-<LocationMatch "^/daxeopen/(res|priv)/(.+/)?$">
+<LocationMatch "^/daxeopen/(res|priv|uploaded)/(.+/)?$">
SetHandler perl-script
PerlHandler Apache::daxeopen
</LocationMatch>
-<LocationMatch "^/daxeopen/uploaded/[^/]+/[^/]+/.*html?$">
+<LocationMatch "^/daxeopen/uploaded/[^/]+/[^/]+/(docs|supplemental)/.*html?$">
SetHandler perl-script
PerlHandler Apache::daxeopen
</LocationMatch>
@@ -550,6 +550,13 @@
</IfModule>
</LocationMatch>
+<LocationMatch "(?i)^/daxeopen/uploaded/.+\.(?!html$|htm$|xhtml$|xhtm$)[^.]*$">
+<IfModule mod_rewrite.c>
+ RewriteEngine on
+ RewriteRule /daxeopen/(.*) /$1
+</IfModule>
+</LocationMatch>
+
<LocationMatch "(?i)^/daxeopen/(res/.*\.(jpg|jpeg|gif|png|svg))$">
<IfModule mod_rewrite.c>
RewriteEngine on
More information about the LON-CAPA-cvs
mailing list