/** preview a page that is maybe still under embargo/already expired
  *
  * if the user has permissions to preview the specified page, she is
  * redirected to the regular site with a special one-time permission to view
  * a page, even if that page is under embargo or already expired (which
  * normally would prevent any user from viewing that page).
  *
  * There are several ways to implement such a one-off permit, e.g.
  * by setting a quasi-random string in the session and specifying that
  * string as a parameter to index.php. If (in index.php) the string provided matches
  * ths string in the session, the user is granted access. However, this
  * leaves room for the user to manually change the node id to _any_
  * number, even a node that that user is not supposed to see.
  *
  * Another solution might have been to simply include index.php.
  * I decided against that; I don't want to have to deal with a mix
  * of admin.php and index.php-code in the same run.
  *
  * I took a slightly different approach, as follows.
  * First I generate a quasi-random string of N (N=32) characters.
  * (The lenght of 32 is an arbitrary choice.)
  * This string is stored in the session variable.
  * Then I store the requested node in the session variable, too.
  * After that I calculate the md5sum of the combination of the
  * random string and the node id. This yields a hash.
  * This hash is passed on to index.php as the sole parameter.
  *
  * Note that the quasi-random key never leaves the server: it is
  * only stored in the session variables. Also, the node id is not
  * one of the parameters of index.php, this too is only stored in
  * the session variables.
  *
  * Once index.php is processed, the specified md5sum is retrieved
  * and a check is performed on the node id and the quasi-random string
  * in the session variables in order to see if the hashes match. If
  * this is the case, index.php can proceed to show the page preview.
  * Note that there is no way for the user to manipulate the node id,
  * because that number never travels to the user's browser in plain
  * text.
  *
  * Making a bookmark for the preview will use the hash, but the hash
  * depends on a quasi-random string stored in the session. It means
  * that when the session is terminated, the bookmarked page will no
  * longer be visible, which is good. Also, whenever another page
  * preview is requested, a new quasi-random string is generated,
  * which also invalidates the bookmarked page.
  *
  * The only thing that CAN happen is that the user saves the preview in
  * a place where it can be seen by others. Also, the page will probably
  * be cached in the user's browser.
  *
  * With respect to permissions: I consider the preview privilege equivalent
  * with edit permission: if the user is able to edit the node she can see
  * the content of the node anyway. However, maybe we should look at different
  * permissions. Put it on the todo-list.
  *
  * @return void results are returned as output in $this->output
  * @uses $CFG
  * @todo the check on permissions can be improved (is PERMISSION_XXXX_EDIT_NODE enough?)
  * @todo there is an issue with redirecting to another site:
  *       officially the url should be fully qualified (ie. $CFG->www).
  *       I use the shorthand, possibly without scheme and hostname
  *       ($CFG->www_short). This might pose a problem with picky browsers.
  *       See {@link calculate_uri_shortcuts} for more information.
  */
 function task_page_preview()
 {
     global $CFG;
     // 1A -- do we have a sane value for node_id?
     $node_id = get_parameter_int('node', 0);
     $anode = array('{NODE}' => strval($node_id));
     if ($node_id == 0 || !isset($this->tree[$node_id])) {
         // are they trying to trick us, specifying a node from another area?
         logger(__FUNCTION__ . "(): weird: user previews node '{$node_id}' working in area '{$this->area_id}'?");
         $this->output->add_message(t('invalid_node', 'admin', $anode));
         $this->task_treeview();
         return;
     }
     // 1B -- is it a page?
     if (!$this->tree[$node_id]['is_page']) {
         logger(__CLASS__ . ": weird: cannot preview content of a section (section '{$node_id}')");
         $this->task_treeview();
         return;
     }
     // 2 -- does the user have permission to edit and thus view this page at all?
     $user_has_permission = $this->permission_edit_node_content($node_id) || $this->permission_edit_node($node_id, $this->tree[$node_id]['is_page']);
     if ($user_has_permission) {
         $random_string = quasi_random_string(32);
         $_SESSION['preview_salt'] = $random_string;
         $_SESSION['preview_node'] = $node_id;
         $_SESSION['preview_area'] = $this->area_id;
         $hash = md5($_SESSION['preview_salt'] . $_SESSION['preview_node']);
         session_write_close();
         redirect_and_exit($CFG->www_short . '/index.php?preview=' . $hash);
         // we never reach this point
     } else {
         $msg = t('access_denied', 'admin');
         $this->output->add_message($msg);
         $this->output->add_popup_bottom($msg);
         $this->output->add_content('<h2>' . $msg . '</h2>');
         $this->output->add_content(t('access_denied_preview', 'admin'));
     }
 }
Ejemplo n.º 2
0
/** generate a quasi random string to salt the password hash
 *
 * this generates a quasi-randomg string of digits and letters
 * to be used as a salt when calculating a password hash.
 *
 * @param int $length the number of characters in the generated string
 * @return string quasi-random string
 */
function password_salt($length = 12)
{
    return quasi_random_string($length, QUASI_RANDOM_DIGITS_UPPER_LOWER);
}