]> git.mjollnir.org Git - moodle.git/commitdiff
trusttext:
authorskodak <skodak>
Sat, 26 Aug 2006 13:00:07 +0000 (13:00 +0000)
committerskodak <skodak>
Sat, 26 Aug 2006 13:00:07 +0000 (13:00 +0000)
 * proposed by Martin Dougiamas
 * implemented by skodak

Usage:
1/ change enabletrusttext to yes in site settings (it is off by default) or set it in config.php
2/ assign moodle/site:trustcontent capability to users whose text submitted in glossary entries, comments, forum posts etc. should not be cleaned == they can use javascript or any other forbidden tags in glossary and forums...

done:
 * core
 * glossary (without proper upgrade)

to do:
 * data cleaning in upgrades
 * forum, blocks and some other places (MD decides)

12 files changed:
admin/configvars.php
admin/settings/authenticationandsecurity.php
lib/db/access.php
lib/defaults.php
lib/weblib.php
mod/glossary/comment.html
mod/glossary/comment.php
mod/glossary/edit.html
mod/glossary/edit.php
mod/glossary/import.php
mod/glossary/lib.php
version.php

index a1e0b87f7514d6ab68ec3529b0a27a263ad46e70..c3188444cdace843c720b0899be5403f5c286357 100644 (file)
@@ -225,6 +225,9 @@ class configvarrss extends configvar {
     $permissions['allowobjectembed'] = new configvar (get_string('configallowobjectembed', 'admin'),
         choose_from_menu ($noyesoptions, 'allowobjectembed', $config->allowobjectembed, '', '', '', true) );
 
+/// enabletrusttext
+    $permissions['enabletrusttext'] = new configvar (get_string('configenabletrusttext', 'admin'),
+        choose_from_menu ($noyesoptions, 'enabletrusttext', $config->enabletrusttext, '', '', '', true) );
 
     unset($options);
     $options['none'] = 'No courses';
index c500e5cfd4625b16f008664c003ba42cd503e2f6..31c9c9977da0bcdbb17b12039426fb83ae4c4310 100644 (file)
@@ -77,6 +77,7 @@ $temp->add(new admin_setting_configcheckbox('opentogoogle', get_string('opentogo
 $temp->add(new admin_setting_configtext('maxbytes', get_string('maxbytes', 'admin'), get_string('configmaxbytes', 'admin'), PARAM_INT));
 $temp->add(new admin_setting_configcheckbox('messaging', get_string('messaging', 'admin'), get_string('configmessaging','admin')));
 $temp->add(new admin_setting_configcheckbox('allowobjectembed', get_string('allowobjectembed', 'admin'), get_string('configallowobjectembed', 'admin')));
+$temp->add(new admin_setting_configcheckbox('enabletrusttext', get_string('enabletrusttext', 'admin'), get_string('configenabletrusttext', 'admin')));
 $temp->add(new admin_setting_configselect('maxeditingtime', get_string('maxeditingtime','admin'), get_string('configmaxeditingtime','admin'), array(60 => get_string('numminutes', '', 1),
                                                                                                                                                     300 => get_string('numminutes', '', 5),
                                                                                                                                                                                                                                                                                                        900 => get_string('numminutes', '', 15),
index c4d6d40e745d12a9a8f0ff9123c2f7d8b43020a4..a533ec284723c4885ed7146d5fc5f43a0bcbcd09 100644 (file)
@@ -186,6 +186,20 @@ $moodle_capabilities = array(
         )
     ),
     
+    'moodle/site:trustcontent' => array(
+    
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'legacy' => array(
+            'guest' => CAP_PREVENT,
+            'student' => CAP_PREVENT,
+            'teacher' => CAP_PREVENT,
+            'editingteacher' => CAP_ALLOW,
+            'coursecreator' => CAP_ALLOW,
+            'admin' => CAP_ALLOW
+        )
+    ),
+    
     'moodle/user:create' => array(
     
         'captype' => 'write',
index ceeda36d51b6d71513c5defad5bb902592a8bfe9..755ecf982932e33de734633b4c859292fe724dbd 100644 (file)
@@ -34,6 +34,7 @@
        'enablecourserequests'     =>  0,
        'enablerssfeeds'           =>  0,
        'enablestats'              =>  0,
+       'enabletrusttext'          =>  0,
        'enrol'                    => 'internal',
        'extendedusernamechars'    =>  false,
        'editorbackgroundcolor'    => '#ffffff',
index b104948c9f6a926498fcd0325b34c87a9c267e44..8b4e363088771fc9fe029e266e3997f48d263111 100644 (file)
@@ -72,6 +72,11 @@ define('FORMAT_WIKI',     '3');   // Wiki-formatted text
  */
 define('FORMAT_MARKDOWN', '4');   // Markdown-formatted text http://daringfireball.net/projects/markdown/
 
+/**
+ * TRUSTTEXT marker - if present in text, text cleaning should be bypassed
+ */
+define('TRUSTTEXT', '#####TRUSTTEXT#####');
+
 
 /**
  * Allowed tags - string of html tags that can be tested against for safe html tags
@@ -1234,10 +1239,14 @@ function format_text_menu() {
  * @return string
  * @todo Finish documenting this function
  */
-function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) {
+function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) {
 
     global $CFG, $course;
 
+    if (!isset($options->trusttext)) {
+        $options->trusttext = false;
+    }
+
     if (!isset($options->noclean)) {
         $options->noclean=false;
     }
@@ -1262,7 +1271,7 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
 
     if (!empty($CFG->cachetext)) {
         $time = time() - $CFG->cachetext;
-        $md5key = md5($text.'-'.$courseid.$options->noclean.$options->smiley.$options->filter.$options->para.$options->newlines.$format.current_language().$courseid);
+        $md5key = md5($text.'-'.$courseid.$options->noclean.$options->smiley.$options->filter.$options->para.$options->newlines.$format.current_language().$courseid.$options->trusttext);
         if ($oldcacheitem = get_record_sql('SELECT * FROM '.$CFG->prefix.'cache_text WHERE md5key = \''.$md5key.'\'', true)) {
             if ($oldcacheitem->timemodified >= $time) {
                 return $oldcacheitem->formattedtext;
@@ -1270,17 +1279,31 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
         }
     }
 
+    // trusttext overrides the noclean option!
+    if ($options->trusttext) {
+        if (trusttext_present($text)) {
+            $text = trusttext_strip($text);
+            if (!empty($CFG->enabletrusttext)) {
+                $options->noclean = true;
+            } else {
+                $options->noclean = false;
+            }
+        } else {
+            $options->noclean = false;
+        }
+    }
+
     $CFG->currenttextiscacheable = true;   // Default status - can be changed by any filter
 
     switch ($format) {
         case FORMAT_HTML:
-            if (!empty($options->smiley)) {
+            if ($options->smiley) {
                 replace_smilies($text);
             }
-            if (empty($options->noclean)) {
+            if (!$options->noclean) {
                 $text = clean_text($text, $format);
             }
-            if (!empty($options->filter)) {
+            if ($options->filter) {
                 $text = filter_text($text, $courseid);
             }
             break;
@@ -1302,25 +1325,25 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
 
         case FORMAT_MARKDOWN:
             $text = markdown_to_html($text);
-            if (!empty($options->smiley)) {
+            if ($options->smiley) {
                 replace_smilies($text);
             }
-            if (empty($options->noclean)) {
+            if (!$options->noclean) {
                 $text = clean_text($text, $format);
             }
 
-            if (!empty($options->filter)) {
+            if ($options->filter) {
                 $text = filter_text($text, $courseid);
             }
             break;
 
         default:  // FORMAT_MOODLE or anything else
             $text = text_to_html($text, $options->smiley, $options->para, $options->newlines);
-            if (empty($options->noclean)) {
+            if (!$options->noclean) {
                 $text = clean_text($text, $format);
             }
 
-            if (!empty($options->filter)) {
+            if ($options->filter) {
                 $text = filter_text($text, $courseid);
             }
             break;
@@ -1475,7 +1498,6 @@ function format_text_email($text, $format) {
  * @todo Finish documenting this function
  */
 function filter_text($text, $courseid=NULL) {
-
     global $CFG;
 
     require_once($CFG->libdir.'/filterlib.php');
@@ -1499,6 +1521,88 @@ function filter_text($text, $courseid=NULL) {
     return $text;
 }
 
+/**
+ * Is the text marked as trusted?
+ *
+ * @param string $text text to be searched for TRUSTTEXT marker
+ * @return boolean
+ */
+function trusttext_present($text) {
+    if (strpos($text, TRUSTTEXT) !== FALSE) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/**
+ * This funtion MUST be called before the cleaning or any other
+ * function that modifies the data! We do not know the origin of trusttext
+ * in database, if it gets there in tweaked form we must not convert it
+ * to supported form!!!
+ *
+ * Please be carefull not to use stripslashes on data from database
+ * or twice stripslashes when processing data recieved from user.
+ *
+ * @param string $text text that may contain TRUSTTEXT marker 
+ * @return text without any TRUSTTEXT marker
+ */
+function trusttext_strip($text) {
+    global $CFG;
+
+    while (true) { //removing nested TRUSTTEXT
+        $orig = $text; 
+        $text = str_replace(TRUSTTEXT, '', $text);
+        if (strcmp($orig, $text) === 0) {
+            return $text;
+        }
+    }
+}
+
+/**
+ * Mark text as trusted, such text may contain any HTML tags because the
+ * normal text cleaning will be bypassed.
+ * Please make sure that the text comes from trusted user before storing
+ * it into database!
+ */
+function trusttext_mark($text) {
+    global $CFG;
+    if (!empty($CFG->enabletrusttext) and (strpos($text, TRUSTTEXT) === FALSE)) {
+        return TRUSTTEXT.$text;
+    } else {
+        return $text;
+    }
+}
+function trusttext_after_edit(&$text, $context) {
+    if (has_capability('moodle/site:trustcontent', $context)) {
+        $text = trusttext_mark($text);
+    } else {
+        $text = trusttext_strip($text);
+    }
+}
+
+function trusttext_prepare_edit(&$text, &$format, $usehtmleditor, $context) {
+    global $CFG;
+
+    $options = new object();
+    $options->smiley = false;
+    $options->filter = false;
+    if (!empty($CFG->enabletrusttext)
+         and has_capability('moodle/site:trustcontent', $context)
+         and trusttext_present($text)) {
+        $options->noclean = true;
+    } else {
+        $options->noclean = false;
+    }
+    $text = trusttext_strip($text);
+    if ($usehtmleditor) {
+        $text = format_text($text, $format, $options);
+        $format = FORMAT_HTML;
+    } else if (!$options->noclean){
+        $text = clean_text($text, $format);
+    }
+}
+
 /**
  * Given raw text (eg typed in by a user), this function cleans it up
  * and removes any nasty tags that could mess up Moodle pages.
index fa2117140f2454942c317a81d180c9eb6a3e1108..7d749ed4007e888a40efb774a10405e5e08f5726 100644 (file)
@@ -2,13 +2,9 @@
     if (!isset($form->format)) {
         $form->format = $defaultformat;
     }
-    if ($usehtmleditor) { //clean and convert before editing
-        $options = new object();
-        $options->smiley = false;
-        $options->filter = false;
-        $form->text = format_text($form->text, $form->format, $options);
-        $form->format = FORMAT_HTML;
-    }
+
+    trusttext_prepare_edit($form->text, $form->format, $usehtmleditor, $context)
+
 ?>
 <form name="form" method="post" action="comment.php">
 <table  class="generalbox">
index bc9f098318df95d9c7d3ab162b63d16941a120e0..879eaad3961e121bfd33e907117bbe05e434ec31 100644 (file)
         }
 
         if ( $confirm and $form = data_submitted() ) {
-            //$form->text = clean_text($form->text, $form->format);
+            trusttext_after_edit($form->text, $context);
 
             $newentry->entryid = $entry->id;
             $newentry->comment = $form->text;
index c1e2896d4826dc6fb04d93a1e6f2f52b23c29108..455ed276f9634ae03fb0f51e2463902d95bac78e 100644 (file)
@@ -2,13 +2,9 @@
     if (!isset($newentry->format)) {
         $newentry->format = $defaultformat;
     }
-    if ($usehtmleditor) { //clean and convert before editing
-        $options = new object();
-        $options->smiley = false;
-        $options->filter = false;
-        $newentry->definition = format_text($newentry->definition, $newentry->format, $options);
-        $newentry->format = FORMAT_HTML;
-    }
+
+    trusttext_prepare_edit($newentry->definition, $newentry->format, $usehtmleditor, $context)
+
 ?>
 <form name="form" method="post" action="edit.php" enctype="multipart/form-data">
 <table border="0" cellpadding="5">
index 69a82219df1046f97fc2e2c8d9626436c0cc25c1..accc444489aaca1d471d23a309c8d7b1029ed95f 100644 (file)
@@ -43,6 +43,8 @@ if (!$glossary->studentcanpost && !has_capability('mod/glossary:manageentries',
 }
 if ( $confirm ) {
     $form = data_submitted();
+    trusttext_after_edit($form->text, $context);
+
     if ( !isset($form->usedynalink) ) {
         $form->usedynalink = 0;
     }
@@ -245,6 +247,7 @@ if ( $confirm ) {
         $newentry->userid = $form->userid;
         $newentry->timecreated = $form->timecreated;
 
+
         if ( $aliases = get_records("glossary_alias","entryid",$e) ) {
             foreach ($aliases as $alias) {
                 $newentry->aliases .= $alias->alias . "\n";
@@ -332,7 +335,7 @@ $tab = GLOSSARY_ADDENTRY_VIEW;
 include("tabs.html");
 
 if (!$e) {
-    require_capability('glossary_write', $context);  
+    require_capability('mod/glossary:write', $context);  
 }
 
 include("edit.html");
index 9ce562356e50c1576e664521343758235ae6a29a..f91bd6d846db4680608ac9655b1c67f8c8870fb6 100644 (file)
             $xmlentry = $xmlentries[$i];
             unset($newentry);
             $newentry->concept = trim(addslashes($xmlentry['#']['CONCEPT'][0]['#']));
-            $newentry->definition = addslashes($xmlentry['#']['DEFINITION'][0]['#']);
+            $newentry->definition = trusttext_strip(addslashes($xmlentry['#']['DEFINITION'][0]['#']));
             if ( isset($xmlentry['#']['CASESENSITIVE'][0]['#']) ) {
                 $newentry->casesensitive    = addslashes($xmlentry['#']['CASESENSITIVE'][0]['#']);
             } else {
index a70c91de9122e509076bafcd75cb2407227cbd29..b987daea921c16965c4c8403e48767a1bee39197 100644 (file)
@@ -588,13 +588,36 @@ function glossary_print_entry($course, $cm, $glossary, $entry, $mode='',$hook=''
  //Default (old) print format used if custom function doesn't exist in format
 function glossary_print_entry_default ($entry) {
     echo '<b>'. strip_tags($entry->concept) . ': </b>';
+
+    $definition = $entry->definition;
+
+    // always detect and strip TRUSTTEXT marker before processing and add+strip it afterwards!
+    if (trusttext_present($definition)) {
+        $ttpresent = true;
+        $definition = trusttext_strip($definition);
+    } else {
+        $ttpresent = false;
+    }
+
+    $definition = '<span class="nolink">' . strip_tags($definition) . '</span>';
+
+    // reconstruct the TRUSTTEXT properly after processing
+    if ($ttpresent) {
+        $definition = trusttext_mark($definition);
+    } else {
+        $definition = trusttext_strip($definition); //make 100% sure TRUSTTEXT marker was not created
+    }
+
+    $options = new object();
     $options->para = false;
-    $definition = format_text('<span class="nolink">' . strip_tags($entry->definition) . '</span>', $entry->format,$options);
+    $options->trusttext = true;
+    $definition = format_text($definition, $entry->format, $options);
     echo ($definition);
     echo '<br /><br />';
 }
 
 function  glossary_print_entry_concept($entry) {
+    $options = new object();
     $options->para = false;
     $text = format_text('<span class="nolink">' . $entry->concept . '</span>', FORMAT_MOODLE, $options);
     if (!empty($entry->highlight)) {
@@ -607,6 +630,14 @@ function glossary_print_entry_definition($entry) {
 
     $definition = $entry->definition;
 
+    // always detect and strip TRUSTTEXT marker before processing and add+strip it afterwards!
+    if (trusttext_present($definition)) {
+        $ttpresent = true;
+        $definition = trusttext_strip($definition);
+    } else {
+        $ttpresent = false;
+    }
+
     $links = array();
     $tags = array();
     $urls = array();
@@ -702,9 +733,18 @@ function glossary_print_entry_definition($entry) {
         $definition = str_replace(array_keys($links),$links,$definition);
     }
 
+    $options = new object();
     $options->para = false;
+    $options->trusttext = true;
+
+    // reconstruct the TRUSTTEXT properly after processing
+    if ($ttpresent) {
+        $definition = trusttext_mark($definition);
+    } else {
+        $definition = trusttext_strip($definition); //make 100% sure TRUSTTEXT marker was not created
+    }
 
-    $text = format_text($definition, $entry->format,$options);
+    $text = format_text($definition, $entry->format, $options);
     if (!empty($entry->highlight)) {
         $text = highlight($entry->highlight, $text);
     }
@@ -1537,7 +1577,9 @@ function glossary_print_comment($course, $cm, $glossary, $entry, $comment) {
     echo '&nbsp;';
     echo '</td><td class="entry">';
 
-    echo format_text($comment->comment, $comment->format);
+    $options = new object();
+    $options->trusttext = true;
+    echo format_text($comment->comment, $comment->format, $options);
 
     echo '<div class="icons commands">';
 
@@ -1692,7 +1734,7 @@ function glossary_generate_export_file($glossary, $hook = "", $hook = 0) {
                 if ( $entry->approved and $permissiongranted ) {
                     $co .= glossary_start_tag("ENTRY",3,true);
                     $co .= glossary_full_tag("CONCEPT",4,false,trim($entry->concept));
-                    $co .= glossary_full_tag("DEFINITION",4,false,$entry->definition);
+                    $co .= glossary_full_tag("DEFINITION",4,false,trusttext_strip($entry->definition));
                     $co .= glossary_full_tag("FORMAT",4,false,$entry->format);
                     $co .= glossary_full_tag("USEDYNALINK",4,false,$entry->usedynalink);
                     $co .= glossary_full_tag("CASESENSITIVE",4,false,$entry->casesensitive);
index cbd51bd4d39c3557b7de60e8b20e3e27ac53677a..7a6f70b5eb6b599b68272a1c75c428fdd5df78ad 100644 (file)
@@ -6,7 +6,7 @@
 // This is compared against the values stored in the database to determine
 // whether upgrades should be performed (see lib/db/*.php)
 
-   $version = 2006082300;  // YYYYMMDD = date
+   $version = 2006082600;  // YYYYMMDD = date
                            //       XY = increments within a single day
 
    $release = '1.7 dev';    // Human-friendly version name