From 475e6c33db88e87dabf6177578d3254cfc6b1ebf Mon Sep 17 00:00:00 2001 From: Matthieu Marcillaud <marcimat@rezo.net> Date: Mon, 10 Jul 2017 21:59:55 +0000 Subject: [PATCH] =?UTF-8?q?Changement=20dans=20le=20changement=20du=20toke?= =?UTF-8?q?n=20de=20pr=C3=A9visualisation=20par=20r23636=20(toujours=20act?= =?UTF-8?q?ivable=20par=20define).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le token n’est plus calculé avec le type/id de l’objet mais à partir de l’URL. Corrolaire 1 : si l’URL de l’objet change (parce qu’on a changé son titre), le token ne sera plus valable. Corrolaire 2 : on peut demander un token pour n’importe quelle URL (Bonux va l’utiliser pour son bouton de relecture) De plus, on ne permet d’accéder aux redirections que si l’objet de destination est publié ou qu’on est en mode preview et qu’on a l’autorisation de voir. On retourne sur une page 404 sinon. --- ecrire/action/redirect.php | 100 +++++++++++++++++++++++--------- ecrire/inc/securiser_action.php | 31 ++++------ ecrire/inc/utils.php | 13 ++++- 3 files changed, 91 insertions(+), 53 deletions(-) diff --git a/ecrire/action/redirect.php b/ecrire/action/redirect.php index 5b908fb7a9..371f3b0c76 100644 --- a/ecrire/action/redirect.php +++ b/ecrire/action/redirect.php @@ -38,50 +38,92 @@ if (!defined('_ECRIRE_INC_VERSION')) { function action_redirect_dist() { $type = _request('type'); $id = intval(_request('id')); + $page = false; - if ($m = _request('var_mode')) { + // verifier le type ou page transmis + if (!preg_match('/^\w+$/', $type)) { + $page = _request('page'); + if (!preg_match('/^\w+$/', $page)) { + return; + } + } + + if ($var_mode = _request('var_mode')) { // forcer la mise a jour de l'url de cet objet ! if (!defined('_VAR_URLS')) { define('_VAR_URLS', true); } } - if (preg_match('/^\w+$/', $type)) { - $h = generer_url_entite_absolue($id, $type, '', '', true); + if ($page) { + $url = generer_url_public($page, '', true); } else { - if ($page = _request('page') - and preg_match('/^\w+$/', $page) + $url = calculer_url_redirect_entite($type, $id, $var_mode); + } + + $status = '302'; + if ($url) { + if ($var_mode) { + $url = parametre_url($url, 'var_mode', $var_mode); + } + + if ($var_mode == 'preview' + and defined('_PREVIEW_TOKEN') + and _PREVIEW_TOKEN + and autoriser('previsualiser') ) { - $h = generer_url_public($page, '', true); - } else { - return; + include_spip('inc/securiser_action'); + $token = calculer_token_previsu($url); + $url = parametre_url($url, 'var_previewtoken', $token); } - } - if ($m > '') { - $h = parametre_url($h, 'var_mode', $m); + if (_request('status') and _request('status') == '301') { + $status = '301'; + } + } else { + $url = generer_url_public('404', '', true); } - if ($m == 'preview' - and defined('_PREVIEW_TOKEN') - and _PREVIEW_TOKEN - and $type - and $id - and autoriser('previsualiser') - ) { - include_spip('inc/securiser_action'); - $token = calculer_token_previsu($type, $id); - $h = parametre_url($h, 'var_previewtoken', $token); + redirige_par_entete(str_replace('&', '&', $url), '', $status); +} + +/** + * Retourne l’URL de l’objet sur lequel on doit rediriger + * + * On met en cache les calculs (si memoization), + * et on ne donne pas l’URL si la personne n’y a pas accès + * + * @param string $type + * @param int $id + * @param string $var_mode + */ +function calculer_url_redirect_entite($type, $id, $var_mode) { + // invalider le cache à chaque modif en bdd + $date = 0; + if (isset($GLOBALS['meta']['derniere_modif'])) { + $date = $GLOBALS['meta']['derniere_modif']; } + $key = "url-$date-$type-$id"; - $status = '302'; - if (_request('status') and _request('status') == '301') { - $status = '301'; + // Obtenir l’url et si elle est publié du cache memoization + if (function_exists('cache_get') and $desc = cache_get($key)) { + list($url, $publie) = $desc; + } + // Si on ne l’a pas trouvé, ou si var mode, on calcule l’url et son état publie + if (!$desc or $var_mode) { + $publie = objet_test_si_publie($type, $id); + $url = generer_url_entite_absolue($id, $type, '', '', true); + if (function_exists('cache_set')) { + cache_set($key, array($url, $publie), 3600); + } } - if ($h) { - redirige_par_entete(str_replace('&', '&', $h), '', $status); - } else { - redirige_par_entete('/', '', $status); + // On valide l’url si elle est publiee ; sinon si preview on teste l’autorisation + if ($publie) { + return $url; + } elseif (defined('_VAR_PREVIEW') and _VAR_PREVIEW and autoriser('voir', $type, $id)) { + return $url; } -} + + return; +} \ No newline at end of file diff --git a/ecrire/inc/securiser_action.php b/ecrire/inc/securiser_action.php index 4bbebfbc1b..8fcbed6d41 100644 --- a/ecrire/inc/securiser_action.php +++ b/ecrire/inc/securiser_action.php @@ -301,13 +301,12 @@ function verifier_cle_action($action, $cle) { * pour qu’une personne tierce le relise. Valable quelques temps. * * @see verifier_token_previsu() - * @param string $type Type d’objet - * @param int $id_objet Identifiant de l’objet + * @param string $url Url à autoriser en prévisu * @param int|null id_auteur qui génère le token de prévisu. Null utilisera auteur courant. * @param string $alea Nom de l’alea à utiliser * @return string Token, de la forme "{id}*{hash}" */ -function calculer_token_previsu($type, $id_objet, $id_auteur = null, $alea = 'alea_ephemere') { +function calculer_token_previsu($url, $id_auteur = null, $alea = 'alea_ephemere') { if (is_null($id_auteur)) { if (!empty($GLOBALS['visiteur_session']['id_auteur'])) { $id_auteur = $GLOBALS['visiteur_session']['id_auteur']; @@ -316,7 +315,10 @@ function calculer_token_previsu($type, $id_objet, $id_auteur = null, $alea = 'al if (!$id_auteur = intval($id_auteur)) { return ""; } - $token = _action_auteur('previsualiser-' . $type . '-' . $id_objet, $id_auteur, null, $alea); + // On nettoie l’URL de tous les var_. + $url = nettoyer_uri_var($url); + + $token = _action_auteur('previsualiser-' . $url, $id_auteur, null, $alea); return "$id_auteur-$token"; } @@ -338,8 +340,7 @@ function verifier_token_previsu($token) { // retrouver auteur / hash $e = explode('-', $token, 2); if (count($e) == 2 and is_numeric(reset($e))) { - list($id_auteur, $hash) = $e; - $id_auteur = intval($id_auteur); + $id_auteur = intval(reset($e)); } else { return false; } @@ -347,22 +348,12 @@ function verifier_token_previsu($token) { // calculer le type et id de l’url actuelle include_spip('inc/urls'); include_spip('inc/filtres_mini'); - $self = url_absolue(self()); - $contexte = urls_decoder_url($self); - list($type, $contexte) = $contexte; - if (is_numeric($type)) { - return false; - } - $_id_table = id_table_objet($type); - if (empty($contexte[$_id_table])) { - return false; - } - $id = $contexte[$_id_table]; + $url = url_absolue(self()); // verifier le token - $_token = calculer_token_previsu($type, $id, $id_auteur, 'alea_ephemere'); + $_token = calculer_token_previsu($url, $id_auteur, 'alea_ephemere'); if (!$_token or $token !== $_token) { - $_token = calculer_token_previsu($type, $id, $id_auteur, 'alea_ephemere_ancien'); + $_token = calculer_token_previsu($url, $id_auteur, 'alea_ephemere_ancien'); if (!$_token or $token !== $_token) { return false; } @@ -370,8 +361,6 @@ function verifier_token_previsu($token) { return array( 'id_auteur' => $id_auteur, - 'type' => $type, - 'id_objet' => $id ); } diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php index 7610de0d58..57afa33e78 100644 --- a/ecrire/inc/utils.php +++ b/ecrire/inc/utils.php @@ -591,15 +591,22 @@ function nettoyer_uri($reset = null) { return $propre; } $done = true; + return $propre = nettoyer_uri_var($GLOBALS['REQUEST_URI']); +} - $uri1 = $GLOBALS['REQUEST_URI']; +/** + * Nettoie une request_uri des paramètres var_xxx + * @param $request_uri + * @return string + */ +function nettoyer_uri_var($request_uri) { + $uri1 = $request_uri; do { $uri = $uri1; $uri1 = preg_replace(',([?&])(PHPSESSID|(var_[^=&]*))=[^&]*(&|$),i', '\1', $uri); } while ($uri <> $uri1); - - return $propre = (preg_replace(',[?&]$,', '', $uri1)); + return preg_replace(',[?&]$,', '', $uri1); } -- GitLab