@@ -23,130 +23,131 @@ function get_microtime()
2323//
2424function check_cookie ()
2525{
26- global $ db , $ db_type , $ feather_config , $ cookie_name , $ cookie_seed ;
26+ global $ cookie_name , $ cookie_seed ;
2727
28- $ now = time ();
29-
3028 // Get Slim current session
3129 $ feather = \Slim \Slim::getInstance ();
30+ $ now = time ();
3231
33- // If the cookie is set and it matches the correct pattern, then read the values from it
34- if (isset ($ _COOKIE [$ cookie_name ]) && preg_match ('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$% ' , $ _COOKIE [$ cookie_name ], $ matches )) {
35- $ cookie = array (
36- 'user_id ' => intval ($ matches [1 ]),
37- 'password_hash ' => $ matches [2 ],
38- 'expiration_time ' => intval ($ matches [3 ]),
39- 'cookie_hash ' => $ matches [4 ],
40- );
32+ // Get FeatherBB cookie
33+ $ cookie_raw = $ feather ->getCookie ($ cookie_name );
34+
35+ // Check if cookie exists and is valid (getCookie method returns false if the data has been tampered locally so it can't decrypt the cookie);
36+ if (isset ($ cookie_raw )) {
37+ $ cookie = json_decode ($ cookie_raw , true );
38+ $ checksum = hash_hmac ('sha1 ' , $ cookie ['user_id ' ].$ cookie ['expires ' ], $ cookie_seed . '_checksum ' );
39+
40+ // If cookie has a non-guest user, hasn't expired and is legit
41+ if ($ cookie ['user_id ' ] > 1 && $ cookie ['expires ' ] > $ now && $ checksum == $ cookie ['checksum ' ]) {
42+
43+ // Get user info from db
44+ $ select_check_cookie = array ('u.* ' , 'g.* ' , 'o.logged ' , 'o.idle ' );
45+ $ where_check_cookie = array ('u.id ' => intval ($ cookie ['user_id ' ]));
46+
47+ $ result = ORM ::for_table ($ feather ->prefix .'users ' )
48+ ->table_alias ('u ' )
49+ ->select_many ($ select_check_cookie )
50+ ->inner_join ($ feather ->prefix .'groups ' , array ('u.group_id ' , '= ' , 'g.g_id ' ), 'g ' )
51+ ->left_outer_join ($ feather ->prefix .'online ' , array ('o.user_id ' , '= ' , 'u.id ' ), 'o ' )
52+ ->where ($ where_check_cookie )
53+ ->find_result_set ();
54+
55+ foreach ($ result as $ feather ->user );
56+
57+ // Another security check, to prevent identity fraud by changing the user id in the cookie) (might be useless considering the strength of encryption)
58+ if (isset ($ feather ->user ->id ) && hash_hmac ('sha1 ' , $ feather ->user ->password , $ cookie_seed .'_password_hash ' ) === $ cookie ['password_hash ' ]) {
59+ $ expires = ($ cookie ['expires ' ] > $ now + $ feather ->config ['o_timeout_visit ' ]) ? $ now + 1209600 : $ now + $ feather ->config ['o_timeout_visit ' ];
60+ $ feather ->user ->is_guest = false ;
61+ $ feather ->user ->is_admmod = $ feather ->user ->g_id == FEATHER_ADMIN || $ feather ->user ->g_moderator == '1 ' ;
62+ feather_setcookie ($ feather ->user ->id , $ feather ->user ->password , $ expires );
63+ set_preferences ();
64+ return true ;
65+ }
66+ }
4167 }
68+ // If there is no cookie, or cookie is guest or expired, let's reconnect.
69+ $ expires = $ now + 31536000 ; // The cookie expires after a year
70+ feather_setcookie (1 , feather_hash (uniqid (rand (), true )), $ expires );
71+ return set_default_user ();
72+ }
4273
43- // If it has a non-guest user, and hasn't expired
44- if (isset ($ cookie ) && $ cookie ['user_id ' ] > 1 && $ cookie ['expiration_time ' ] > $ now ) {
45- // If the cookie has been tampered with
46- if (hash_hmac ('sha1 ' , $ cookie ['user_id ' ].'| ' .$ cookie ['expiration_time ' ], $ cookie_seed .'_cookie_hash ' ) !== $ cookie ['cookie_hash ' ]) {
47- $ expire = $ now + 31536000 ; // The cookie expires after a year
48- feather_setcookie (1 , feather_hash (uniqid (rand (), true )), $ expire );
49- set_default_user ();
50-
51- return ;
52- }
53-
54- $ select_check_cookie = array ('u.* ' , 'g.* ' , 'o.logged ' , 'o.idle ' );
55- $ where_check_cookie = array ('u.id ' => intval ($ cookie ['user_id ' ]));
56-
57- $ result = ORM ::for_table ($ feather ->prefix .'users ' )
58- ->table_alias ('u ' )
59- ->select_many ($ select_check_cookie )
60- ->inner_join ($ feather ->prefix .'groups ' , array ('u.group_id ' , '= ' , 'g.g_id ' ), 'g ' )
61- ->left_outer_join ($ feather ->prefix .'online ' , array ('o.user_id ' , '= ' , 'u.id ' ), 'o ' )
62- ->where ($ where_check_cookie )
63- ->find_result_set ();
64-
65- foreach ($ result as $ feather ->user );
66-
67- // If user authorisation failed
68- if (!isset ($ feather ->user ->id ) || hash_hmac ('sha1 ' , $ feather ->user ->password , $ cookie_seed .'_password_hash ' ) !== $ cookie ['password_hash ' ]) {
69- $ expire = $ now + 31536000 ; // The cookie expires after a year
70- feather_setcookie (1 , feather_hash (uniqid (rand (), true )), $ expire );
71- set_default_user ();
74+ //
75+ // Set preferences
76+ //
77+ function set_preferences ()
78+ {
79+ global $ db_type , $ cookie_name ;
7280
73- return ;
74- }
81+ // Get Slim current session
82+ $ feather = \Slim \Slim::getInstance ();
83+ $ now = time ();
7584
76- // Send a new, updated cookie with a new expiration timestamp
77- $ expire = ($ cookie ['expiration_time ' ] > $ now + $ feather_config ['o_timeout_visit ' ]) ? $ now + 1209600 : $ now + $ feather_config ['o_timeout_visit ' ];
78- feather_setcookie ($ feather ->user ->id , $ feather ->user ->password , $ expire );
85+ // Set a default language if the user selected language no longer exists
86+ if (!file_exists (FEATHER_ROOT .'lang/ ' .$ feather ->user ->language )) {
87+ $ feather ->user ->language = $ feather ->config ['o_default_lang ' ];
88+ }
7989
80- // Set a default language if the user selected language no longer exists
81- if (!file_exists (FEATHER_ROOT .'lang / ' .$ feather ->user ->language )) {
82- $ feather ->user ->language = $ feather_config [ ' o_default_lang ' ];
83- }
90+ // Set a default style if the user selected style no longer exists
91+ if (!file_exists (FEATHER_ROOT .'style / ' .$ feather ->user ->style . ' .css ' )) {
92+ $ feather ->user ->style = $ feather -> config [ ' o_default_style ' ];
93+ }
8494
85- // Set a default style if the user selected style no longer exists
86- if (!file_exists (FEATHER_ROOT .'style/ ' .$ feather ->user ->style .'.css ' )) {
87- $ feather ->user ->style = $ feather_config ['o_default_style ' ];
88- }
95+ if (!$ feather ->user ->disp_topics ) {
96+ $ feather ->user ->disp_topics = $ feather ->config ['o_disp_topics_default ' ];
97+ }
98+ if (!$ feather ->user ->disp_posts ) {
99+ $ feather ->user ->disp_posts = $ feather ->config ['o_disp_posts_default ' ];
100+ }
89101
90- if (!$ feather ->user ->disp_topics ) {
91- $ feather ->user ->disp_topics = $ feather_config ['o_disp_topics_default ' ];
92- }
93- if (!$ feather ->user ->disp_posts ) {
94- $ feather ->user ->disp_posts = $ feather_config ['o_disp_posts_default ' ];
95- }
102+ // Define this if you want this visit to affect the online list and the users last visit data
103+ if (!defined ('FEATHER_QUIET_VISIT ' )) {
104+ // Update the online list
105+ if (!$ feather ->user ->logged ) {
106+ $ feather ->user ->logged = $ now ;
96107
97- // Define this if you want this visit to affect the online list and the users last visit data
98- if (!defined ('FEATHER_QUIET_VISIT ' )) {
99- // Update the online list
100- if (!$ feather ->user ->logged ) {
101- $ feather ->user ->logged = $ now ;
102-
103- // With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
104- switch ($ db_type ) {
105- case 'mysql ' :
106- case 'mysqli ' :
107- case 'mysql_innodb ' :
108- case 'mysqli_innodb ' :
109- case 'sqlite ' :
110- case 'sqlite3 ' :
111- \ORM ::for_table ($ db ->prefix .'online ' )->raw_execute ('REPLACE INTO ' .$ db ->prefix .'online (user_id, ident, logged) VALUES(:user_id, :ident, :logged) ' , array (':user_id ' => $ feather ->user ->id , ':ident ' => $ feather ->user ->username , ':logged ' => $ feather ->user ->logged ));
112- break ;
113-
114- default :
115- \ORM ::for_table ($ db ->prefix .'online ' )->raw_execute ('INSERT INTO ' .$ db ->prefix .'online (user_id, ident, logged) SELECT :user_id, :ident, :logged WHERE NOT EXISTS (SELECT 1 FROM ' .$ db ->prefix .'online WHERE user_id=:user_id) ' , array (':user_id ' => $ feather ->user ->id , ':ident ' => $ feather ->user ->username , ':logged ' => $ feather ->user ->logged ));
116- break ;
117- }
108+ // With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
109+ switch ($ db_type ) {
110+ case 'mysql ' :
111+ case 'mysqli ' :
112+ case 'mysql_innodb ' :
113+ case 'mysqli_innodb ' :
114+ case 'sqlite ' :
115+ case 'sqlite3 ' :
116+ \ORM ::for_table ($ feather ->db ->prefix .'online ' )->raw_execute ('REPLACE INTO ' .$ feather ->db ->prefix .'online (user_id, ident, logged) VALUES(:user_id, :ident, :logged) ' , array (':user_id ' => $ feather ->user ->id , ':ident ' => $ feather ->user ->username , ':logged ' => $ feather ->user ->logged ));
117+ break ;
118118
119- // Reset tracked topics
120- set_tracked_topics (null );
121- } else {
122- // Special case: We've timed out, but no other user has browsed the forums since we timed out
123- if ($ feather ->user ->logged < ($ now -$ feather_config ['o_timeout_visit ' ])) {
124- \ORM ::for_table ($ this ->db ->prefix .'users ' )->where ('id ' , $ feather ->user ->id )
125- ->find_one ()
126- ->set ('last_visit ' , $ feather ->user ->logged )
127- ->save ();
128- $ feather ->user ->last_visit = $ feather ->user ->logged ;
129- }
119+ default :
120+ \ORM ::for_table ($ feather ->db ->prefix .'online ' )->raw_execute ('INSERT INTO ' .$ feather ->db ->prefix .'online (user_id, ident, logged) SELECT :user_id, :ident, :logged WHERE NOT EXISTS (SELECT 1 FROM ' .$ feather ->db ->prefix .'online WHERE user_id=:user_id) ' , array (':user_id ' => $ feather ->user ->id , ':ident ' => $ feather ->user ->username , ':logged ' => $ feather ->user ->logged ));
121+ break ;
122+ }
130123
131- $ idle_sql = ($ feather ->user ->idle == '1 ' ) ? ', idle=0 ' : '' ;
132-
133- \ORM ::for_table ($ db ->prefix .'online ' )->raw_execute ('UPDATE ' .$ db ->prefix .'online SET logged= ' .$ now .$ idle_sql .' WHERE user_id=:user_id ' , array (':user_id ' => $ feather ->user ->id ));
124+ // Reset tracked topics
125+ set_tracked_topics (null );
134126
135- // Update tracked topics with the current expire time
136- if (isset ($ _COOKIE [$ cookie_name .'_track ' ])) {
137- forum_setcookie ($ cookie_name .'_track ' , $ _COOKIE [$ cookie_name .'_track ' ], $ now + $ feather_config ['o_timeout_visit ' ]);
138- }
139- }
140127 } else {
141- if (!$ feather ->user ->logged ) {
142- $ feather ->user ->logged = $ feather ->user ->last_visit ;
128+ // Special case: We've timed out, but no other user has browsed the forums since we timed out
129+ if ($ feather ->user ->logged < ($ now -$ feather ->config ['o_timeout_visit ' ])) {
130+ \ORM ::for_table ($ feather ->db ->prefix .'users ' )->where ('id ' , $ feather ->user ->id )
131+ ->find_one ()
132+ ->set ('last_visit ' , $ feather ->user ->logged )
133+ ->save ();
134+ $ feather ->user ->last_visit = $ feather ->user ->logged ;
143135 }
144- }
145136
146- $ feather ->user ->is_guest = false ;
147- $ feather ->user ->is_admmod = $ feather ->user ->g_id == FEATHER_ADMIN || $ feather ->user ->g_moderator == '1 ' ;
137+ $ idle_sql = ($ feather ->user ->idle == '1 ' ) ? ', idle=0 ' : '' ;
138+
139+ \ORM ::for_table ($ feather ->db ->prefix .'online ' )->raw_execute ('UPDATE ' .$ feather ->db ->prefix .'online SET logged= ' .$ now .$ idle_sql .' WHERE user_id=:user_id ' , array (':user_id ' => $ feather ->user ->id ));
140+
141+ // Update tracked topics with the current expire time
142+ $ cookie_tracked_topics = $ feather ->getCookie ($ cookie_name .'_track ' );
143+ if (isset ($ cookie_tracked_topics )) {
144+ set_tracked_topics (json_decode ($ cookie_tracked_topics , true ));
145+ }
146+ }
148147 } else {
149- set_default_user ();
148+ if (!$ feather ->user ->logged ) {
149+ $ feather ->user ->logged = $ feather ->user ->last_visit ;
150+ }
150151 }
151152}
152153
@@ -308,14 +309,19 @@ function set_default_user()
308309
309310
310311//
311- // Set a cookie, FluxBB style!
312- // Wrapper for forum_setcookie
312+ // Wrapper for Slim setCookie method
313313//
314- function feather_setcookie ($ user_id , $ password_hash , $ expire )
314+ function feather_setcookie ($ user_id , $ password , $ expires )
315315{
316316 global $ cookie_name , $ cookie_seed ;
317317
318- forum_setcookie ($ cookie_name , $ user_id .'| ' .hash_hmac ('sha1 ' , $ password_hash , $ cookie_seed .'_password_hash ' ).'| ' .$ expire .'| ' .hash_hmac ('sha1 ' , $ user_id .'| ' .$ expire , $ cookie_seed .'_cookie_hash ' ), $ expire );
318+ // Get Slim current session
319+ $ feather = \Slim \Slim::getInstance ();
320+ $ cookie_data = array ('user_id ' => $ user_id ,
321+ 'password_hash ' => hash_hmac ('sha1 ' , $ password , $ cookie_seed .'_password_hash ' ),
322+ 'expires ' => $ expires ,
323+ 'checksum ' => hash_hmac ('sha1 ' , $ user_id .$ expires , $ cookie_seed .'_checksum ' ));
324+ $ feather ->setCookie ($ cookie_name , json_encode ($ cookie_data ), $ expires );
319325}
320326
321327
@@ -557,33 +563,22 @@ function generate_page_title($page_title, $p = null)
557563//
558564// Save array of tracked topics in cookie
559565//
560- function set_tracked_topics ($ tracked_topics )
566+ function set_tracked_topics ($ tracked_topics = null )
561567{
562- global $ cookie_name , $ cookie_path , $ cookie_domain , $ cookie_secure , $ feather_config ;
568+ global $ cookie_name ;
569+
570+ // Get Slim current session
571+ $ feather = \Slim \Slim::getInstance ();
563572
564- $ cookie_data = '' ;
565573 if (!empty ($ tracked_topics )) {
566574 // Sort the arrays (latest read first)
567575 arsort ($ tracked_topics ['topics ' ], SORT_NUMERIC );
568576 arsort ($ tracked_topics ['forums ' ], SORT_NUMERIC );
569-
570- // Homebrew serialization (to avoid having to run unserialize() on cookie data)
571- foreach ($ tracked_topics ['topics ' ] as $ id => $ timestamp ) {
572- $ cookie_data .= 't ' .$ id .'= ' .$ timestamp .'; ' ;
573- }
574- foreach ($ tracked_topics ['forums ' ] as $ id => $ timestamp ) {
575- $ cookie_data .= 'f ' .$ id .'= ' .$ timestamp .'; ' ;
576- }
577-
578- // Enforce a byte size limit (4096 minus some space for the cookie name - defaults to 4048)
579- if (strlen ($ cookie_data ) > FORUM_MAX_COOKIE_SIZE ) {
580- $ cookie_data = substr ($ cookie_data , 0 , FORUM_MAX_COOKIE_SIZE );
581- $ cookie_data = substr ($ cookie_data , 0 , strrpos ($ cookie_data , '; ' )).'; ' ;
582- }
577+ } else {
578+ $ tracked_topics = array ('topics ' => array (), 'forums ' => array ());
583579 }
584580
585- forum_setcookie ($ cookie_name .'_track ' , $ cookie_data , time () + $ feather_config ['o_timeout_visit ' ]);
586- $ _COOKIE [$ cookie_name .'_track ' ] = $ cookie_data ; // Set it directly in $_COOKIE as well
581+ return $ feather ->setCookie ($ cookie_name . '_track ' , json_encode ($ tracked_topics ), time () + $ feather ->config ['o_timeout_visit ' ]);
587582}
588583
589584
@@ -594,28 +589,16 @@ function get_tracked_topics()
594589{
595590 global $ cookie_name ;
596591
597- $ cookie_data = isset ($ _COOKIE [$ cookie_name .'_track ' ]) ? $ _COOKIE [$ cookie_name .'_track ' ] : false ;
598- if (!$ cookie_data ) {
599- return array ('topics ' => array (), 'forums ' => array ());
600- }
592+ // Get Slim current session
593+ $ feather = \Slim \Slim::getInstance ();
601594
602- if (strlen ($ cookie_data ) > FORUM_MAX_COOKIE_SIZE ) {
603- return array ('topics ' => array (), 'forums ' => array ());
604- }
595+ $ cookie_raw = $ feather ->getCookie ($ cookie_name .'_track ' );
605596
606- // Unserialize data from cookie
607- $ tracked_topics = array ('topics ' => array (), 'forums ' => array ());
608- $ temp = explode ('; ' , $ cookie_data );
609- foreach ($ temp as $ t ) {
610- $ type = substr ($ t , 0 , 1 ) == 'f ' ? 'forums ' : 'topics ' ;
611- $ id = intval (substr ($ t , 1 ));
612- $ timestamp = intval (substr ($ t , strpos ($ t , '= ' ) + 1 ));
613- if ($ id > 0 && $ timestamp > 0 ) {
614- $ tracked_topics [$ type ][$ id ] = $ timestamp ;
615- }
597+ if (isset ($ cookie_raw )) {
598+ $ cookie_data = json_decode ($ cookie_raw , true );
599+ return $ cookie_data ;
616600 }
617-
618- return $ tracked_topics ;
601+ return array ('topics ' => array (), 'forums ' => array ());
619602}
620603
621604
0 commit comments