--- loncom/lti/ltiutils.pm	2017/12/07 15:36:25	1.1
+++ loncom/lti/ltiutils.pm	2018/05/15 04:33:17	1.9
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA LTI interactions 
 #
-# $Id: ltiutils.pm,v 1.1 2017/12/07 15:36:25 raeburn Exp $
+# $Id: ltiutils.pm,v 1.9 2018/05/15 04:33:17 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -51,7 +51,7 @@ use LONCAPA qw(:DEFAULT :match);
 #
 # When LON-CAPA is operating as a Provider, nonce checking 
 # occurs when a user in course context in another LMS (the 
-# Consumer launches an external tool to access a LON-CAPA URL: 
+# Consumer) launches an external tool to access a LON-CAPA URL: 
 # /adm/lti/ with LON-CAPA symb, map, or deep-link ID appended.
 #
 
@@ -286,26 +286,26 @@ sub verify_lis_item {
             my $expected_sig;
             if ($context eq 'grade') {
                 my $uniqid = $digsymb.':::'.$diguser.':::'.$cdom.'_'.$cnum;
-                $expected_sig = &get_service_id($secret,$uniqid);
+                $expected_sig = (split(/:::/,&get_service_id($secret,$uniqid)))[0]; 
                 if ($expected_sig eq $sigrec) {
                     return 1;
                 } else {
-                    $errors->{16} = 1;
+                    $errors->{17} = 1;
                 }
             } elsif ($context eq 'roster') {
                 my $uniqid = $digsymb.':::'.$cdom.'_'.$cnum;
-                $expected_sig = &get_service_id($secret,$uniqid);
+                $expected_sig = (split(/:::/,&get_service_id($secret,$uniqid)))[0]; 
                 if ($expected_sig eq $sigrec) {
                     return 1;
                 } else {
-                    $errors->{17} = 1;
+                    $errors->{18} = 1;
                 }
             }
         } else {
-            $errors->{18} = 1;
+            $errors->{19} = 1;
         }
     } else {
-        $errors->{19} = 1;
+        $errors->{20} = 1;
     }
     return;
 }
@@ -314,20 +314,24 @@ sub verify_lis_item {
 # LON-CAPA as LTI Consumer
 #
 # Sign a request used to launch an instance of an external
-# too in a LON-CAPA course, using the key and secret supplied 
+# tool in a LON-CAPA course, using the key and secret supplied 
 # by the Tool Provider.
 # 
 
 sub sign_params {
-    my ($url,$key,$secret,$paramsref) = @_;
+    my ($url,$key,$secret,$sigmethod,$paramsref) = @_;
     return unless (ref($paramsref) eq 'HASH');
+    if ($sigmethod eq '') {
+        $sigmethod = 'HMAC-SHA1';
+    }
+    srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.
     my $nonce = Digest::SHA::sha1_hex(sprintf("%06x%06x",rand(0xfffff0),rand(0xfffff0)));
     my $request = Net::OAuth->request("request token")->new(
             consumer_key => $key,
             consumer_secret => $secret,
             request_url => $url,
             request_method => 'POST',
-            signature_method => 'HMAC-SHA1',
+            signature_method => $sigmethod,
             timestamp => time,
             nonce => $nonce,
             callback => 'about:blank',
@@ -444,7 +448,7 @@ sub get_tool_lock {
 #
 
 sub release_tool_lock {
-    my ($cdom,$cnum,$marker) = @_;
+    my ($cdom,$cnum,$marker,$name) = @_;
     #  remove lock
     my @del_lock = ($name."\0".$marker."\0".'lock');
     my $dellockoutcome=&Apache::lonnet::del('exttools',\@del_lock,$cdom,$cnum);
@@ -455,4 +459,93 @@ sub release_tool_lock {
     }
 }
 
+#
+# LON-CAPA as LTI Provider
+#
+# Use the part of the launch URL after /adm/lti to determine
+# the scope for the current session (i.e., restricted to a
+# single resource, to a single folder/map, or to an entire
+# course).
+#
+# Returns an array containing scope: resource, map, or course
+# and the LON-CAPA URL that is displayed post-launch, including
+# accommodation of URL encryption, and translation of a tiny URL
+# to the actual URL
+#
+
+sub lti_provider_scope {
+    my ($tail,$cdom,$cnum) = @_;
+    my ($scope,$realuri);
+    if ($tail =~ m{^/uploaded/$cdom/$cnum/(?:default|supplemental)(?:|_\d+)\.(?:sequence|page)(|___\d+___.+)$}) {
+        my $rest = $1;
+        if ($rest eq '') {
+            $scope = 'map';
+            $realuri = $tail;
+        } else {
+            my ($map,$resid,$url) = &Apache::lonnet::decode_symb($tail);
+            $realuri = &Apache::lonnet::clutter($url);
+            if ($url =~ /\.sequence$/) {
+                $scope = 'map';
+            } else {
+                $scope = 'resource';
+                $realuri .= '?symb='.$tail;
+            }
+        }
+    } elsif ($tail =~ m{^/res/$match_domain/$match_username/.+\.(?:sequence|page)(|___\d+___.+)$}) {
+        my $rest = $1;
+        if ($rest eq '') {
+            $scope = 'map';
+            $realuri = $tail;
+        } else {
+            my ($map,$resid,$url) = &Apache::lonnet::decode_symb($tail);
+            $realuri = &Apache::lonnet::clutter($url);
+            if ($url =~ /\.sequence$/) {
+                $scope = 'map';
+            } else {
+                $scope = 'resource';
+                $realuri .= '?symb='.$tail;
+            }
+        }
+    } elsif ($tail =~ m{^/tiny/$cdom/(\w+)$}) {
+        my $key = $1;
+        my $tinyurl;
+        my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key);
+        if (defined($cached)) {
+            $tinyurl = $result;
+        } else {
+            my $configuname = &Apache::lonnet::get_domainconfiguser($cdom);
+            my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname);
+            if ($currtiny{$key} ne '') {
+                $tinyurl = $currtiny{$key};
+                &Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600);
+            }
+        }
+        if ($tinyurl ne '') {
+            my ($cnum,$symb) = split(/\&/,$tinyurl,2);
+            my ($map,$resid,$url) = &Apache::lonnet::decode_symb($symb);
+            if ($url =~ /\.(page|sequence)$/) {
+                $scope = 'map';
+            } else {
+                $scope = 'resource';
+            }
+            if ((&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i) &&
+                (!$env{'request.role.adv'})) {
+                $realuri = &Apache::lonenc::encrypted(&Apache::lonnet::clutter($url));
+                if ($scope eq 'resource') {
+                    $realuri .= '?symb='.&Apache::lonenc::encrypted($symb);
+                }
+            } else {
+                $realuri = &Apache::lonnet::clutter($url);
+                if ($scope eq 'resource') {
+                    $realuri .= '?symb='.$symb;
+                }
+            }
+        }
+    } elsif ($tail =~ m{^/$cdom/$cnum$}) {
+        $scope = 'course';
+        $realuri = '/adm/navmaps';
+    }
+    return ($scope,$realuri);
+}
+
 1;