diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index fcd706631..4d9937f3f 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,4 +1,5 @@ 7.5.19 + - fixed: user profile defaults can contain arbitrary perl code - fixed: Syndicated Content UTF-8 check for decoded content - fixed: unable to purge trash - fixed: EMS not displaying all users with a badge diff --git a/lib/WebGUI/User.pm b/lib/WebGUI/User.pm index 16baacf11..a2df86745 100644 --- a/lib/WebGUI/User.pm +++ b/lib/WebGUI/User.pm @@ -19,6 +19,7 @@ use WebGUI::Cache; use WebGUI::Group; use WebGUI::DatabaseLink; use WebGUI::Utility; +use WebGUI::Operation::Shared; =head1 NAME @@ -156,6 +157,25 @@ sub authMethod { #------------------------------------------------------------------- +=head2 cache ( ) + +Saves the user object into the cache. + +=cut + +sub cache { + my $self = shift; + my $cache = WebGUI::Cache->new($self->session,["user",$self->userId]); + # copy user object + my %userData; + for my $k (qw(_userId _user _profile)) { + $userData{$k} = $self->{$k}; + } + $cache->set(%userData, 60*60*24); +} + +#------------------------------------------------------------------- + =head2 canUseAdminMode ( ) Returns a boolean indicating whether the user has the basic privileges needed to turn on admin mode and use basic admin functions. Note this isn't checking for any special privileges like whether the user can create new users, etc. @@ -534,8 +554,10 @@ sub new { my $overrideId = shift; $userId = _create($session, $overrideId) if ($userId eq "new"); my $cache = WebGUI::Cache->new($session,["user",$userId]); - my $userData = $cache->get; - unless ($userData->{_userId} && $userData->{_user}{username}) { + my $self = $cache->get || {}; + bless $self, $class; + $self->{_session} = $session; + unless ($self->{_userId} && $self->{_user}{username}) { my %user; tie %user, 'Tie::CPHash'; %user = $session->db->quickHash("select * from users where userId=?",[$userId]); @@ -546,30 +568,23 @@ sub new { ); delete $profile{userId}; - my %default = $session->db->buildHash("select fieldName, dataDefault from userProfileField"); - foreach my $key (keys %default) { - my $value; - if ($profile{$key} eq "" && $default{$key}) { - $value = eval($default{$key}); - if (ref $value eq "ARRAY") { - $profile{$key} = $value->[0]; - } else { - $profile{$key} = $value; - } + # remove undefined fields so they will fall back on defaults when requested + for my $key (keys %profile) { + if (!defined $profile{$key} || $profile{$key} eq '') { + delete $profile{$key}; } } + $profile{alias} = $user{username} if ($profile{alias} =~ /^\W+$/ || $profile{alias} eq ""); - $userData = { - _userId => $userId, - _user => \%user, - _profile => \%profile - }; - $cache->set($userData, 60*60*24); + $self->{_userId} = $userId; + $self->{_user} = \%user, + $self->{_profile} = \%profile, + $self->cache; } - $userData->{_session} = $session; - bless $userData, $class; + return $self; } + #------------------------------------------------------------------- =head2 newByEmail ( session, email ) @@ -649,7 +664,7 @@ sub profileField { my $fieldName = shift; my $value = shift; my $db = $self->session->db; - if (!exists $self->{_profile}{$fieldName} && !$self->session->db->quickScalar("SELECT COUNT(*) FROM userProfileField WHERE fieldName = ?", [$fieldName]) ) { + if (!$self->session->db->quickScalar("SELECT COUNT(*) FROM userProfileField WHERE fieldName = ?", [$fieldName])) { $self->session->errorHandler->warn("No such profile field: $fieldName"); return undef; } @@ -663,7 +678,12 @@ sub profileField { my $time = $self->session->datetime->time; $self->{_user}{"lastUpdated"} = $time; $self->session->db->write("update users set lastUpdated=? where userId=?", [$time, $self->{_userId}]); - } + } + elsif (!exists $self->{_profile}{$fieldName}) { + my $default = $self->session->db->quickScalar("SELECT dataDefault FROM userProfileField WHERE fieldName=?", [$fieldName]); + $self->{_profile}{$fieldName} = WebGUI::Operation::Shared::secureEval($self->session, $default); + $self->cache; + } return $self->{_profile}{$fieldName}; } @@ -752,7 +772,7 @@ Deletes this user object out of the cache. sub uncache { my $self = shift; my $cache = WebGUI::Cache->new($self->session,["user",$self->userId]); - $cache->delete; + $cache->delete; } #------------------------------------------------------------------- diff --git a/t/User.t b/t/User.t index feed6770b..709c5670e 100644 --- a/t/User.t +++ b/t/User.t @@ -430,6 +430,21 @@ $buster->uncache; $buster3 = WebGUI::User->new($session, $buster->userId); is($buster3->profileField('listProfile'), 'alpha', 'profile field with default data value that is a list gives the user the first value'); +################################################################ +# +# Attempt to eval userProfileData +# +################################################################ + +my %evalProfile = %copiedAliasProfile; +$evalProfile{'fieldName'} = 'evalProfile'; +$evalProfile{'dataDefault'} = q!$session->scratch->set('hack','true'); 1;!; +my $evalProfileField = WebGUI::ProfileField->create($session, 'evalProfile', \%evalProfile); + +$buster->uncache; +my $buster4 = WebGUI::User->new($session, $buster->userId); +is($session->scratch->get('hack'), undef, 'userProfile dataDefault is not executed when creating users'); + ################################################################ # # getGroups @@ -608,6 +623,7 @@ END { $profileField->set(\%originalFieldData); $aliasProfile->set(\%originalAliasProfile); $listProfileField->delete; + $evalProfileField->delete; $visitor->profileField('email', $originalVisitorEmail); $newProfileField->delete();