diff --git a/data/tables.sql b/data/tables.sql index 59f15f2..32457b7 100644 --- a/data/tables.sql +++ b/data/tables.sql @@ -73,8 +73,7 @@ CREATE TABLE `sc_users` ( `email` varchar(50) NOT NULL default '', `homepage` varchar(255) default NULL, `uContent` text, - `privateKey` varchar(32) NULL, - `enablePrivateKey` int(1) default '0', + `privateKey` varchar(33) default NULL, PRIMARY KEY (`uId`), UNIQUE KEY `privateKey` (`privateKey`) ) CHARACTER SET utf8 COLLATE utf8_general_ci ; diff --git a/data/templates/editprofile.tpl.php b/data/templates/editprofile.tpl.php index f083322..16fbc94 100644 --- a/data/templates/editprofile.tpl.php +++ b/data/templates/editprofile.tpl.php @@ -32,7 +32,7 @@ $this->includeTemplate($GLOBALS['top_include']); - getEnablePrivateKey()==1) echo 'checked="checked"'; ?>>    + >    diff --git a/data/templates/rss.tpl.php b/data/templates/rss.tpl.php index e6e66f7..6be5425 100644 --- a/data/templates/rss.tpl.php +++ b/data/templates/rss.tpl.php @@ -3,7 +3,7 @@ echo '<' . '?xml version="1.0" encoding="utf-8" ?' . ">\n"; ?> - <?php echo htmlspecialchars($feedtitle); ?> + <?php echo $feedtitle; ?> @@ -23,4 +23,4 @@ echo '<' . '?xml version="1.0" encoding="utf-8" ?' . ">\n"; - \ No newline at end of file + diff --git a/data/templates/top.inc.php b/data/templates/top.inc.php index b1ffa14..40d69be 100644 --- a/data/templates/top.inc.php +++ b/data/templates/top.inc.php @@ -5,14 +5,13 @@ <?php echo filter($GLOBALS['sitename'] .(isset($pagetitle) ? ' ยป ' . $pagetitle : '')); ?> - + '; + $size = count($rsschannels); + for ($i = 0; $i < $size; $i++) { + echo ' '."\n"; } } ?> diff --git a/src/SemanticScuttle/Model/User.php b/src/SemanticScuttle/Model/User.php index 124bce3..c9debd9 100644 --- a/src/SemanticScuttle/Model/User.php +++ b/src/SemanticScuttle/Model/User.php @@ -36,7 +36,6 @@ class SemanticScuttle_Model_User var $datetime; var $isAdmin; var $privateKey; - var $enablePrivateKey; /** * Create a new user object @@ -86,22 +85,6 @@ class SemanticScuttle_Model_User return $this->privateKey; } - /** - * Returns private key flag - * - * @return integer private key 1=enabled, 0=disabled - */ - public function getEnablePrivateKey() - { - // Look for value only if not already set - if (!isset($this->enablePrivateKey)) { - $us = SemanticScuttle_Service_Factory::get('User'); - $user = $us->getUser($this->id); - $this->enablePrivateKey = $user['enablePrivateKey']; - } - return $this->enablePrivateKey; - } - /** * Returns full user name as specified in the profile. * diff --git a/src/SemanticScuttle/Service/Bookmark.php b/src/SemanticScuttle/Service/Bookmark.php index 3e4bfcc..8194cf1 100644 --- a/src/SemanticScuttle/Service/Bookmark.php +++ b/src/SemanticScuttle/Service/Bookmark.php @@ -303,7 +303,9 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService function editAllowed($bookmark) { if (!is_numeric($bookmark) - && (!is_array($bookmark) || !isset($bookmark['bId']) || !is_numeric($bookmark['bId'])) + && (!is_array($bookmark) + || !isset($bookmark['bId']) + || !is_numeric($bookmark['bId'])) ) { return false; } @@ -667,26 +669,26 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService * each bookmark array contains two additional keys: * 'hasVoted' and 'vote'. * - * @param integer $start Page number - * @param integer $perpage Number of bookmarks per page - * @param integer $user User ID - * @param mixed $tags Array of tags or tags separated - * by "+" signs - * @param string $terms Search terms separated by spaces - * @param string $sortOrder One of the following values: - * "date_asc", "date_desc", - * "title_desc", "title_asc", - * "url_desc", "url_asc", - * "voting_asc", "voting_desc" - * @param boolean $watched True if only watched bookmarks - * shall be returned (FIXME) - * @param integer $startdate Filter for creation date. - * SQL-DateTime value - * "YYYY-MM-DD hh:ii:ss' - * @param integer $enddate Filter for creation date. - * SQL-DateTime value - * "YYYY-MM-DD hh:ii:ss' - * @param string $hash Filter by URL hash + * @param integer $start Page number + * @param integer $perpage Number of bookmarks per page + * @param integer $user User ID + * @param mixed $tags Array of tags or tags separated + * by "+" signs + * @param string $terms Search terms separated by spaces + * @param string $sortOrder One of the following values: + * "date_asc", "date_desc", + * "title_desc", "title_asc", + * "url_desc", "url_asc", + * "voting_asc", "voting_desc" + * @param boolean $watched True if only watched bookmarks + * shall be returned (FIXME) + * @param integer $startdate Filter for creation date. + * SQL-DateTime value + * "YYYY-MM-DD hh:ii:ss' + * @param integer $enddate Filter for creation date. + * SQL-DateTime value + * "YYYY-MM-DD hh:ii:ss' + * @param string $hash Filter by URL hash * * @return array Array with two keys: 'bookmarks' and 'total'. * First contains an array of bookmarks, 'total' @@ -705,15 +707,16 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService if ($userservice->isLoggedOn()) { // All public bookmarks, user's own bookmarks // and any shared with user - $privacy = ' ((B.bStatus = 0) OR (B.uId = '. $sId .')'; - $watchlist = $userservice->getWatchlist($sId); - foreach ($watchlist as $watchuserID) { - $privacy .= ' OR (B.uId = '. $watchuserID .' AND B.bStatus = 1)'; + $privacy = ' AND ((B.bStatus = 0) OR (B.uId = '. $sId .')'; + $watchnames = $userservice->getWatchNames($sId, true); + foreach ($watchnames as $watchuser) { + $privacy .= ' OR (U.username = "'. $watchuser; + $privacy .= '" AND B.bStatus = 1)'; } $privacy .= ')'; } else { // Just public bookmarks - $privacy = ' B.bStatus = 0'; + $privacy = ' AND B.bStatus = 0'; } // Set up the tags, if need be. @@ -727,20 +730,17 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService } // Set up the SQL query. - $query_1 = 'SELECT DISTINCT(B.bHash), '; - $query_1.= '(select '. $userservice->getFieldName('username'); - $query_1.= ' from '. $userservice->getTableName(); - $query_1.= ' where uId=B.uId'; - $query_1.= ') as '. $userservice->getFieldName('username') .', '; - + $query_1 = 'SELECT DISTINCT '; if (SQL_LAYER == 'mysql4') { $query_1 .= 'SQL_CALC_FOUND_ROWS '; } - $query_1 .= 'B.*'; + $query_1 .= 'B.*, U.'. $userservice->getFieldName('username'); - $query_2 = ' FROM '. $this->getTableName() .' AS B'; + $query_2 = ' FROM '. $userservice->getTableName() .' AS U' + . ', '. $this->getTableName() .' AS B'; - $query_3 = ' WHERE '. $privacy; + $query_3 = ' WHERE B.uId = U.'. $userservice->getFieldName('primary'); + $query_3 .= $privacy; if ($GLOBALS['enableVoting'] && $GLOBALS['hideBelowVoting'] !== null && !$userservice->isAdmin($userservice->getCurrentUserId()) @@ -749,11 +749,9 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService } if (is_null($watched)) { -/* if (!is_null($user)) { $query_3 .= ' AND B.uId = '. $user; } -*/ } else { $arrWatch = $userservice->getWatchlist($user); if (count($arrWatch) > 0) { @@ -769,14 +767,20 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService } $query_5 = ''; + if ($hash == null) { + $query_5.= ' GROUP BY B.bHash'; + } + //Voting system //needs to be directly after FROM bookmarks if ($GLOBALS['enableVoting'] && $userservice->isLoggedOn()) { $cuid = $userservice->getCurrentUserId(); $vs = SemanticScuttle_Service_Factory::get('Vote'); - $query_1 .= ', (select !ISNULL(bId) from '.$vs->getTableName().' where bId=B.bId and uId='.(int)$cuid.') as hasVoted, (select vote from '.$vs->getTableName().' where bId=B.bId and uId='.(int)$cuid.') as vote'; - + $query_1 .= ', !ISNULL(V.bId) as hasVoted, V.vote as vote'; + $query_2 .= ' LEFT JOIN ' . $vs->getTableName() . ' AS V' + . ' ON B.bId = V.bId' + . ' AND V.uId = ' . (int)$cuid; } switch($sortOrder) { @@ -805,11 +809,6 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService $query_5 .= ' ORDER BY B.' . $GLOBALS['dateOrderField'] . ' DESC '; } - // Add GROUP BY only if tag is given - if ($tagcount > 0) { - $query_5 = ' GROUP BY B.bHash' . $query_5; - } - // Handle the parts of the query that depend on any tags that are present. $query_4 = ''; for ($i = 0; $i < $tagcount; $i ++) { @@ -859,9 +858,9 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService $query_4 .= ' OR B.bPrivateNote LIKE "' . $this->db->sql_escape($aTerms[$i]) .'%"'; - $query_4 .= ' OR B.uId = (select '.$userservice->getFieldName('primary').' from '.$userservice->getTableName().' where '.$userservice->getFieldName('username').'="' + $query_4 .= ' OR U.username = "' . $this->db->sql_escape($aTerms[$i]) - . '")'; + . '"'; //exact match for username if ($dotags) { $query_4 .= ' OR T.tag LIKE "' . $this->db->sql_escape($aTerms[$i]) diff --git a/src/SemanticScuttle/Service/User.php b/src/SemanticScuttle/Service/User.php index 71bbad3..3f2d5c7 100644 --- a/src/SemanticScuttle/Service/User.php +++ b/src/SemanticScuttle/Service/User.php @@ -577,6 +577,13 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService */ public function loginPrivateKey($username, $privatekey) { + /* Check for size, only 32 char keys will work */ + /* Failsafe to hopefully lessen hackability and */ + /* deactivated keys (preceded by dash) */ + if (strlen($privatekey) != 32) { + return false; + } + $query = 'SELECT '. $this->getFieldName('primary') .' FROM ' . $this->getTableName() .' WHERE ' . $this->getFieldName('username') .' = "' @@ -789,33 +796,26 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService * No checks are done in here - you ought to have checked * everything before calling this method! * - * @param string $username Username to use - * @param string $password Password to use - * @param string $email Email to use - * @param string $privateKey Key for RSS auth - * @param integer $enablePrivateKey Flag to enable Private RSS + * @param string $username Username to use + * @param string $password Password to use + * @param string $email Email to use + * @param string $privateKey Key for RSS auth * * @return mixed Integer user ID if all is well, * boolean false if an error occured */ - public function addUser( - $username, $password, $email, $privateKey=null, $enablePrivateKey=0 - ) { + public function addUser($username, $password, $email, $privateKey=null) + { // Set up the SQL UPDATE statement. $datetime = gmdate('Y-m-d H:i:s', time()); $password = $this->sanitisePassword($password); - // set new private key if enabled but user forgot to generate - if ($enablePrivateKey == 1) { - $privateKey = $this->getNewPrivateKey(); - } $values = array( 'username' => $username, 'password' => $password, 'email' => $email, 'uDatetime' => $datetime, 'uModified' => $datetime, - 'privateKey' => $privateKey, - 'enablePrivateKey' => $enablePrivateKey + 'privateKey' => $privateKey ); $sql = 'INSERT INTO '. $this->getTableName() . ' '. $this->db->sql_build_array('INSERT', $values); @@ -839,39 +839,52 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService /** * Update User Record * - * @param string $uId User ID - * @param string $password User Password - * @param string $name User Name - * @param string $email Email Address - * @param string $homepage Homepage URL - * @param string $uContent Content - * @param string $privateKey RSS Private Key - * @param integer $enablePrivateKey Flag to enable RSS Private Key + * @param string $uId User ID + * @param string $password User Password + * @param string $name User Name + * @param string $email Email Address + * @param string $homepage Homepage URL + * @param string $uContent Content + * @param string $privateKey RSS Private Key + * @param string $enablePrivateRSS RSS Private Key * * @return boolean true if it successful, false if not */ function updateUser( $uId, $password, $name, $email, $homepage, $uContent, - $privateKey=null, $enablePrivateKey=0 + $privateKey=null, $enablePrivateRSS=0 ) { if (!is_numeric($uId)) { return false; } + // prepend - to privateKey if disabled + if ($privateKey!=null and strlen($privateKey)==32 and $enablePrivateRSS==0) { + $privateKey = "-".$privateKey; + } + + // remove - from privateKey if enabling + if ($privateKey!=null and strlen($privateKey)==33 and $enablePrivateRSS==1) { + $privateKey = substr($privateKey, 1, 32); + } + + // if new user is enabling Private RSS, create new key + if ($privateKey==null and $enablePrivateRSS==1) { + $privateKey = $this->getNewPrivateKey(); + } + // Set up the SQL UPDATE statement. $moddatetime = gmdate('Y-m-d H:i:s', time()); if ($password == '') { $updates = array ( 'uModified' => $moddatetime, 'name' => $name, 'email' => $email, 'homepage' => $homepage, - 'uContent' => $uContent, 'privateKey' => $privateKey, - 'enablePrivateKey' => $enablePrivateKey); + 'uContent' => $uContent, 'privateKey' => $privateKey); } else { $updates = array ('uModified' => $moddatetime, 'password' => $this->sanitisePassword($password), 'name' => $name, 'email' => $email, 'homepage' => $homepage, - 'uContent' => $uContent, 'privateKey' => $privateKey, - 'enablePrivateKey' => $enablePrivateKey); + 'uContent' => $uContent, 'privateKey' => $privateKey); } $sql = 'UPDATE '. $this->getTableName() .' SET ' . $this->db->sql_build_array('UPDATE', $updates) .' WHERE ' diff --git a/tests/BookmarkTest.php b/tests/BookmarkTest.php index f54fe9a..c13ab17 100644 --- a/tests/BookmarkTest.php +++ b/tests/BookmarkTest.php @@ -1164,7 +1164,7 @@ class BookmarkTest extends TestBase //create bookmarks for main user and other one $this->addBookmark($uid, $address, 0); - $this->addBookmark($friendPublic1, $address, 1);//1 is shared + $this->addBookmark($friendPublic1, $address, 1);//1 is shared //log main user in $this->us->setCurrentUserId($uid); @@ -1342,6 +1342,51 @@ class BookmarkTest extends TestBase ); } + /** + * Test private bookmarks + * + * @return void + */ + public function testPrivateBookmarks() + { + $uid = $this->addUser(); + /* create private bookmark */ + $this->bs->addBookmark( + 'http://test', 'test', 'desc', 'note', + 2,//private + array(), null, null, false, false, $uid + ); + /* create public bookmark */ + $this->bs->addBookmark( + 'http://example.org', 'title', 'desc', 'priv', + 0,//public + array(), null, null, false, false, $uid + ); + + $this->assertEquals(1, $this->bs->countBookmarks($uid, 'public')); + $this->assertEquals(1, $this->bs->countBookmarks($uid, 'private')); + $this->assertEquals(0, $this->bs->countBookmarks($uid, 'shared')); + $this->assertEquals(2, $this->bs->countBookmarks($uid, 'all')); + + $this->us->setCurrentUserId($uid); + $bookmarks = $this->bs->getBookmarks(); + // first record should be private bookmark + $b0 = $bookmarks['bookmarks'][0]; + $this->assertEquals('test', $b0['bTitle']); + // second record should be public bookmark + $b0 = $bookmarks['bookmarks'][1]; + $this->assertEquals('title', $b0['bTitle']); + + // test non authenticated query + $this->us->setCurrentUserId(null); + $bookmarks = $this->bs->getBookmarks(); + // should only result in one link - public + $b2 = $bookmarks['bookmarks'][0]; + $this->assertEquals('title', $b2['bTitle']); + // there should be no second record + $this->assertNull($bookmarks['bookmarks'][1]); + + } } diff --git a/tests/UserTest.php b/tests/UserTest.php index a73285b..b626170 100644 --- a/tests/UserTest.php +++ b/tests/UserTest.php @@ -221,6 +221,57 @@ class UserTest extends TestBase $this->assertTrue($this->us->privateKeyExists($randKey)); } + + + + /** + * Test loginPrivateKey() function returns righ + * + * @return void + */ + public function testLoginWithPrivateKey() + { + /* normal user with enabled privatekey */ + $randKey = $this->us->getNewPrivateKey(); + $uid1 = $this->addUser('testusername', 'passw0rd', $randKey); + /* user that has disabled privatekey */ + $randKey2 = '-'.$this->us->getNewPrivateKey(); + $uid2 = $this->addUser('seconduser', 'passw0RD', $randKey2); + + /* test invalid credentials - both invalid login and key */ + $this->assertFalse( + $this->us->loginPrivateKey('userdoesnot', '02848248084082408240824802408248') + ); + + /* test valid credentials with private key enabled */ + $this->assertTrue( + $this->us->loginPrivateKey('testusername', $randKey) + ); + + /* test valid credentials with private key enabled but invalid key */ + $this->assertFalse( + $this->us->loginPrivateKey('testusername', '123') + ); + + /* confirm user exists so future fails should be due to randkey */ + $this->assertTrue( + $this->us->login('seconduser', 'passw0RD', false) + ); + + /* test valid credentials with private key disabled */ + $this->assertFalse( + $this->us->loginPrivateKey('seconduser', $randKey2) + ); + + /* test valid credentials with private key disabled and invalid key */ + $this->assertFalse( + $this->us->loginPrivateKey('seconduser', '-1') + ); + $this->assertFalse( + $this->us->loginPrivateKey('seconduser', null) + ); + } + } diff --git a/tests/prepare.php b/tests/prepare.php index 6afc284..214bc32 100644 --- a/tests/prepare.php +++ b/tests/prepare.php @@ -36,4 +36,4 @@ if ($GLOBALS['debugMode'] == true . '!!! The combination of debugMode and dbtype==mysql4' . ' will wreck some tests' . "\n\n"; } -?> \ No newline at end of file +?> diff --git a/www/bookmarks.php b/www/bookmarks.php index fe8c9fd..52145c4 100644 --- a/www/bookmarks.php +++ b/www/bookmarks.php @@ -259,7 +259,7 @@ if ($templatename == 'editbookmark.tpl') { ) ); if ($userservice->isLoggedOn()) { - if ($currentUser->getPrivateKey() <> null && $currentUser->getEnablePrivateKey() == 1) { + if (strlen($currentUser->getPrivateKey()) == 32) { array_push( $tplVars['rsschannels'], array( diff --git a/www/index.php b/www/index.php index ea28345..f1fc81b 100644 --- a/www/index.php +++ b/www/index.php @@ -44,12 +44,12 @@ $tplVars['rsschannels'] = array( ); if ($userservice->isLoggedOn()) { $currentUsername = $currentUser->getUsername(); - if ($currentUser->getPrivateKey() <> null && $currentUser->getEnablePrivateKey() == 1) { + if ($currentUser->getPrivateKey() <> null && strlen($currentUser->getPrivateKey()) == 32) { array_push( $tplVars['rsschannels'], array( filter($sitename . sprintf(T_(': (private) ')) . $sitename), - createURL('rss', filter($currentUsername, 'url') . '?sort='.getSortOrder().'&privatekey='.$currentUser->getPrivateKey()) + createURL('rss', filter($currentUsername, 'url') . '?sort='.getSortOrder().'&privatekey='.$currentUser->getPrivateKey()) ) ); } diff --git a/www/profile.php b/www/profile.php index a1b1841..06cc52d 100644 --- a/www/profile.php +++ b/www/profile.php @@ -66,7 +66,6 @@ if ($user) { if ($userservice->isLoggedOn() && $user == $currentUser->getUsername()) { $title = T_('My Profile'); $tplVars['privateKey'] = $currentUser->getPrivateKey(); - $tplVars['enablePrivateKey'] = $currentUser->getPrivateKey(); } else { $title = T_('Profile') .': '. $user; $tplVars['privateKey'] = ''; diff --git a/www/rss.php b/www/rss.php index 3138c2d..5f20fd1 100644 --- a/www/rss.php +++ b/www/rss.php @@ -82,6 +82,11 @@ if ($user && $user != 'all') { if ($privatekey != null) { if ($userservice->loginPrivateKey($user, $privatekey)) { $isTempLogin = true; + } else { + $tplVars['error'] = sprintf(T_('Failed to Autenticate User with username %s using private key'), $user); + $templateservice->loadTemplate('error.404.tpl', $tplVars); + //throw a 404 error + exit(); } } }