diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index bae5031a3..1282037ac 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -5,6 +5,13 @@ - fix: Closed Posts Displaying in CS - RFE: testEnvironment improvement - fix: Cannot add new page to the Wiki + - fix: Wiki does not have content type restrictions and can not use + the content filtering system + - fix: GetSyndicatedContent Workflow Activity not trapping errors. + - fix: GetSyndicatedContent Workflow Activity not checking for timeout. + - fix: Wiki displays 'Add a new page" link to users who are not allowed to + add pages. + - fix: XSS vulnerability in Wiki Page titles. - Removed the requirement for DBIx::FullTextSearch from testEnvironment.pl since it hasn't been needed since 6.5. It was just never removed. diff --git a/docs/upgrades/templates-7.3.4/wiki_search.tmpl b/docs/upgrades/templates-7.3.4/wiki_search.tmpl new file mode 100644 index 000000000..dfddd6348 --- /dev/null +++ b/docs/upgrades/templates-7.3.4/wiki_search.tmpl @@ -0,0 +1,26 @@ +#WikiSearchTmpl00000001 + +

+ + + + +

+ +
+ + + +

+

+ +

+

+
+
+
| |
+~~~ + + diff --git a/docs/upgrades/upgrade_7.3.3-7.3.4.pl b/docs/upgrades/upgrade_7.3.3-7.3.4.pl index 518f704f1..bbd6a679a 100644 --- a/docs/upgrades/upgrade_7.3.3-7.3.4.pl +++ b/docs/upgrades/upgrade_7.3.3-7.3.4.pl @@ -20,17 +20,19 @@ my $quiet; # this line required my $session = start(); # this line required -# upgrade functions go here +fixWiki($session); finish($session); # this line required ##------------------------------------------------- -#sub exampleFunction { -# my $session = shift; -# print "\tWe're doing some stuff here that you should know about.\n" unless ($quiet); -# # and here's our code -#} +sub fixWiki { + my $session = shift; + print "\tImplementing replacements and content filtering for the Wiki Wobject.\n" unless ($quiet); + + $session->db->write("alter table WikiMaster add column useContentFilter int(11) default 0"); + $session->db->write("alter table WikiMaster add column filterCode varchar(30) default 'javascript'"); +} diff --git a/lib/WebGUI/Asset/WikiPage.pm b/lib/WebGUI/Asset/WikiPage.pm index 1febbce8b..c50477003 100644 --- a/lib/WebGUI/Asset/WikiPage.pm +++ b/lib/WebGUI/Asset/WikiPage.pm @@ -233,17 +233,23 @@ sub processPropertiesFromFormPost { my $self = shift; $self->SUPER::processPropertiesFromFormPost(@_); my $actionTaken = ($self->session->form->process("assetId") eq "new") ? "Created" : "Edited"; + $self->update({ groupIdView => $self->getWiki->get('groupIdView'), groupIdEdit => $self->getWiki->get('groupToAdminister'), isHidden => 1, actionTakenBy => $self->session->user->userId, - actionTaken => $actionTaken}); + actionTaken => $actionTaken, + title => WebGUI::HTML::filter($self->get("title"), "all"), + }); + if ($self->getWiki->canAdminister) { $self->update({isProtected => $self->session->form("isProtected")}); } + delete $self->{_storageLocation}; my $size = 0; my $storage = $self->getStorageLocation; + foreach my $file (@{$storage->getFiles}) { if ($storage->isImage($file)) { ##Use generateThumbnail to shrink size to site's max image size @@ -255,9 +261,35 @@ sub processPropertiesFromFormPost { } $size += $storage->getFileSize($file); } + $self->setSize($size); } +#------------------------------------------------------------------- + +=head2 scrubContent ( [ content ] ) + +Uses WikiMaster settings to remove unwanted markup and apply site wide replacements. + +=head3 content + +Optionally pass the ontent that we want to run the filters on. Otherwise we get it from self. + +=cut + +sub scrubContent { + my $self = shift; + my $content = shift || $self->get("content"); + + my $scrubbedContent = WebGUI::HTML::filter($content, $self->getWiki->get("filterCode")); + + if ($self->getWiki->get("useContentFilter")) { + $scrubbedContent = WebGUI::HTML::processReplacements($self->session, $scrubbedContent); + } + + return $scrubbedContent; +} + #------------------------------------------------------------------- sub view { my $self = shift; @@ -276,7 +308,7 @@ sub view { wikiHomeUrl=>$self->getParent->getUrl, historyUrl=>$self->getUrl("func=getHistory"), editContent=>$self->getEditForm, - content => $self->getWiki->autolinkHtml($self->get('content')), + content => $self->getWiki->autolinkHtml($self->scrubContent), }; return $self->processTemplate($var, $self->getWiki->get("pageTemplateId")); } diff --git a/lib/WebGUI/Asset/Wobject/WikiMaster.pm b/lib/WebGUI/Asset/Wobject/WikiMaster.pm index 17b72dadc..f1368bcf1 100644 --- a/lib/WebGUI/Asset/Wobject/WikiMaster.pm +++ b/lib/WebGUI/Asset/Wobject/WikiMaster.pm @@ -67,6 +67,7 @@ sub appendSearchBoxVars { $var->{'searchQuery'} = WebGUI::Form::text($self->session, { name => 'query', value => $queryText }); $var->{'searchSubmit'} = WebGUI::Form::submit($self->session, { value => $submitText }); $var->{'searchFormFooter'} = WebGUI::Form::formFooter($self->session); + $var->{'canAddPages'} = $self->canEditPages(); return $self; } @@ -274,6 +275,20 @@ sub definition { label => $i18n->get("max image size"), hoverHelp => $i18n->get("max image size help") }, + useContentFilter =>{ + fieldType=>"yesNo", + defaultValue=>1, + tab=>'display', + label=>$i18n->get('content filter'), + hoverHelp=>$i18n->get('content filter description'), + }, + filterCode =>{ + fieldType=>"filterContent", + defaultValue=>'javascript', + tab=>'security', + label=>$i18n->get('filter code'), + hoverHelp=>$i18n->get('filter code description'), + }, ); push @$definition, diff --git a/lib/WebGUI/Help/Asset_WikiMaster.pm b/lib/WebGUI/Help/Asset_WikiMaster.pm index e6ac8b20a..87fe2efb5 100644 --- a/lib/WebGUI/Help/Asset_WikiMaster.pm +++ b/lib/WebGUI/Help/Asset_WikiMaster.pm @@ -452,6 +452,10 @@ our $HELP = { { 'name' => 'performSearch', }, + { + 'name' => 'canAddPages', + 'description' => 'canAddPages variable', + }, { 'name' => 'searchResults', variables => [ diff --git a/lib/WebGUI/Workflow/Activity/GetSyndicatedContent.pm b/lib/WebGUI/Workflow/Activity/GetSyndicatedContent.pm index dbfc72c7a..ef7ab4efc 100644 --- a/lib/WebGUI/Workflow/Activity/GetSyndicatedContent.pm +++ b/lib/WebGUI/Workflow/Activity/GetSyndicatedContent.pm @@ -18,6 +18,7 @@ package WebGUI::Workflow::Activity::GetSyndicatedContent; use strict; use base 'WebGUI::Workflow::Activity'; use WebGUI::Asset::Wobject::SyndicatedContent; +use JSON; =head1 NAME @@ -69,20 +70,81 @@ See WebGUI::Workflow::Activity::execute() for details. sub execute { my $self = shift; - #In the new Wobject, "rssURL" actually can refer to more than one URL. - my @syndicatedWobjectURLs = $self->session->db->buildArray("select distinct SyndicatedContent.rssUrl from SyndicatedContent left join asset on SyndicatedContent.assetId=asset.assetId where asset.state='published'"); - foreach my $url(@syndicatedWobjectURLs) { + my $object = shift; + my $instance = shift; + unless (defined $instance) { + $self->session->errorHandler->error("Could not instanciate Workflow Instance in GetSyndicatedContent Activity"); + return $self->ERROR; + } + + my @syndicatedUrls = @{$self->getSyndicatedUrls($instance)}; + my @arrayCopy = @syndicatedUrls; # copy we can delete elements from inside the foreach loop + my $time = time(); + + foreach my $urls (@syndicatedUrls) { #Loop through the SyndicatedWobjects and split all the URLs they are syndicating off into #a separate array. - my @urlsToSyndicate = split(/\s+/,$url); - foreach ((@urlsToSyndicate)) { - WebGUI::Asset::Wobject::SyndicatedContent::_get_rss_data($self->session,$_); + my @urlsToSyndicate = split(/\s+/,$urls); + + foreach my $url (@urlsToSyndicate) { + # We could timeout in here but I don't see a good way to handle that right now + # May need to fix this in the future. + my $returnValue = WebGUI::Asset::Wobject::SyndicatedContent::_get_rss_data($self->session, $url); + unless (defined $returnValue) { + $self->session->errorHandler->error("GetSyndicatedContent Workflow Activity: _get_rss_data returned undef while trying to process syndicated content url $url"); + return $self->ERROR; + } } + + # Delete this element from the array + splice(@arrayCopy,0,1); + + # Check for timeout + last unless (time() - $time <= 60); } + + # See if we're done + if (scalar(@arrayCopy) > 0) { + $instance->setScratch("syndicatedUrls", objToJson(@arrayCopy)); + return $self->WAITING; + } + + $instance->deleteScratch("syndicatedUrls"); return $self->COMPLETE; } +#--------------------------------------------------------------------- +=head2 getWobjectUrls ( ) + +Returns URLs from all of the Syndicated Content Wobjects from scratch or fetches them from the db if needed + +=head3 session + +A reference to the current webgui session + +=cut + +sub getSyndicatedUrls { + my $self = shift; + my $instance = shift; + my $syndicatedUrls = $instance->getScratch("syndicatedUrls"); + + unless ($syndicatedUrls) { + my $urls = $self->session->db->buildArrayRef("select + distinct SyndicatedContent.rssUrl from SyndicatedContent + left join + asset on SyndicatedContent.assetId=asset.assetId + where + asset.state='published'" + ); + + $instance->setScratch("syndicatedUrls", objToJson($urls)); + return $urls; + } + + return jsonToObj($syndicatedUrls); +} 1; diff --git a/lib/WebGUI/i18n/English/Asset_WikiMaster.pm b/lib/WebGUI/i18n/English/Asset_WikiMaster.pm index 9647362f8..6ff85530e 100644 --- a/lib/WebGUI/i18n/English/Asset_WikiMaster.pm +++ b/lib/WebGUI/i18n/English/Asset_WikiMaster.pm @@ -13,6 +13,30 @@ our $I18N = { addPageLabel=>{message=>q|Add a new page.|, lastUpdated=>0}, wikiHomeLabel=>{message=>q|Wiki Home|, lastUpdated=>0}, + 'filter code' => { + message => q|Filter Code|, + lastUpdated => 0, + context => q|Label for edit wobject screen|, + }, + + 'filter code description' => { + message => q|Sets the level of HTML Filtering done on each Wiki entry|, + lastUpdated => 0, + context => q|Hover help for edit wobject screen|, + }, + + 'content filter' => { + message => q|Use Content Filter?|, + lastUpdated => 0, + context => q|Label for edit wobject screen|, + }, + + 'content filter description' => { + message => q|Process the content of Wiki pages through the WebGUI Content Filtering system. This can also be used to create custom markup symbols for inserting reusable content styling.|, + lastUpdated => 0, + context => q|Hover help for edit wobject screen|, + }, + 'wikiHomeLabel variable' => { message=>q|An internationalized label to go with wikiHomeUrl.|, lastUpdated=>1165816161, @@ -444,6 +468,16 @@ our $I18N = { lastUpdated => 1165946014, }, + 'canAddPages' => { + message => q|canAddPages Variable|, + lastUpdated=>0, + }, + + 'canAddPages variable' => { + message => q|Boolean value that is true when the user is allowed to add and edit pages in the Wiki.|, + lastUpdated=> 0, + }, + }; 1;