From: nicosomb Date: Thu, 18 Apr 2013 13:39:34 +0000 (+0200) Subject: #4 - ajout système de connexion (login poche mot de passe poche pour l'instant) X-Git-Tag: 0.1~3 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=e4d2565e05a517641de921c4c19a2c9d1beea2e7;p=github%2Fwallabag%2Fwallabag.git #4 - ajout système de connexion (login poche mot de passe poche pour l'instant) --- diff --git a/CREDITS b/CREDITS index 31e74bad..c917a012 100644 --- a/CREDITS +++ b/CREDITS @@ -5,6 +5,7 @@ poche is based on : * logo by Brightmix http://www.iconfinder.com/icondetails/43256/128/jeans_monotone_pocket_icon * icons http://icomoon.io * PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/ +* Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php poche is developed by Nicolas Lœuillet under the Do What the Fuck You Want to Public License diff --git a/css/style.css b/css/style.css index cf1ee2f0..29dca289 100644 --- a/css/style.css +++ b/css/style.css @@ -62,16 +62,15 @@ header { color: #F1F1F1; } -/*#content { - width: 800px; - margin: 0 auto; -}*/ - - footer { text-align: right; } +/*** ***/ +/*** LOGIN FORM ***/ +ul#login li { + list-style-type: none; +} /*** ***/ /*** LINKS DISPLAY ***/ diff --git a/import.php b/import.php index 135443c9..72e3eac7 100644 --- a/import.php +++ b/import.php @@ -30,7 +30,7 @@ else { $url = $a[0]->href; - action_to_do('add', $url, $token); + action_to_do('add', $url); if ($read == '1') { $last_id = $db->getHandle()->lastInsertId(); $sql_update = "UPDATE entries SET is_read=~is_read WHERE id=?"; diff --git a/inc/MyTool.class.php b/inc/MyTool.class.php new file mode 100644 index 00000000..8206f3f7 --- /dev/null +++ b/inc/MyTool.class.php @@ -0,0 +1,256 @@ + '/* moderate */', + '/\[b\](.+?)\[\/b\]/is' + => '$1', + '/\[i\](.+?)\[\/i\]/is' + => '$1', + '/\[s\](.+?)\[\/s\]/is' + => '$1', + '/\[u\](.+?)\[\/u\]/is' + => '$1', + '/\[url\](.+?)\[\/url]/is' + => '$1', + '/\[url=(\w+:\/\/[^\]]+)\](.+?)\[\/url]/is' + => '$2', + '/\[quote\](.+?)\[\/quote\]/is' + => '
$1
', + '/\[code\](.+?)\[\/code\]/is' + => '$1', + '/\[([^[]+)\|([^[]+)\]/is' + => '$1' + ); + $text = preg_replace( + array_keys($replace), + array_values($replace), + $text + ); + + return $text; + } + + public static function formatText($text) + { + $text = preg_replace_callback( + '/(.*?)<\/code_html>/is', + create_function( + '$matches', + 'return htmlspecialchars($matches[1]);' + ), + $text + ); + $text = preg_replace_callback( + '/(.*?)<\/code_php>/is', + create_function( + '$matches', + 'return highlight_string("", true);' + ), + $text + ); + $text = preg_replace('/
/is', '', $text); + + $text = preg_replace( + '#(^|\s)([a-z]+://([^\s\w/]?[\w/])*)(\s|$)#im', + '\\1\\2\\4', + $text + ); + $text = preg_replace( + '#(^|\s)wp:?([a-z]{2}|):([\w]+)#im', + '\\1\\3', + $text + ); + $text = str_replace( + 'http://.wikipedia.org/wiki/', + 'http://www.wikipedia.org/wiki/', + $text + ); + $text = str_replace('\wp:', 'wp:', $text); + $text = str_replace('\http:', 'http:', $text); + $text = MyTool::formatBBCode($text); + $text = nl2br($text); + + return $text; + } + + public static function getUrl() + { + $https = (!empty($_SERVER['HTTPS']) + && (strtolower($_SERVER['HTTPS']) == 'on')) + || (isset($_SERVER["SERVER_PORT"]) + && $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection. + $serverport = (!isset($_SERVER["SERVER_PORT"]) + || $_SERVER["SERVER_PORT"] == '80' + || ($https && $_SERVER["SERVER_PORT"] == '443') + ? '' + : ':' . $_SERVER["SERVER_PORT"]); + + $scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]); + + if (!isset($_SERVER["SERVER_NAME"])) { + return $scriptname; + } + + return 'http' . ($https ? 's' : '') . '://' + . $_SERVER["SERVER_NAME"] . $serverport . $scriptname; + } + + public static function rrmdir($dir) + { + if (is_dir($dir) && ($d = @opendir($dir))) { + while (($file = @readdir($d)) !== false) { + if ( $file == '.' || $file == '..' ) { + continue; + } else { + unlink($dir . '/' . $file); + } + } + } + } + + public static function humanBytes($bytes) + { + $siPrefix = array( 'bytes', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB' ); + $base = 1024; + $class = min((int) log($bytes, $base), count($siPrefix) - 1); + $val = sprintf('%1.2f', $bytes / pow($base, $class)); + + return $val . ' ' . $siPrefix[$class]; + } + + public static function returnBytes($val) + { + $val = trim($val); + $last = strtolower($val[strlen($val)-1]); + switch($last) + { + case 'g': $val *= 1024; + case 'm': $val *= 1024; + case 'k': $val *= 1024; + } + + return $val; + } + + public static function getMaxFileSize() + { + $sizePostMax = MyTool::returnBytes(ini_get('post_max_size')); + $sizeUploadMax = MyTool::returnBytes(ini_get('upload_max_filesize')); + + // Return the smaller of two: + return min($sizePostMax, $sizeUploadMax); + } + + public static function smallHash($text) + { + $t = rtrim(base64_encode(hash('crc32', $text, true)), '='); + // Get rid of characters which need encoding in URLs. + $t = str_replace('+', '-', $t); + $t = str_replace('/', '_', $t); + $t = str_replace('=', '@', $t); + + return $t; + } + + public static function renderJson($data) + { + header('Cache-Control: no-cache, must-revalidate'); + header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); + header('Content-type: application/json; charset=UTF-8'); + + echo json_encode($data); + exit(); + } + + public static function grabToLocal($url, $file, $force = false) + { + if ((!file_exists($file) || $force) && in_array('curl', get_loaded_extensions())){ + $ch = curl_init ($url); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); + $raw = curl_exec($ch); + if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) { + $fp = fopen($file, 'x'); + fwrite($fp, $raw); + fclose($fp); + } + curl_close ($ch); + } + } + + public static function redirect($rurl = '') + { + if ($rurl === '') { + // if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0) + $rurl = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']); + if (isset($_POST['returnurl'])) { + $rurl = $_POST['returnurl']; + } + } + + // prevent loop + if (empty($rurl) || parse_url($rurl, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) { + $rurl = MyTool::getUrl(); + } + + if (substr($rurl, 0, 1) !== '?') { + $ref = MyTool::getUrl(); + if (substr($rurl, 0, strlen($ref)) !== $ref) { + $rurl = $ref; + } + } + header('Location: '.$rurl); + exit(); + } + + public static function silence_errors($num, $str) + { +// No-op + } +} \ No newline at end of file diff --git a/inc/Session.class.php b/inc/Session.class.php new file mode 100644 index 00000000..06fa6a8e --- /dev/null +++ b/inc/Session.class.php @@ -0,0 +1,136 @@ + $value) { + $_SESSION[$key] = $value; + } + if ($login==$login_test && $password==$password_test){ + // generate unique random number to sign forms (HMAC) + $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); + $_SESSION['info']=Session::_allInfos(); + $_SESSION['username']=$login; + // Set session expiration. + $_SESSION['expires_on']=time()+Session::$inactivity_timeout; + return true; + } + return false; + } + + // Force logout + public static function logout() + { + unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on']); + } + + // Make sure user is logged in. + public static function isLogged() + { + if (!isset ($_SESSION['uid']) + || $_SESSION['info']!=Session::_allInfos() + || time()>=$_SESSION['expires_on']){ + Session::logout(); + return false; + } + // User accessed a page : Update his/her session expiration date. + $_SESSION['expires_on']=time()+Session::$inactivity_timeout; + return true; + } + + // Returns a token. + public static function getToken() + { + if (!isset($_SESSION['tokens'])){ + $_SESSION['tokens']=array(); + } + // We generate a random string and store it on the server side. + $rnd = sha1(uniqid('',true).'_'.mt_rand()); + $_SESSION['tokens'][$rnd]=1; + return $rnd; + } + + // Tells if a token is ok. Using this function will destroy the token. + // return true if token is ok. + public static function isToken($token) + { + if (isset($_SESSION['tokens'][$token])) + { + unset($_SESSION['tokens'][$token]); // Token is used: destroy it. + return true; // Token is ok. + } + return false; // Wrong token, or already used. + } +} \ No newline at end of file diff --git a/inc/config.php b/inc/config.php index 386fd036..403217ce 100644 --- a/inc/config.php +++ b/inc/config.php @@ -22,10 +22,12 @@ include 'functions.php'; require_once 'Readability.php'; require_once 'Encoding.php'; require_once 'rain.tpl.class.php'; +require_once 'MyTool.class.php'; +require_once 'Session.class.php'; $db = new db(DB_PATH); -# Initialisation de RainTPL +# initialisation de RainTPL raintpl::$tpl_dir = './tpl/'; raintpl::$cache_dir = './cache/'; raintpl::$base_url = get_poche_url(); @@ -33,13 +35,43 @@ raintpl::configure('path_replace', false); raintpl::configure('debug', false); $tpl = new raintpl(); -# Démarrage session et initialisation du jeton de sécurité -session_start(); +# initialize session +Session::init(); +# XSRF protection with token +if (!empty($_POST)) { + if (!Session::isToken($_POST['token'])) { + die('Wrong token.'); + } + unset($_SESSION['tokens']); +} + +$ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; + +if (isset($_GET['login'])) { + // Login + if (!empty($_POST['login']) && !empty($_POST['password'])) { + if (Session::login('poche', 'poche', $_POST['login'], $_POST['password'])) { + if (!empty($_POST['longlastingsession'])) { + $_SESSION['longlastingsession'] = 31536000; + $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession']; + session_set_cookie_params($_SESSION['longlastingsession']); + } else { + session_set_cookie_params(0); // when browser closes + } + session_regenerate_id(true); -if (!isset($_SESSION['token_poche'])) { - $token = md5(uniqid(rand(), TRUE)); - $_SESSION['token_poche'] = $token; - $_SESSION['token_time_poche'] = time(); + MyTool::redirect(); + } + logm('login failed'); + die("Login failed !"); + } else { + logm('login successful'); + } +} +elseif (isset($_GET['logout'])) { + logm('logout'); + Session::logout(); + MyTool::redirect(); } # Traitement des paramètres et déclenchement des actions @@ -48,8 +80,12 @@ $action = (isset ($_REQUEST['action'])) ? htmlentities($_REQUEST['ac $_SESSION['sort'] = (isset ($_REQUEST['sort'])) ? htmlentities($_REQUEST['sort']) : 'id'; $id = (isset ($_REQUEST['id'])) ? htmlspecialchars($_REQUEST['id']) : ''; $url = (isset ($_GET['url'])) ? $_GET['url'] : ''; -$token = (isset ($_REQUEST['token'])) ? $_REQUEST['token'] : ''; + +$tpl->assign('isLogged', Session::isLogged()); +$tpl->assign('referer', $ref); +$tpl->assign('view', $view); +$tpl->assign('poche_url', get_poche_url()); if ($action != '') { - action_to_do($action, $url, $token, $id); + action_to_do($action, $url, $id); } diff --git a/inc/functions.php b/inc/functions.php index 936ec6ea..13acd36f 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -91,7 +91,7 @@ function get_external_file($url) function prepare_url($url) { $parametres = array(); - $url = html_entity_decode(trim($url)); + $url = html_entity_decode(trim($url)); // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...) // from shaarli, by sebsauvage @@ -99,7 +99,7 @@ function prepare_url($url) $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i); $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i); - $title = $url; + $title = $url; if (!preg_match('!^https?://!i', $url)) $url = 'http://' . $url; @@ -230,7 +230,7 @@ function remove_directory($directory) * Appel d'une action (mark as fav, archive, delete) */ -function action_to_do($action, $url, $token, $id = 0) +function action_to_do($action, $url, $id = 0) { global $db; @@ -248,29 +248,20 @@ function action_to_do($action, $url, $token, $id = 0) logm('add link ' . $url); break; case 'delete': - if (verif_token($token)) { - remove_directory(ABS_PATH . $id); - $sql_action = "DELETE FROM entries WHERE id=?"; - $params_action = array($id); - logm('delete link #' . $id); - } - else logm('csrf problem while deleting entry'); + remove_directory(ABS_PATH . $id); + $sql_action = "DELETE FROM entries WHERE id=?"; + $params_action = array($id); + logm('delete link #' . $id); break; case 'toggle_fav' : - if (verif_token($token)) { - $sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?"; - $params_action = array($id); - logm('mark as favorite link #' . $id); - } - else logm('csrf problem while fav entry'); + $sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?"; + $params_action = array($id); + logm('mark as favorite link #' . $id); break; case 'toggle_archive' : - if (verif_token($token)) { - $sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?"; - $params_action = array($id); - logm('archive link #' . $id); - } - else logm('csrf problem while archive entry'); + $sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?"; + $params_action = array($id); + logm('archive link #' . $id); break; default: break; @@ -305,7 +296,7 @@ function action_to_do($action, $url, $token, $id = 0) /** * Détermine quels liens afficher : home, fav ou archives */ -function display_view($view) +function get_entries($view) { global $db; @@ -385,36 +376,6 @@ function get_article($id) return $entry; } -/** - * Vérifie si le jeton passé en $_POST correspond à celui en session - */ -function verif_token($token) -{ - if(isset($_SESSION['token_poche']) && isset($_SESSION['token_time_poche']) && isset($token)) - { - if($_SESSION['token_poche'] == $token) - { - $old_timestamp = time() - (15*60); - if($_SESSION['token_time_poche'] >= $old_timestamp) - { - return TRUE; - } - else { - session_destroy(); - logm('session expired'); - } - } - else { - logm('token error : the token is different'); - return FALSE; - } - } - else { - logm('token error : the token is not here'); - return FALSE; - } -} - function logm($message) { $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; diff --git a/inc/rain.tpl.class.php b/inc/rain.tpl.class.php index ea83b2c1..6522c798 100644 --- a/inc/rain.tpl.class.php +++ b/inc/rain.tpl.class.php @@ -81,18 +81,18 @@ class RainTPL{ * */ static $check_template_update = true; - + /** - * PHP tags + * PHP tags * True: php tags are enabled into the template * False: php tags are disabled into the template and rendered as html * * @var bool */ - static $php_enabled = false; + static $php_enabled = true; + - /** * Debug mode flag. * True: debug mode is used, syntax errors are displayed directly in template. Execution of script is not terminated. @@ -285,7 +285,7 @@ class RainTPL{ */ protected function xml_reSubstitution($capture) { return "'; ?>"; - } + } /** * Compile and write the compiled template file @@ -304,11 +304,11 @@ class RainTPL{ $template_code = str_replace( array(""), array("<?","?>"), $template_code ); //xml re-substitution - $template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code ); + $template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code ); //compile template $template_compiled = "" . $this->compileTemplate( $template_code, $tpl_basedir ); - + // fix the php-eating-newline-after-closing-tag-problem $template_compiled = str_replace( "?>\n", "?>\n\n", $template_compiled ); @@ -413,7 +413,7 @@ class RainTPL{ // if the cache is active if( isset($code[ 2 ]) ){ - + //dynamic include $compiled_code .= 'cache( $template = basename("'.$include_var.'") ) )' . @@ -426,7 +426,7 @@ class RainTPL{ '} ?>'; } else{ - + //dynamic include $compiled_code .= 'assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ). '$tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'. '?>'; - - + + } } @@ -548,7 +548,7 @@ class RainTPL{ else // parse the function $parsed_function = $function . $this->var_replace( $code[ 2 ], $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); - + //if code $compiled_code .= ""; } @@ -582,8 +582,8 @@ class RainTPL{ } return $compiled_code; } - - + + /** * Reduce a path, eg. www/library/../filepath//file => www/filepath/file * @param type $path @@ -612,7 +612,7 @@ class RainTPL{ if( self::$path_replace ){ $tpl_dir = self::$base_url . self::$tpl_dir . $tpl_basedir; - + // reduce the path $path = $this->reduce_path($tpl_dir); @@ -683,7 +683,7 @@ class RainTPL{ $this->function_check( $tag ); $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level ); - + // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value $is_init_variable = preg_match( "/^(\s*?)\=[^=](.*?)$/", $extra_var ); @@ -712,7 +712,7 @@ class RainTPL{ //if there's a function if( $function_var ){ - + // check if there's a function or a static method and separate, function by parameters $function_var = str_replace("::", "@double_dot@", $function_var ); @@ -786,7 +786,7 @@ class RainTPL{ // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value $is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var ); - + //function associate to variable $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null; @@ -805,16 +805,16 @@ class RainTPL{ //transform .$variable in ["$variable"] and .variable in ["variable"] $variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path ); - + // if is an assignment also assign the variable to $this->var['value'] if( $is_init_variable ) $extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var; - + //if there's a function if( $function_var ){ - + // check if there's a function or a static method and separate, function by parameters $function_var = str_replace("::", "@double_dot@", $function_var ); @@ -855,13 +855,13 @@ class RainTPL{ $php_var = '$' . $var_name . $variable_path; }else $php_var = '$' . $var_name . $variable_path; - + // compile the variable for php if( isset( $function ) ) $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter; else $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter; - + $html = str_replace( $tag, $php_var, $html ); diff --git a/index.php b/index.php index d0d008ed..995426b4 100644 --- a/index.php +++ b/index.php @@ -10,17 +10,19 @@ include dirname(__FILE__).'/inc/config.php'; -$entries = display_view($view); +$entries = get_entries($view); $tpl->assign('title', 'poche, a read it later open source system'); -$tpl->assign('view', $view); -$tpl->assign('poche_url', get_poche_url()); $tpl->assign('entries', $entries); $tpl->assign('load_all_js', 1); -$tpl->assign('token', $_SESSION['token_poche']); $tpl->draw('head'); -$tpl->draw('home'); -$tpl->draw('entries'); -$tpl->draw('js'); -$tpl->draw('footer'); +if (Session::isLogged()) { + $tpl->draw('home'); + $tpl->draw('entries'); + $tpl->draw('js'); +} +else { + $tpl->draw('login'); +} +$tpl->draw('footer'); \ No newline at end of file diff --git a/tpl/entries.html b/tpl/entries.html index 0d3e6bc0..c74bc346 100644 --- a/tpl/entries.html +++ b/tpl/entries.html @@ -6,9 +6,9 @@
    -
  • -
  • -
  • +
  • +
  • +
diff --git a/tpl/head.html b/tpl/head.html index 66150d8f..6fcf9741 100644 --- a/tpl/head.html +++ b/tpl/head.html @@ -15,4 +15,9 @@ - \ No newline at end of file + + +
+

logo pochepoche

+
+
\ No newline at end of file diff --git a/tpl/home.html b/tpl/home.html index 568b9274..216f39b9 100644 --- a/tpl/home.html +++ b/tpl/home.html @@ -1,16 +1,12 @@ - -
-

logo pochepoche

-
-
    -
  • by date
  • -
  • by title
  • +
  • by date
  • +
  • by title
\ No newline at end of file diff --git a/tpl/login.html b/tpl/login.html new file mode 100644 index 00000000..024b3fd0 --- /dev/null +++ b/tpl/login.html @@ -0,0 +1,13 @@ +
+
+

login to your poche

+
    +
  • +
  • +
  • +
  • +
+
+ + +
\ No newline at end of file diff --git a/tpl/view.html b/tpl/view.html index 3a1ba7c6..1191bd82 100644 --- a/tpl/view.html +++ b/tpl/view.html @@ -1,4 +1,21 @@ -{include="head"} + + + + + + + + + + + {$title} + + + + + + +
@@ -6,9 +23,9 @@
    -
  • -
  • -
  • +
  • +
  • +
@@ -25,7 +42,12 @@
- {include="footer"} + {include="js"} + + + - + \ No newline at end of file diff --git a/view.php b/view.php index 9ba6f62d..29a5b324 100644 --- a/view.php +++ b/view.php @@ -24,7 +24,6 @@ if(!empty($id)) { $tpl->assign('is_fav', $entry[0]['is_fav']); $tpl->assign('is_read', $entry[0]['is_read']); $tpl->assign('load_all_js', 0); - $tpl->assign('token', $_SESSION['token_poche']); $tpl->draw('view'); } else {