[LON-CAPA-cvs] cvs: loncom / Lond.pm /interface domainprefs.pm lonconfigsettings.pm /lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Sun Feb 13 21:48:53 EST 2022
raeburn Mon Feb 14 02:48:53 2022 EDT
Modified files:
/loncom/interface domainprefs.pm lonconfigsettings.pm
/loncom Lond.pm
/loncom/lonnet/perl lonnet.pm
Log:
- Bug 6907
- Rename "LTI Provider" domain config item.
- Add three additional sections: "Encryption of shared secrets",
"Rules for shared secrets" and Link Protectors (domain).
- Keys used in domain for a particular library server may only be set in
a session on that server (and use Lond.pm and not lonc/lond).
- Min and max length and character requirements can be set for secrets used
for LTI-based link protection for deep-links.
-------------- next part --------------
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.404 loncom/interface/domainprefs.pm:1.405
--- loncom/interface/domainprefs.pm:1.404 Sun Feb 6 21:36:59 2022
+++ loncom/interface/domainprefs.pm Mon Feb 14 02:48:46 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: domainprefs.pm,v 1.404 2022/02/06 21:36:59 raeburn Exp $
+# $Id: domainprefs.pm,v 1.405 2022/02/14 02:48:46 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -220,10 +220,10 @@
'serverstatuses','requestcourses','helpsettings',
'coursedefaults','usersessions','loadbalancing',
'requestauthor','selfenrollment','inststatus',
- 'ltitools','ssl','trust','lti','privacy','passwords',
+ 'ltitools','ssl','trust','lti','ltisec','privacy','passwords',
'proctoring','wafproxy','ipaccess'],$dom);
my %encconfig =
- &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring'],$dom,undef,1);
+ &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1);
if (ref($domconfig{'ltitools'}) eq 'HASH') {
if (ref($encconfig{'ltitools'}) eq 'HASH') {
foreach my $id (keys(%{$domconfig{'ltitools'}})) {
@@ -248,6 +248,20 @@
}
}
}
+ if (ref($domconfig{'ltisec'}) eq 'HASH') {
+ if (ref($domconfig{'ltisec'}{'prot'}) eq 'HASH') {
+ if (ref($encconfig{'linkprot'}) eq 'HASH') {
+ foreach my $id (keys(%{$domconfig{'ltisec'}{'prot'}})) {
+ if ((ref($domconfig{'ltisec'}{'prot'}{$id}) eq 'HASH') &&
+ (ref($encconfig{'linkprot'}{$id}) eq 'HASH')) {
+ foreach my $item ('key','secret') {
+ $domconfig{'ltisec'}{'prot'}{$id}{$item} = $encconfig{'linkprot'}{$id}{$item};
+ }
+ }
+ }
+ }
+ }
+ }
if (ref($domconfig{'proctoring'}) eq 'HASH') {
if (ref($encconfig{'proctoring'}) eq 'HASH') {
foreach my $provider (keys(%{$domconfig{'proctoring'}})) {
@@ -617,10 +631,16 @@
modify => \&modify_trust,
},
'lti' =>
- {text => 'LTI Provider',
+ {text => 'LTI Link Protection and LTI Consumers',
help => 'Domain_Configuration_LTI_Provider',
- header => [{col1 => 'Setting',
- col2 => 'Value',}],
+ header => [{col1 => 'Encryption of shared secrets',
+ col2 => 'Settings'},
+ {col1 => 'Rules for shared secrets',
+ col2 => 'Settings'},
+ {col1 => 'Link Protectors (domain)',
+ col2 => 'Settings'},
+ {col1 => 'Consumers',
+ col2 => 'Settings'},],
print => \&print_lti,
modify => \&modify_lti,
},
@@ -639,7 +659,7 @@
header => [{col1 => 'Log-in Service',
col2 => 'Server Setting',},
{col1 => 'Log-in Page Items',
- col2 => ''},
+ col2 => 'Settings'},
{col1 => 'Log-in Help',
col2 => 'Value'},
{col1 => 'Custom HTML in document head',
@@ -850,7 +870,7 @@
} elsif ($action eq 'defaults') {
$output = &defaults_javascript($settings);
} elsif ($action eq 'passwords') {
- $output = &passwords_javascript();
+ $output = &passwords_javascript($action);
} elsif ($action eq 'helpsettings') {
my (%privs,%levelscurrent);
my %full=();
@@ -870,7 +890,8 @@
} elsif ($action eq 'ltitools') {
$output .= <itools_javascript($settings);
} elsif ($action eq 'lti') {
- $output .= <i_javascript($settings);
+ $output .= &passwords_javascript('secrets')."\n".
+ <i_javascript($dom,$settings);
} elsif ($action eq 'proctoring') {
$output .= &proctoring_javascript($settings);
} elsif ($action eq 'wafproxy') {
@@ -924,7 +945,7 @@
($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
- ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy')) {
+ ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy') || ($action eq 'lti')) {
$output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
} elsif ($action eq 'passwords') {
$output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
@@ -960,7 +981,7 @@
($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
($action eq 'usersessions') || ($action eq 'coursecategories') ||
($action eq 'trust') || ($action eq 'contacts') ||
- ($action eq 'privacy') || ($action eq 'passwords')) {
+ ($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti')) {
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
$colspan = ' colspan="2"';
@@ -1013,7 +1034,8 @@
</tr>'."\n";
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
- } elsif (($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'passwords')) {
+ } elsif (($action eq 'contacts') || ($action eq 'privacy') ||
+ ($action eq 'passwords') || ($action eq 'lti')) {
if ($action eq 'passwords') {
$output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);
} else {
@@ -1250,8 +1272,8 @@
$output .= &print_quotas($dom,$settings,\$rowtotal,$action);
} elsif (($action eq 'autoenroll') || ($action eq 'autocreate') ||
($action eq 'serverstatuses') || ($action eq 'loadbalancing') ||
- ($action eq 'ltitools') || ($action eq 'lti') ||
- ($action eq 'proctoring') || ($action eq 'ipaccess')) {
+ ($action eq 'ltitools') || ($action eq 'proctoring') ||
+ ($action eq 'ipaccess')) {
$output .= $item->{'print'}->($dom,$settings,\$rowtotal);
}
}
@@ -3386,8 +3408,8 @@
sub lti_javascript {
- my ($settings) = @_;
- my $togglejs = <i_toggle_js();
+ my ($dom,$settings) = @_;
+ my $togglejs = <i_toggle_js($dom);
unless (ref($settings) eq 'HASH') {
return $togglejs;
}
@@ -3460,12 +3482,17 @@
}
sub lti_toggle_js {
+ my ($dom) = @_;
my %lcauthparmtext = &Apache::lonlocal::texthash (
localauth => 'Local auth argument',
krb => 'Kerberos domain',
);
my $crsincalert = &mt('"User\'s identity sent" needs to be set to "Yes" first,[_1] before setting "Course\'s identity sent" to "Yes"',"\n");
&js_escape(\$crsincalert);
+ my %servers = &Apache::lonnet::get_servers($dom,'library');
+ my $primary = &Apache::lonnet::domain($dom,'primary');
+ my $course_servers = "'".join("','",keys(%servers))."'";
+
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
@@ -3668,6 +3695,125 @@
}
return;
}
+
+function toggleLTIEncKey(form) {
+ var shownhosts = new Array();
+ var hiddenhosts = new Array();
+ var forcourse = new Array($course_servers);
+ var fromdomain = '$primary';
+ var crsradio = form.elements['ltisec_crslinkprot'];
+ if (crsradio.length) {
+ for (var i=0; i<crsradio.length; i++) {
+ if (crsradio[i].checked) {
+ if (crsradio[i].value == 1) {
+ if (forcourse.length > 0) {
+ for (var j=0; j<forcourse.length; j++) {
+ if (!shownhosts.includes(forcourse[j])) {
+ shownhosts.push(forcourse[j]);
+ }
+ }
+ }
+ } else {
+ if (forcourse.length > 0) {
+ for (var j=0; j<forcourse.length; j++) {
+ if (!hiddenhosts.includes(forcourse[j])) {
+ hiddenhosts.push(forcourse[j]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ var domradio = form.elements['ltisec_domlinkprot'];
+ if (domradio.length) {
+ for (var i=0; i<domradio.length; i++) {
+ if (domradio[i].checked) {
+ if (domradio[i].value == 1) {
+ if (!shownhosts.includes(fromdomain)) {
+ shownhosts.push(fromdomain);
+ }
+ } else {
+ if (!hiddenhosts.includes(fromdomain)) {
+ hiddenhosts.push(fromdomain);
+ }
+ }
+ }
+ }
+ }
+ var consumersradio = form.elements['ltisec_consumers'];
+ if (consumersradio.length) {
+ for (var i=0; i<consumersradio.length; i++) {
+ if (consumersradio[i].checked) {
+ if (consumersradio[i].value == 1) {
+ if (!shownhosts.includes(fromdomain)) {
+ shownhosts.push(fromdomain);
+ }
+ } else {
+ if (!hiddenhosts.includes(fromdomain)) {
+ hiddenhosts.push(fromdomain);
+ }
+ }
+ }
+ }
+ }
+ if (shownhosts.length > 0) {
+ for (var i=0; i<shownhosts.length; i++) {
+ if (document.getElementById('ltisec_info_'+shownhosts[i])) {
+ document.getElementById('ltisec_info_'+shownhosts[i]).style.display = 'block';
+ }
+ }
+ if (document.getElementById('ltisec_noprivkey')) {
+ document.getElementById('ltisec_noprivkey').style.display = 'none';
+ }
+ } else {
+ if (document.getElementById('ltisec_noprivkey')) {
+ document.getElementById('ltisec_noprivkey').style.display = 'inline-block';
+ }
+ }
+ if (hiddenhosts.length > 0) {
+ for (var i=0; i<hiddenhosts.length; i++) {
+ if (!shownhosts.includes(hiddenhosts[i])) {
+ if (document.getElementById('ltisec_info_'+hiddenhosts[i])) {
+ document.getElementById('ltisec_info_'+hiddenhosts[i]).style.display = 'none';
+ }
+ }
+ }
+ }
+ return;
+}
+
+function togglePrivKey(form,hostid) {
+ var radioname = '';
+ var currdivid = '';
+ var newdivid = '';
+ if ((document.getElementById('ltisec_divcurrprivkey_'+hostid)) &&
+ (document.getElementById('ltisec_divchgprivkey_'+hostid))) {
+ currdivid = document.getElementById('ltisec_divcurrprivkey_'+hostid);
+ newdivid = document.getElementById('ltisec_divchgprivkey_'+hostid);
+ radioname = form.elements['ltisec_changeprivkey_'+hostid];
+ if (radioname) {
+ if (radioname.length > 0) {
+ var setvis;
+ for (var i=0; i<radioname.length; i++) {
+ if (radioname[i].checked == true) {
+ if (radioname[i].value == 1) {
+ newdivid.style.display = 'inline-block';
+ currdivid.style.display = 'none';
+ setvis = 1;
+ }
+ break;
+ }
+ }
+ if (!setvis) {
+ newdivid.style.display = 'none';
+ currdivid.style.display = 'inline-block';
+ }
+ }
+ }
+ }
+}
+
// ]]>
</script>
@@ -6308,144 +6454,286 @@
}
sub print_lti {
- my ($dom,$settings,$rowtotal) = @_;
+ my ($position,$dom,$settings,$rowtotal) = @_;
my $itemcount = 1;
- my $maxnum = 0;
- my $css_class;
- my %ordered;
+ my ($datatable,$css_class);
+ my (%rules,%encrypt,%privkeys,%linkprot);
if (ref($settings) eq 'HASH') {
- foreach my $item (keys(%{$settings})) {
- if (ref($settings->{$item}) eq 'HASH') {
- my $num = $settings->{$item}{'order'};
- if ($num eq '') {
- $num = scalar(keys(%{$settings}));
+ if ($position eq 'top') {
+ if (exists($settings->{'encrypt'})) {
+ if (ref($settings->{'encrypt'}) eq 'HASH') {
+ foreach my $key (keys(%{$settings->{'encrypt'}})) {
+ if ($key eq 'consumers') {
+ $encrypt{'ltisec_'.$key} = $settings->{'encrypt'}{$key};
+ } else {
+ $encrypt{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key};
+ }
+ }
+ }
+ }
+ if (exists($settings->{'private'})) {
+ if (ref($settings->{'private'}) eq 'HASH') {
+ if (ref($settings->{'private'}) eq 'HASH') {
+ if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {
+ map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});
+ }
+ }
+ }
+ }
+ } elsif ($position eq 'middle') {
+ if (exists($settings->{'rules'})) {
+ if (ref($settings->{'rules'}) eq 'HASH') {
+ %rules = %{$settings->{'rules'}};
+ }
+ }
+ } elsif ($position eq 'lower') {
+ if (exists($settings->{'linkprot'})) {
+ if (ref($settings->{'linkprot'}) eq 'HASH') {
+ %linkprot = %{$settings->{'linkprot'}};
+ }
+ }
+ } else {
+ foreach my $key ('encrypt','private','rules','linkprot') {
+ if (exists($settings->{$key})) {
+ delete($settings->{$key});
}
- $ordered{$num} = $item;
}
}
}
- my $maxnum = scalar(keys(%ordered));
- my $datatable;
- my %lt = <i_names();
- if (keys(%ordered)) {
- my @items = sort { $a <=> $b } keys(%ordered);
- for (my $i=0; $i<@items; $i++) {
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- my $item = $ordered{$items[$i]};
- my ($key,$secret,$lifetime,$consumer,$requser,$crsinc,$current);
- if (ref($settings->{$item}) eq 'HASH') {
- $key = $settings->{$item}->{'key'};
- $secret = $settings->{$item}->{'secret'};
- $lifetime = $settings->{$item}->{'lifetime'};
- $consumer = $settings->{$item}->{'consumer'};
- $requser = $settings->{$item}->{'requser'};
- $crsinc = $settings->{$item}->{'crsinc'};
- $current = $settings->{$item};
- }
- my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';
- my %checkedrequser = (
- yes => ' checked="checked"',
- no => '',
- );
- if (!$requser) {
- $checkedrequser{'no'} = $checkedrequser{'yes'};
- $checkedrequser{'yes'} = '';
+ if ($position eq 'top') {
+ my @ids=&Apache::lonnet::current_machine_ids();
+ my %servers = &Apache::lonnet::get_servers($dom,'library');
+ my $primary = &Apache::lonnet::domain($dom,'primary');
+ my ($extra,$numshown);
+ foreach my $hostid (sort(keys(%servers))) {
+ my ($showextra,$divsty,$switch);
+ if ($hostid eq $primary) {
+ if (($encrypt{'ltisec_consumers'}) || ($encrypt{'ltisec_domlinkprot'})) {
+ $showextra = 1;
+ }
+ }
+ if ($encrypt{'ltisec_crslinkprot'}) {
+ $showextra = 1;
+ }
+ unless (grep(/^\Q$hostid\E$/, at ids)) {
+ $switch = 1;
+ }
+ if ($showextra) {
+ $numshown ++;
+ $divsty = 'display:inline-block';
+ } else {
+ $divsty = 'display:none';
+ }
+ $extra .= '<fieldset id="ltisec_info_'.$hostid.'" style="'.$divsty.'">'.
+ '<legend>'.$hostid.'</legend>';
+ if ($switch) {
+ my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&role='.
+ &HTML::Entities::encode($env{'request.role'},'\'<>"&').
+ '&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
+ if (exists($privkeys{$hostid})) {
+ $extra .= '<div id="ltisec_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'.
+ '<span class="LC_nobreak">'.
+ &mt('Encryption Key').': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'.
+ '<span class="LC_nobreak">'.&mt('Change?').
+ '<label><input type="radio" value="0" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'.
+ (' 'x2).
+ '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes').
+ '</label> </span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'.
+ '<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).
+ '</span></div>';
+ } else {
+ $extra .= '<span class="LC_nobreak">'.
+ &mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).
+ '</span>'."\n";
+ }
+ } elsif (exists($privkeys{$hostid})) {
+ $extra .= '<div id="ltisec_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'.
+ &mt('Encryption Key').': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'.
+ '<span class="LC_nobreak">'.&mt('Change?').
+ '<label><input type="radio" value="0" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'.
+ (' 'x2).
+ '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes').
+ '</label> </span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'.
+ '<span class="LC_nobreak">'.&mt('New Key').':'.
+ '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="off" />'.
+ '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
+ '</span></div>';
+ } else {
+ $extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'.
+ '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="off" />'.
+ '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';
+ }
+ $extra .= '</fieldset>';
+ }
+ my %choices = &Apache::lonlocal::texthash (
+ ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses',
+ ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain',
+ ltisec_consumers => 'Encrypt stored consumer secrets defined in domain',
+ );
+ my @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers);
+ my %defaultchecked = (
+ 'ltisec_crslinkprot' => 'off',
+ 'ltisec_domlinkprot' => 'off',
+ 'ltisec_consumers' => 'off',
+ );
+ my ($onclick,$itemcount);
+ $onclick = 'javascript:toggleLTIEncKey(this.form);';
+ ($datatable,$itemcount) = &radiobutton_prefs(\%encrypt,\@toggles,\%defaultchecked,
+ \%choices,$itemcount,$onclick,'','left','no');
+
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $noprivkeysty = 'display:inline-block';
+ if ($numshown) {
+ $noprivkeysty = 'display:none';
+ }
+ $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.
+ '<td><div id="ltisec_noprivkey" style="'.$noprivkeysty.'" >'.
+ '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.
+ $extra.
+ '</td></tr>';
+ $itemcount ++;
+ $$rowtotal += $itemcount;
+ } elsif ($position eq 'middle') {
+ $datatable = &password_rules('secrets',\$itemcount,\%rules);
+ } elsif ($position eq 'lower') {
+ $datatable .= '<tr><td>Not set yet</td><td>To be done</td></tr>';
+ } else {
+ my $maxnum = 0;
+ my %ordered;
+ if (ref($settings) eq 'HASH') {
+ foreach my $item (keys(%{$settings})) {
+ if (ref($settings->{$item}) eq 'HASH') {
+ my $num = $settings->{$item}{'order'};
+ if ($num eq '') {
+ $num = scalar(keys(%{$settings}));
+ }
+ $ordered{$num} = $item;
+ }
}
- my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"';
- my %checkedcrsinc = (
+ }
+ $maxnum = scalar(keys(%ordered));
+ my %lt = <i_names();
+ if (keys(%ordered)) {
+ my @items = sort { $a <=> $b } keys(%ordered);
+ for (my $i=0; $i<@items; $i++) {
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $item = $ordered{$items[$i]};
+ my ($key,$secret,$lifetime,$consumer,$requser,$crsinc,$current);
+ if (ref($settings->{$item}) eq 'HASH') {
+ $key = $settings->{$item}->{'key'};
+ $secret = $settings->{$item}->{'secret'};
+ $lifetime = $settings->{$item}->{'lifetime'};
+ $consumer = $settings->{$item}->{'consumer'};
+ $requser = $settings->{$item}->{'requser'};
+ $crsinc = $settings->{$item}->{'crsinc'};
+ $current = $settings->{$item};
+ }
+ my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';
+ my %checkedrequser = (
+ yes => ' checked="checked"',
+ no => '',
+ );
+ if (!$requser) {
+ $checkedrequser{'no'} = $checkedrequser{'yes'};
+ $checkedrequser{'yes'} = '';
+ }
+ my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"';
+ my %checkedcrsinc = (
yes => ' checked="checked"',
no => '',
- );
- if (!$crsinc) {
- $checkedcrsinc{'no'} = $checkedcrsinc{'yes'};
- $checkedcrsinc{'yes'} = '';
- }
- my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';
- $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
- .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';
- for (my $k=0; $k<=$maxnum; $k++) {
- my $vpos = $k+1;
- my $selstr;
- if ($k == $i) {
- $selstr = ' selected="selected" ';
+ );
+ if (!$crsinc) {
+ $checkedcrsinc{'no'} = $checkedcrsinc{'yes'};
+ $checkedcrsinc{'yes'} = '';
+ }
+ my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';
+ $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
+ .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';
+ for (my $k=0; $k<=$maxnum; $k++) {
+ my $vpos = $k+1;
+ my $selstr;
+ if ($k == $i) {
+ $selstr = ' selected="selected" ';
+ }
+ $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
- $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
+ $datatable .= '</select>'.(' 'x2).
+ '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.
+ &mt('Delete?').'</label></span></td>'.
+ '<td colspan="2">'.
+ '<fieldset><legend>'.&mt('Required settings').'</legend>'.
+ '<span class="LC_nobreak">'.$lt{'consumer'}.
+ ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.
+ '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.
+ 'value="'.$lifetime.'" size="3" /></span>'.
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'requser'}.':'.
+ '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label> '."\n".
+ '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".
+ '<br /><br />'.
+ '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
+ '<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label> '."\n".
+ '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".
+ (' 'x4).
+ '<span class="LC_nobreak">'.$lt{'key'}.
+ ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '.
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'secret'}.':'.
+ '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'.
+ '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
+ '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
+ '</fieldset>'.<i_options($i,$current,$itemcount,%lt).'</td></tr>';
+ $itemcount ++;
}
- $datatable .= '</select>'.(' 'x2).
- '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.
- &mt('Delete?').'</label></span></td>'.
- '<td colspan="2">'.
- '<fieldset><legend>'.&mt('Required settings').'</legend>'.
- '<span class="LC_nobreak">'.$lt{'consumer'}.
- ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.
- '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.
- 'value="'.$lifetime.'" size="3" /></span>'.
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'requser'}.':'.
- '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label> '."\n".
- '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".
- '<br /><br />'.
- '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
- '<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label> '."\n".
- '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".
- (' 'x4).
- '<span class="LC_nobreak">'.$lt{'key'}.
- ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '.
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'secret'}.':'.
- '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'.
- '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
- '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
- '</fieldset>'.<i_options($i,$current,$itemcount,%lt).'</td></tr>';
- $itemcount ++;
}
- }
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';
- $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
- '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".
- '<select name="lti_pos_add"'.$chgstr.'>';
- for (my $k=0; $k<$maxnum+1; $k++) {
- my $vpos = $k+1;
- my $selstr;
- if ($k == $maxnum) {
- $selstr = ' selected="selected" ';
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';
+ $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
+ '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".
+ '<select name="lti_pos_add"'.$chgstr.'>';
+ for (my $k=0; $k<$maxnum+1; $k++) {
+ my $vpos = $k+1;
+ my $selstr;
+ if ($k == $maxnum) {
+ $selstr = ' selected="selected" ';
+ }
+ $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
- $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
+ $datatable .= '</select> '."\n".
+ '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".
+ '<td colspan="2">'.
+ '<fieldset><legend>'.&mt('Required settings').'</legend>'.
+ '<span class="LC_nobreak">'.$lt{'consumer'}.
+ ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
+ '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span> '."\n".
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'requser'}.':'.
+ '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n".
+ '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".
+ '<br /><br />'.
+ '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
+ '<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n".
+ '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".
+ (' 'x4).
+ '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n".
+ (' 'x2).
+ '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'.
+ '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".
+ '</fieldset>'.<i_options('add',undef,$itemcount,%lt).
+ '</td>'."\n".
+ '</tr>'."\n";
+ $itemcount ++;
}
- $datatable .= '</select> '."\n".
- '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".
- '<td colspan="2">'.
- '<fieldset><legend>'.&mt('Required settings').'</legend>'.
- '<span class="LC_nobreak">'.$lt{'consumer'}.
- ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
- '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span> '."\n".
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'requser'}.':'.
- '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n".
- '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".
- '<br /><br />'.
- '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
- '<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n".
- '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".
- (' 'x4).
- '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n".
- (' 'x2).
- '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'.
- '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".
- '</fieldset>'.<i_options('add',undef,$itemcount,%lt).
- '</td>'."\n".
- '</tr>'."\n";
- $$rowtotal ++;
- return $datatable;;
+ $$rowtotal += $itemcount;
+ return $datatable;
}
sub lti_names {
@@ -6847,6 +7135,22 @@
);
}
+sub check_switchserver {
+ my ($home) = @_;
+ my $switchserver;
+ if ($home ne '') {
+ my $allowed;
+ my @ids=&Apache::lonnet::current_machine_ids();
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
+ if (!$allowed) {
+ $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&role='.
+ &HTML::Entities::encode($env{'request.role'},'\'<>"&').
+ '&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
+ }
+ }
+ return $switchserver;
+}
+
sub print_coursedefaults {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked, at toggles);
@@ -6863,7 +7167,7 @@
postsubmit => 'Disable submit button/keypress following student submission',
canclone => "People who may clone a course (besides course's owner and coordinators)",
mysqltables => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
- ltiauth => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',
+ ltiauth => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',
);
my %staticdefaults = (
anonsurvey_threshold => 10,
@@ -6986,12 +7290,12 @@
my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);
my $currusecredits = 0;
my $postsubmitclient = 1;
- my $ltiauth = 0;
+ my $ltiauth = 0;
my @types = ('official','unofficial','community','textbook','placement');
if (ref($settings) eq 'HASH') {
if ($settings->{'ltiauth'}) {
$ltiauth = 1;
- }
+ }
$currdefresponder = $settings->{'anonsurvey_threshold'};
if (ref($settings->{'uploadquota'}) eq 'HASH') {
foreach my $type (keys(%{$settings->{'uploadquota'}})) {
@@ -7800,95 +8104,7 @@
$itemcount ++;
}
} elsif ($position eq 'lower') {
- my ($min,$max,%chars,$expire,$numsaved);
- $min = $Apache::lonnet::passwdmin;
- if (ref($settings) eq 'HASH') {
- if ($settings->{min}) {
- $min = $settings->{min};
- }
- if ($settings->{max}) {
- $max = $settings->{max};
- }
- if (ref($settings->{chars}) eq 'ARRAY') {
- map { $chars{$_} = 1; } (@{$settings->{chars}});
- }
- if ($settings->{expire}) {
- $expire = $settings->{expire};
- }
- if ($settings->{numsaved}) {
- $numsaved = $settings->{numsaved};
- }
- }
- my %rulenames = &Apache::lonlocal::texthash(
- uc => 'At least one upper case letter',
- lc => 'At least one lower case letter',
- num => 'At least one number',
- spec => 'At least one non-alphanumeric',
- );
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
- '<td class="LC_left_item"><span class="LC_nobreak">'.
- '<input type="text" name="passwords_min" value="'.$min.'" size="3" '.
- 'onblur="javascript:warnIntPass(this);" />'.
- '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.
- '</span></td></tr>';
- $itemcount ++;
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
- '<td class="LC_left_item"><span class="LC_nobreak">'.
- '<input type="text" name="passwords_max" value="'.$max.'" size="3" '.
- 'onblur="javascript:warnIntPass(this);" />'.
- '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
- '</span></td></tr>';
- $itemcount ++;
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
- '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
- '</span></td>';
- my $numinrow = 2;
- my @possrules = ('uc','lc','num','spec');
- $datatable .= '<td class="LC_left_item"><table>';
- for (my $i=0; $i<@possrules; $i++) {
- my ($rem,$checked);
- if ($chars{$possrules[$i]}) {
- $checked = ' checked="checked"';
- }
- $rem = $i%($numinrow);
- if ($rem == 0) {
- if ($i > 0) {
- $datatable .= '</tr>';
- }
- $datatable .= '<tr>';
- }
- $datatable .= '<td><span class="LC_nobreak"><label>'.
- '<input type="checkbox" name="passwords_chars" value="'.$possrules[$i].'"'.$checked.' />'.
- $rulenames{$possrules[$i]}.'</label></span></td>';
- }
- my $rem = @possrules%($numinrow);
- my $colsleft = $numinrow - $rem;
- if ($colsleft > 1 ) {
- $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
- ' </td>';
- } elsif ($colsleft == 1) {
- $datatable .= '<td class="LC_left_item"> </td>';
- }
- $datatable .='</table></td></tr>';
- $itemcount ++;
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.
- '<td class="LC_left_item"><span class="LC_nobreak">'.
- '<input type="text" name="passwords_expire" value="'.$expire.'" size="4" '.
- 'onblur="javascript:warnIntPass(this);" />'.
- '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
- '</span></td></tr>';
- $itemcount ++;
- $css_class = $itemcount%2?' class="LC_odd_row"':'';
- $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
- '<td class="LC_left_item"><span class="LC_nobreak">'.
- '<input type="text" name="passwords_numsaved" value="'.$numsaved.'" size="3" '.
- 'onblur="javascript:warnIntPass(this);" />'.
- '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.
- '</span></td></tr>';
+ $datatable .= &password_rules('passwords',\$itemcount,$settings);
} else {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my %ownerchg = (
@@ -7948,6 +8164,129 @@
return $datatable;
}
+sub password_rules {
+ my ($prefix,$itemcountref,$settings) = @_;
+ my ($min,$max,%chars,$expire,$numsaved,$numinrow);
+ my %titles;
+ if ($prefix eq 'passwords') {
+ %titles = &Apache::lonlocal::texthash (
+ min => 'Minimum password length',
+ max => 'Maximum password length',
+ chars => 'Required characters',
+ );
+ } elsif ($prefix eq 'secrets') {
+ %titles = &Apache::lonlocal::texthash (
+ min => 'Minimum secret length',
+ max => 'Maximum secret length',
+ chars => 'Required characters',
+ );
+ }
+ $min = $Apache::lonnet::passwdmin;
+ my $datatable;
+ my $itemcount;
+ if (ref($itemcountref)) {
+ $itemcount = $$itemcountref;
+ }
+ if (ref($settings) eq 'HASH') {
+ if ($settings->{min}) {
+ $min = $settings->{min};
+ }
+ if ($settings->{max}) {
+ $max = $settings->{max};
+ }
+ if (ref($settings->{chars}) eq 'ARRAY') {
+ map { $chars{$_} = 1; } (@{$settings->{chars}});
+ }
+ if ($prefix eq 'passwords') {
+ if ($settings->{expire}) {
+ $expire = $settings->{expire};
+ }
+ if ($settings->{numsaved}) {
+ $numsaved = $settings->{numsaved};
+ }
+ }
+ }
+ my %rulenames = &Apache::lonlocal::texthash(
+ uc => 'At least one upper case letter',
+ lc => 'At least one lower case letter',
+ num => 'At least one number',
+ spec => 'At least one non-alphanumeric',
+ );
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="'.$prefix.'_min" value="'.$min.'" size="3" '.
+ 'onblur="javascript:warnInt'.$prefix.'(this);" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.
+ '</span></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="'.$prefix.'_max" value="'.$max.'" size="3" '.
+ 'onblur="javascript:warnInt'.$prefix.'(this);" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
+ '</span></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
+ '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
+ '</span></td>';
+ my $numinrow = 2;
+ my @possrules = ('uc','lc','num','spec');
+ $datatable .= '<td class="LC_left_item"><table>';
+ for (my $i=0; $i<@possrules; $i++) {
+ my ($rem,$checked);
+ if ($chars{$possrules[$i]}) {
+ $checked = ' checked="checked"';
+ }
+ $rem = $i%($numinrow);
+ if ($rem == 0) {
+ if ($i > 0) {
+ $datatable .= '</tr>';
+ }
+ $datatable .= '<tr>';
+ }
+ $datatable .= '<td><span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'.
+ $rulenames{$possrules[$i]}.'</label></span></td>';
+ }
+ my $rem = @possrules%($numinrow);
+ my $colsleft = $numinrow - $rem;
+ if ($colsleft > 1 ) {
+ $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
+ ' </td>';
+ } elsif ($colsleft == 1) {
+ $datatable .= '<td class="LC_left_item"> </td>';
+ }
+ $datatable .='</table></td></tr>';
+ $itemcount ++;
+ if ($prefix eq 'passwords') {
+ $titles{'expire'} = &mt('Password expiration (days)');
+ $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="'.$prefix.'_expire" value="'.$expire.'" size="4" '.
+ 'onblur="javascript:warnInt'.$prefix.'(this);" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
+ '</span></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.
+ 'onblur="javascript:warnInt'.$prefix.'(this);" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.
+ '</span></td></tr>';
+ $itemcount ++;
+ }
+ if (ref($itemcountref)) {
+ $$itemcountref += $itemcount;
+ }
+ return $datatable;
+}
+
sub print_wafproxy {
my ($position,$dom,$settings,$rowtotal) = @_;
my $css_class;
@@ -11168,17 +11507,27 @@
}
sub passwords_javascript {
- my %intalert = &Apache::lonlocal::texthash (
- authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.',
- authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',
- passmin => 'Warning: minimum password length must be a positive integer greater than 6.',
- passmax => 'Warning: maximum password length must be a positive integer (or blank).',
- passexp => 'Warning: days before password expiration must be a positive integer (or blank).',
- passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',
- );
+ my ($prefix) = @_;
+ my %intalert;
+ if ($prefix eq 'passwords') {
+ %intalert = &Apache::lonlocal::texthash (
+ authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.',
+ authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',
+ passmin => 'Warning: minimum password length must be a positive integer greater than 6.',
+ passmax => 'Warning: maximum password length must be a positive integer (or blank).',
+ passexp => 'Warning: days before password expiration must be a positive integer (or blank).',
+ passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',
+ );
+ } elsif ($prefix eq 'secrets') {
+ %intalert = &Apache::lonlocal::texthash (
+ passmin => 'Warning: minimum secret length must be a positive integer greater than 6.',
+ passmax => 'Warning: maximum secret length must be a positive integer (or blank).',
+ );
+ }
&js_escape(\%intalert);
my $defmin = $Apache::lonnet::passwdmin;
- my $intauthjs = <<"ENDSCRIPT";
+ my $intauthjs;
+ if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";
function warnIntAuth(field) {
if (field.name == 'intauth_check') {
@@ -11198,11 +11547,17 @@
return;
}
-function warnIntPass(field) {
+ENDSCRIPT
+
+ }
+
+ $intauthjs .= <<"ENDSCRIPT";
+
+function warnInt$prefix(field) {
field.value.replace(/^\s+/,'');
field.value.replace(/\s+\$/,'');
var regexdigit=/^\\d+\$/;
- if (field.name == 'passwords_min') {
+ if (field.name == '$prefix\_min') {
if (field.value == '') {
alert('$intalert{passmin}');
field.value = '$defmin';
@@ -11222,7 +11577,7 @@
field.value = '';
}
if (field.value != '') {
- if (field.name == 'passwords_expire') {
+ if (field.name == '$prefix\_expire') {
var regexpposnum=/^\\d+(|\\.\\d*)\$/;
if (!regexpposnum.test(field.value)) {
alert('$intalert{passexp}');
@@ -11236,10 +11591,10 @@
}
} else {
if (!regexdigit.test(field.value)) {
- if (field.name == 'passwords_max') {
+ if (field.name == '$prefix\_max') {
alert('$intalert{passmax}');
} else {
- if (field.name == 'passwords_numsaved') {
+ if (field.name == '$prefix\_numsaved') {
alert('$intalert{passnum}');
}
}
@@ -15473,6 +15828,73 @@
my %menutitles = <imenu_titles();
+ my (%currltisec,%secchanges,%newltisec,%keyset,%newkeyset);
+ $newltisec{'private'}{'keys'} = [];
+ $newltisec{'encrypt'} = {};
+ $newltisec{'rules'} = {};
+ if (ref($domconfig{'ltisec'}) eq 'HASH') {
+ %currltisec = %{$domconfig{'ltisec'}};
+ if (ref($currltisec{'private'}) eq 'HASH') {
+ if (ref($currltisec{'private'}{'keys'}) eq 'ARRAY') {
+ $newltisec{'private'}{'keys'} = $currltisec{'private'}{'keys'};
+ map { $keyset{$_} = 1; } @{$currltisec{'private'}{'keys'}};
+ }
+ }
+ }
+ foreach my $item ('crs','dom','consumers') {
+ my $formelement;
+ if ($item eq 'consumers') {
+ $formelement = 'form.ltisec_'.$item;
+ } else {
+ $formelement = 'form.ltisec_'.$item.'linkprot';
+ }
+ if ($env{$formelement}) {
+ $newltisec{'encrypt'}{$item} = 1;
+ if (ref($currltisec{'encrypt'}) eq 'HASH') {
+ unless ($currltisec{'encrypt'}{$item}) {
+ $secchanges{'encrypt'} = 1;
+ }
+ } else {
+ $secchanges{'encrypt'} = 1;
+ }
+ } elsif (ref($currltisec{'encrypt'}) eq 'HASH') {
+ if ($currltisec{'encrypt'}{$item}) {
+ $secchanges{'encrypt'} = 1;
+ }
+ }
+ }
+ unless (exists($currltisec{'rules'})) {
+ $currltisec{'rules'} = {};
+ }
+ &password_rule_changes('secrets',$newltisec{'rules'},$currltisec{'rules'},\%secchanges);
+
+ my @ids=&Apache::lonnet::current_machine_ids();
+ my %servers = &Apache::lonnet::get_servers($dom,'library');
+
+ foreach my $hostid (keys(%servers)) {
+ if (($hostid ne '') && (grep(/^\Q$hostid\E$/, at ids))) {
+ my $newkey;
+ my $keyitem = 'form.ltisec_privkey_'.$hostid;
+ if (exists($env{$keyitem})) {
+ $env{$keyitem} =~ s/(`)/'/g;
+ if ($keyset{$hostid}) {
+ if ($env{'form.ltisec_changeprivkey_'.$hostid}) {
+ if ($env{$keyitem} ne '') {
+ $secchanges{'private'} = 1;
+ $newkeyset{$hostid} = $env{$keyitem};
+ }
+ }
+ } elsif ($env{$keyitem} ne '') {
+ unless (grep(/^\Q$hostid\E$/,@{$newltisec{'private'}{'keys'}})) {
+ push(@{$newltisec{'private'}{'keys'}},$hostid);
+ }
+ $secchanges{'private'} = 1;
+ $newkeyset{$hostid} = $env{$keyitem};
+ }
+ }
+ }
+ }
+
my (@items,%deletions,%itemids);
if ($env{'form.lti_add'}) {
my $consumer = $env{'form.lti_consumer_add'};
@@ -15538,14 +15960,14 @@
}
if ($confhash{$itemid}{'requser'}) {
if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {
- $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';
+ $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';
} elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {
$confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';
} elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {
my $mapuser = $env{'form.lti_customuser_'.$idx};
$mapuser =~ s/(`)/'/g;
- $mapuser =~ s/^\s+|\s+$//g;
- $confhash{$itemid}{'mapuser'} = $mapuser;
+ $mapuser =~ s/^\s+|\s+$//g;
+ $confhash{$itemid}{'mapuser'} = $mapuser;
}
my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx);
my @makeuser;
@@ -15776,15 +16198,109 @@
}
}
my %ltihash = (
- $action => { %confhash }
- );
- my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,
- $dom);
+ $action => { %confhash }
+ );
+ if (keys(%secchanges)) {
+ $ltihash{'ltisec'} = \%newltisec;
+ }
+ my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);
if ($putresult eq 'ok') {
+ my %keystore;
+ if (keys(%secchanges)) {
+ if ($secchanges{'private'}) {
+ my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});
+ foreach my $hostid (keys(%newkeyset)) {
+ my $storehash = {
+ key => $newkeyset{$hostid},
+ who => $env{'user.name'}.':'.$env{'user.domain'},
+ };
+ $keystore{$hostid} = &Apache::lonnet::store_dom($storehash,'lti','private',
+ $dom,$hostid);
+ }
+ }
+ }
my %ltienchash = (
$action => { %encconfig }
);
&Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);
+ if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {
+ return &mt('No changes made.');
+ }
+ $resulttext = &mt('Changes made:').'<ul>';
+ if (keys(%secchanges) > 0) {
+ foreach my $item (keys(%secchanges)) {
+ if ($item eq 'encrypt') {
+ my %encrypted = (
+ crs => {
+ on => &mt('Encryption of stored link protection secrets defined in courses enabled'),
+ off => &mt('Encryption of stored link protection secrets defined in courses disabled'),
+ },
+ dom => {
+ on => &mt('Encryption of stored link protection secrets defined in domain enabled'),
+ off => &mt('Encryption of stored link protection secrets defined in domain disabled'),
+ },
+ consumers => {
+ on => &mt('Encryption of stored consumer secrets defined in domain enabled'),
+ off => &mt('Encryption of stored consumer secrets defined in domain disabled'),
+ },
+ );
+ foreach my $type ('crs','dom','consumers') {
+ my $shown = $encrypted{$type}{'off'};
+ if (ref($newltisec{$item}) eq 'HASH') {
+ if ($newltisec{$item}{$type}) {
+ $shown = $encrypted{$type}{'on'};
+ }
+ }
+ $resulttext .= '<li>'.$shown.'</li>';
+ }
+ } elsif ($item eq 'rules') {
+ my %titles = &Apache::lonlocal::texthash(
+ min => 'Minimum password length',
+ max => 'Maximum password length',
+ chars => 'Required characters',
+ );
+ foreach my $rule ('min','max') {
+ if ($newltisec{rules}{$rule} eq '') {
+ if ($rule eq 'min') {
+ $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
+ ' '.&mt('Default of [_1] will be used',
+ $Apache::lonnet::passwdmin).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newltisec{rules}{$rule}).'</li>';
+ }
+ }
+ if (ref($newltisec{'rules'}{'chars'}) eq 'ARRAY') {
+ if (@{$newltisec{'rules'}{'chars'}} > 0) {
+ my %rulenames = &Apache::lonlocal::texthash(
+ uc => 'At least one upper case letter',
+ lc => 'At least one lower case letter',
+ num => 'At least one number',
+ spec => 'At least one non-alphanumeric',
+ );
+ my $needed = '<ul><li>'.
+ join('</li><li>',map {$rulenames{$_} } @{$newltisec{'rules'}{'chars'}}).
+ '</li></ul>';
+ $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
+ }
+ } elsif ($item eq 'private') {
+ if (keys(%newkeyset)) {
+ foreach my $hostid (sort(keys(%newkeyset))) {
+ if ($keystore{$hostid} eq 'ok') {
+ $resulttext .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';
+ }
+ }
+ }
+ }
+ }
+ }
if (keys(%changes) > 0) {
my $cachetime = 24*60*60;
my %ltiall = %confhash;
@@ -15799,7 +16315,6 @@
if (ref($lastactref) eq 'HASH') {
$lastactref->{'lti'} = 1;
}
- $resulttext = &mt('Changes made:').'<ul>';
my %bynum;
foreach my $itemid (sort(keys(%changes))) {
my $position = $confhash{$itemid}{'order'};
@@ -15976,10 +16491,8 @@
$resulttext .= '</ul></li>';
}
}
- $resulttext .= '</ul>';
- } else {
- $resulttext = &mt('No changes made.');
}
+ $resulttext .= '</ul>';
} else {
$errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
}
@@ -17705,61 +18218,7 @@
$updatedefaults = 1;
}
}
- foreach my $rule ('min','max','expire','numsaved') {
- $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g;
- my $ruleok;
- if ($rule eq 'expire') {
- if (($env{'form.passwords_'.$rule} =~ /^\d+(|\.\d*)$/) &&
- ($env{'form.passwords_'.$rule} ne '0')) {
- $ruleok = 1;
- }
- } elsif ($rule eq 'min') {
- if ($env{'form.passwords_'.$rule} =~ /^\d+$/) {
- if ($env{'form.passwords_'.$rule} >= $Apache::lonnet::passwdmin) {
- $ruleok = 1;
- }
- }
- } elsif (($env{'form.passwords_'.$rule} =~ /^\d+$/) &&
- ($env{'form.passwords_'.$rule} ne '0')) {
- $ruleok = 1;
- }
- if ($ruleok) {
- $newvalues{$rule} = $env{'form.passwords_'.$rule};
- if (exists($current{$rule})) {
- if ($newvalues{$rule} ne $current{$rule}) {
- $changes{'rules'} = 1;
- }
- } elsif ($rule eq 'min') {
- if ($staticdefaults{$rule} ne $newvalues{$rule}) {
- $changes{'rules'} = 1;
- }
- } else {
- $changes{'rules'} = 1;
- }
- } elsif (exists($current{$rule})) {
- $changes{'rules'} = 1;
- }
- }
- my @posschars = &Apache::loncommon::get_env_multiple('form.passwords_chars');
- my @chars;
- foreach my $item (sort(@posschars)) {
- if ($item =~ /^(uc|lc|num|spec)$/) {
- push(@chars,$item);
- }
- }
- $newvalues{'chars'} = \@chars;
- unless ($changes{'rules'}) {
- if (ref($current{'chars'}) eq 'ARRAY') {
- my @diffs = &Apache::loncommon::compare_arrays($current{'chars'},\@chars);
- if (@diffs > 0) {
- $changes{'rules'} = 1;
- }
- } else {
- if (@chars > 0) {
- $changes{'rules'} = 1;
- }
- }
- }
+ &password_rule_changes('passwords',\%newvalues,\%current,\%changes);
my %crsownerchg = (
by => [],
for => [],
@@ -18019,6 +18478,76 @@
return $resulttext;
}
+sub password_rule_changes {
+ my ($prefix,$newvalues,$current,$changes) = @_;
+ return unless ((ref($newvalues) eq 'HASH') &&
+ (ref($current) eq 'HASH') &&
+ (ref($changes) eq 'HASH'));
+ my (@rules,%staticdefaults);
+ if ($prefix eq 'passwords') {
+ @rules = ('min','max','expire','numsaved');
+ } elsif ($prefix eq 'secrets') {
+ @rules = ('min','max');
+ }
+ $staticdefaults{'min'} = $Apache::lonnet::passwdmin;
+ foreach my $rule (@rules) {
+ $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;
+ my $ruleok;
+ if ($rule eq 'expire') {
+ if (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+(|\.\d*)$/) &&
+ ($env{'form.'.$prefix.'_'.$rule} ne '0')) {
+ $ruleok = 1;
+ }
+ } elsif ($rule eq 'min') {
+ if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) {
+ if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) {
+ $ruleok = 1;
+ }
+ }
+ } elsif (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) &&
+ ($env{'form.'.$prefix.'_'.$rule} ne '0')) {
+ $ruleok = 1;
+ }
+ if ($ruleok) {
+ $newvalues->{$rule} = $env{'form.'.$prefix.'_'.$rule};
+ if (exists($current->{$rule})) {
+ if ($newvalues->{$rule} ne $current->{$rule}) {
+ $changes->{'rules'} = 1;
+ }
+ } elsif ($rule eq 'min') {
+ if ($staticdefaults{$rule} ne $newvalues->{$rule}) {
+ $changes->{'rules'} = 1;
+ }
+ } else {
+ $changes->{'rules'} = 1;
+ }
+ } elsif (exists($current->{$rule})) {
+ $changes->{'rules'} = 1;
+ }
+ }
+ my @posschars = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_chars');
+ my @chars;
+ foreach my $item (sort(@posschars)) {
+ if ($item =~ /^(uc|lc|num|spec)$/) {
+ push(@chars,$item);
+ }
+ }
+ $newvalues->{'chars'} = \@chars;
+ unless ($changes->{'rules'}) {
+ if (ref($current->{'chars'}) eq 'ARRAY') {
+ my @diffs = &Apache::loncommon::compare_arrays($current->{'chars'},\@chars);
+ if (@diffs > 0) {
+ $changes->{'rules'} = 1;
+ }
+ } else {
+ if (@chars > 0) {
+ $changes->{'rules'} = 1;
+ }
+ }
+ }
+ return;
+}
+
sub modify_usercreation {
my ($dom,%domconfig) = @_;
my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.57 loncom/interface/lonconfigsettings.pm:1.58
--- loncom/interface/lonconfigsettings.pm:1.57 Sun Feb 6 21:36:59 2022
+++ loncom/interface/lonconfigsettings.pm Mon Feb 14 02:48:46 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: lonconfigsettings.pm,v 1.57 2022/02/06 21:36:59 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.58 2022/02/14 02:48:46 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -237,6 +237,11 @@
}
}
}
+ my %servers = &Apache::lonnet::get_servers($dom,'library');
+ foreach my $server (keys(%servers)) {
+ $onload .= "togglePrivKey(document.display,'$server');";
+ }
+ $onload .= "toggleLTIEncKey(document.display);";
}
if (grep(/^ltitools$/, at actions)) {
$onload .= "toggleLTITools(document.display,'passback','add');".
@@ -308,7 +313,7 @@
if ($values->{'linkprotection'}->{$i}->{'usable'}) {
$onload .= "toggleLTI(document.display,'$num','secret');";
}
- }
+ }
if ($ltiauth) {
$onload .= "toggleLTIReqUser(document.display,'requser','optional','1','block','$num');".
"toggleLTIReqUser(document.display,'mapuser','userfield','other','inline-block','$num');";
@@ -523,6 +528,16 @@
$settings = $inststatus;
}
}
+ } elsif ($item eq 'lti') {
+ if (ref($values->{'ltisec'}) eq 'HASH') {
+ if (ref($values->{'lti'}) eq 'HASH') {
+ $settings = {%{$values->{'lti'}},%{$values->{'ltisec'}}};
+ } else {
+ $settings = $values->{'ltisec'};
+ }
+ } elsif (ref($values->{'lti'}) eq 'HASH') {
+ $settings = $values->{'lti'};
+ }
}
($output{$item},$rowtotal{$item}) =
&Apache::domainprefs::print_config_box($r,$dom,$confname,
Index: loncom/Lond.pm
diff -u loncom/Lond.pm:1.18 loncom/Lond.pm:1.19
--- loncom/Lond.pm:1.18 Tue Feb 1 23:13:21 2022
+++ loncom/Lond.pm Mon Feb 14 02:48:49 2022
@@ -1,6 +1,6 @@
# The LearningOnline Network
#
-# $Id: Lond.pm,v 1.18 2022/02/01 23:13:21 raeburn Exp $
+# $Id: Lond.pm,v 1.19 2022/02/14 02:48:49 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1044,6 +1044,56 @@
return $qresult;
}
+sub store_dom {
+ my ($userinput) = @_;
+ my ($cmd,$dom,$namespace,$rid,$what) =split(/:/,$userinput);
+ my $hashref = &tie_domain_hash($dom,$namespace,&GDBM_WRCREAT(),"S","$rid:$what") or
+ return "error: ".($!+0)." tie(GDBM) Failed while attempting $cmd";
+ $hashref->{"version:$rid"}++;
+ my $version=$hashref->{"version:$rid"};
+ my $allkeys='';
+ my @pairs=split(/\&/,$what);
+ foreach my $pair (@pairs) {
+ my ($key,$value)=split(/=/,$pair);
+ $allkeys.=$key.':';
+ $hashref->{"$version:$rid:$key"}=$value;
+ }
+ my $now = time;
+ $hashref->{"$version:$rid:timestamp"}=$now;
+ $allkeys.='timestamp';
+ $hashref->{"$version:keys:$rid"}=$allkeys;
+ &untie_user_hash($hashref) or
+ return "error: ".($!+0)." untie(GDBM) Failed while attempting $cmd";
+ return 'ok';
+}
+
+sub restore_dom {
+ my ($userinput) = @_;
+ my ($cmd,$dom,$namespace,$rid) = split(/:/,$userinput);
+ my $hashref = &tie_domain_hash($dom,$namespace,&GDBM_READER()) or
+ return "error: ".($!+0)." tie(GDBM) Failed while attempting $cmd";
+ my $qresult='';
+ if (ref($hashref)) {
+ chomp($rid);
+ my $version=$hashref->{"version:$rid"};
+ $qresult.="version=$version&";
+ my $scope;
+ for ($scope=1;$scope<=$version;$scope++) {
+ my $vkeys=$hashref->{"$scope:keys:$rid"};
+ my @keys=split(/:/,$vkeys);
+ my $key;
+ $qresult.="$scope:keys=$vkeys&";
+ foreach $key (@keys) {
+ $qresult.="$scope:$key=".$hashref->{"$scope:$rid:$key"}."&";
+ }
+ }
+ $qresult=~s/\&$//;
+ }
+ &untie_user_hash($hashref) or
+ return "error: ".($!+0)." untie(GDBM) Failed while attempting $cmd";
+ return $qresult;
+}
+
sub crslti_itemid {
my ($cdom,$cnum,$url,$method,$params,$loncaparev) = @_;
unless (ref($params) eq 'HASH') {
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1480 loncom/lonnet/perl/lonnet.pm:1.1481
--- loncom/lonnet/perl/lonnet.pm:1.1480 Sun Feb 6 21:37:07 2022
+++ loncom/lonnet/perl/lonnet.pm Mon Feb 14 02:48:53 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1480 2022/02/06 21:37:07 raeburn Exp $
+# $Id: lonnet.pm,v 1.1481 2022/02/14 02:48:53 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -2262,6 +2262,26 @@
}
}
+sub store_dom {
+ my ($storehash,$id,$namespace,$dom,$home) = @_;
+ $$storehash{'ip'}=&get_requestor_ip();
+ $$storehash{'host'}=$perlvar{'lonHostID'};
+ my $namevalue='';
+ foreach my $key (keys(%{$storehash})) {
+ $namevalue.=&escape($key).'='.&freeze_escape($$storehash{$key}).'&';
+ }
+ $namevalue=~s/\&$//;
+ if (grep { $_ eq $home } current_machine_ids()) {
+ return LONCAPA::Lond::store_dom("storedom:$dom:$namespace:$id:$namevalue");
+ } else {
+ if ($namespace eq 'private') {
+ return 'refused';
+ } else {
+ return reply("storedom:$dom:$namespace:$id:$namevalue","$home");
+ }
+ }
+}
+
# ----------------------------------construct domainconfig user for a domain
sub get_domainconfiguser {
my ($udom) = @_;
More information about the LON-CAPA-cvs
mailing list