From 88a4f7dcc810118b558bc285276f11bde3b7e915 Mon Sep 17 00:00:00 2001 From: Banana Date: Tue, 22 Oct 2019 00:20:33 +0200 Subject: [PATCH] auth with ?m=auth. Show private links only if auth available. Link management and actions only if auth available. --- TODO | 3 +- documentation/usage.txt | 11 +++ webroot/index.php | 3 + webroot/lib/link.class.php | 10 +++ webroot/lib/management.class.php | 131 +++++++++++++++++++++++++++---- webroot/lib/summoner.class.php | 15 ++++ webroot/view/home.inc.php | 28 +++++-- webroot/view/home.php | 6 +- webroot/view/linkinfo.inc.php | 12 +-- webroot/view/linkinfo.php | 2 + webroot/view/overview.inc.php | 5 ++ webroot/view/overview.php | 4 + 12 files changed, 198 insertions(+), 32 deletions(-) create mode 100644 documentation/usage.txt diff --git a/TODO b/TODO index 7bea930..7cfc51a 100755 --- a/TODO +++ b/TODO @@ -1,11 +1,12 @@ TODO / Feature list ========================================================================== + auth and de-auth call over url only. Then display edit buttons ++ show private links if authenticated + stats, storage usage. With stats and valid auth display moderation + email import auto reply check ++ better url compare. eg. urls with / or without / at the end + sorting + snapshots -+ show private links if authenticated + bookmark js snippet + theme support + more "secure" user authentication diff --git a/documentation/usage.txt b/documentation/usage.txt new file mode 100644 index 0000000..09294a9 --- /dev/null +++ b/documentation/usage.txt @@ -0,0 +1,11 @@ +Use Insipid as a self hosted service for your own bookmarks. Share and collect. + +Management needs authentication which is configured with the following options in the options file: + +FRONTEND_USERNAME => This is the username +FRONTEND_PASSWORD => This is the password for the username + +Call the following URL to trigger the authentication: +http(s)://your.domain.tld/path/to/insipid/index.php?m=auth + +If successful you can now manage your items. Edit buttons are visible now. diff --git a/webroot/index.php b/webroot/index.php index bd35095..4150334 100644 --- a/webroot/index.php +++ b/webroot/index.php @@ -88,6 +88,9 @@ $driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;; # management needs the DB object $Management = new Management($DB); +if($Summoner::simpleAuthCheck() === true) { + $Management->setShowPrivate(true); +} if(isset($_GET['p']) && !empty($_GET['p'])) { $_requestPage = trim($_GET['p']); diff --git a/webroot/lib/link.class.php b/webroot/lib/link.class.php index 65ab166..f73f357 100644 --- a/webroot/lib/link.class.php +++ b/webroot/lib/link.class.php @@ -73,6 +73,7 @@ class Link { $this->_tags(); $this->_categories(); $this->_image(); + $this->_private(); } } @@ -384,5 +385,14 @@ class Link { } } } + + /** + * check if the status is private and set the info + */ + private function _private() { + if(!empty($this->_data['status']) && $this->_data['status'] == "1") { + $this->_data['private'] = "1"; + } + } } diff --git a/webroot/lib/management.class.php b/webroot/lib/management.class.php index a766d3b..c4f0807 100644 --- a/webroot/lib/management.class.php +++ b/webroot/lib/management.class.php @@ -33,6 +33,8 @@ class Management { */ private $DB; + private $_showPrivate = false; + protected $COMBINED_SELECT_VALUES = "any_value(`id`) as id, any_value(`link`) as link, any_value(`created`) as created, @@ -50,6 +52,16 @@ class Management { $this->DB = $databaseConnectionObject; } + /** + * Show private links or not + * @param $bool + */ + public function setShowPrivate($bool) { + if(is_bool($bool)) { + $this->_showPrivate = $bool; + } + } + /** * get all the available categories from the DB. * optional limit @@ -65,9 +77,17 @@ class Management { if($stats === true) { $queryStr = "SELECT COUNT(*) as amount, - any_value(categoryid) as categoryId - FROM `".DB_PREFIX."_categoryrelation` - GROUP BY categoryid"; + any_value(cr.categoryid) as categoryId + FROM `".DB_PREFIX."_categoryrelation` AS cr, `".DB_PREFIX."_link` AS l + WHERE cr.linkid = l.id"; + if($this->_showPrivate === true) { + $queryStr .= " AND l.status IN (2,1)"; + } + else { + $queryStr .= " AND l.status = 2"; + } + $queryStr .= " GROUP BY categoryid"; + $query = $this->DB->query($queryStr); if(!empty($query)) { while($result = $query->fetch_assoc()) { @@ -114,9 +134,17 @@ class Management { if($stats === true) { $queryStr = "SELECT COUNT(*) as amount, - any_value(`tagid`) as tagId - FROM `".DB_PREFIX."_tagrelation` - GROUP BY tagId"; + any_value(tr.tagid) as tagId + FROM `".DB_PREFIX."_tagrelation` AS tr, `".DB_PREFIX."_link` AS l + WHERE tr.linkid = l.id"; + if($this->_showPrivate === true) { + $queryStr .= " AND l.status IN (2,1)"; + } + else { + $queryStr .= " AND l.status = 2"; + } + $queryStr .= "GROUP BY tagId"; + $query = $this->DB->query($queryStr); if(!empty($query)) { while($result = $query->fetch_assoc()) { @@ -156,7 +184,14 @@ class Management { public function latestLinks($limit=5) { $ret = array(); - $queryStr = "SELECT `title` FROM `".DB_PREFIX."_link` WHERE `status` = 2 ORDER BY `created` DESC"; + $queryStr = "SELECT `title` FROM `".DB_PREFIX."_link`"; + if($this->_showPrivate === true) { + $queryStr .= " WHERE `status` IN (2,1)"; + } + else { + $queryStr .= " WHERE `status` = 2"; + } + $queryStr .= " ORDER BY `created` DESC"; if(!empty($limit)) { $queryStr .= " LIMIT $limit"; } @@ -203,7 +238,9 @@ class Management { $querySelect = "SELECT ".$this->COMBINED_SELECT_VALUES; $queryFrom = " FROM `".DB_PREFIX."_combined`"; $queryWhere = " WHERE `status` = 2"; - + if($this->_showPrivate === true) { + $queryWhere = " WHERE `status` IN (2,1)"; + } if(!empty($id) && is_numeric($id)) { $queryWhere .= " AND `categoryId` = '" . $this->DB->real_escape_string($id) . "'"; } @@ -254,7 +291,9 @@ class Management { $querySelect = "SELECT ".$this->COMBINED_SELECT_VALUES; $queryFrom = " FROM `".DB_PREFIX."_combined`"; $queryWhere = " WHERE `status` = 2"; - + if($this->_showPrivate === true) { + $queryWhere = " WHERE `status` IN (2,1)"; + } if(!empty($id) && is_numeric($id)) { $queryWhere .= " AND `tagId` = '" . $this->DB->real_escape_string($id) . "'"; } @@ -302,6 +341,9 @@ class Management { $querySelect = "SELECT `hash`"; $queryFrom = " FROM `".DB_PREFIX."_link`"; $queryWhere = " WHERE `status` = 2"; + if($this->_showPrivate === true) { + $queryWhere = " WHERE `status` IN (2,1)"; + } $queryOrder = " ORDER BY `created` DESC"; $queryLimit = ""; if(!empty($limit)) { @@ -335,10 +377,15 @@ class Management { $ret = array(); if(!empty($categoryid) && is_numeric($categoryid)) { - $queryStr = "SELECT ".$this->COMBINED_SELECT_VALUES." - FROM `".DB_PREFIX."_combined` - WHERE `status` = 2 - AND `categoryId` = '" . $this->DB->real_escape_string($categoryid) . "' + $queryStr = "SELECT ".$this->COMBINED_SELECT_VALUES." + FROM `".DB_PREFIX."_combined`"; + if($this->_showPrivate === true) { + $queryStr .= " WHERE `status` IN (2,1)"; + } + else { + $queryStr .= " WHERE `status` = 2"; + } + $queryStr .= " AND `categoryId` = '" . $this->DB->real_escape_string($categoryid) . "' ORDER BY `created` DESC LIMIT 1"; $query = $this->DB->query($queryStr); @@ -349,6 +396,63 @@ class Management { return $ret; } + /** + * Search for the given url in the links table + * @param $url + * @return mixed + */ + public function searchForLinkByURL($url) { + $ret = false; + + if(!empty($url)) { + $queryStr = "SELECT * FROM `".DB_PREFIX."_link`"; + if($this->_showPrivate === true) { + $queryStr .= " WHERE `status` IN (2,1)"; + } + else { + $queryStr .= " WHERE `status` = 2"; + } + $queryStr .= " AND `link` = '".$this->DB->real_escape_string($url)."'"; + + $query = $this->DB->query($queryStr); + if(!empty($query) && $query->num_rows > 0) { + $ret = $query->fetch_all(MYSQLI_ASSOC); + } + } + + return $ret; + } + + /** + * search for given searchstring in the search data of the links + * @param $searchStr + * @return mixed + */ + public function searchForLinkBySearchData($searchStr) { + $ret = false; + + if(!empty($searchStr)) { + $queryStr = "SELECT *, + MATCH (`search`) AGAINST ('".$this->DB->real_escape_string($searchStr)."' IN BOOLEAN MODE) AS score + FROM `".DB_PREFIX."_link` + WHERE MATCH (`search`) AGAINST ('".$this->DB->real_escape_string($searchStr)."' IN BOOLEAN MODE)"; + if($this->_showPrivate === true) { + $queryStr .= " WHERE `status` IN (2,1)"; + } + else { + $queryStr .= " WHERE `status` = 2"; + } + $queryStr .= " ORDER BY score DESC"; + + $query = $this->DB->query($queryStr); + if(!empty($query) && $query->num_rows > 0) { + $ret = $query->fetch_all(MYSQLI_ASSOC); + } + } + + return $ret; + } + /** * for simpler management we have the search data in a separate column * it is not fancy or even technical nice but it damn works @@ -388,4 +492,3 @@ class Management { } } -?> diff --git a/webroot/lib/summoner.class.php b/webroot/lib/summoner.class.php index 28c2736..e04b8f9 100644 --- a/webroot/lib/summoner.class.php +++ b/webroot/lib/summoner.class.php @@ -435,6 +435,21 @@ class Summoner { } } + /** + * check if we have a valid auth. Nothing more. + * @see Summoner::simpleAuth to trigger the auth + * @return bool + */ + static function simpleAuthCheck() { + if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']) + && $_SERVER['PHP_AUTH_USER'] === FRONTEND_USERNAME && $_SERVER['PHP_AUTH_PW'] === FRONTEND_PASSWORD + ) { + return true; + } + + return false; + } + /** * Checks if in the given urlstring a scheme is existent. If not add http:// to it * @param $urlString diff --git a/webroot/view/home.inc.php b/webroot/view/home.inc.php index d6e7acc..2a06846 100644 --- a/webroot/view/home.inc.php +++ b/webroot/view/home.inc.php @@ -35,6 +35,17 @@ $showAddForm = false; $formData = false; $honeypotCheck = false; +$_requestMode = false; +if(isset($_GET['m']) && !empty($_GET['m'])) { + $_requestMode = trim($_GET['m']); + $_requestMode = Summoner::validate($_requestMode,'nospace') ? $_requestMode : "all"; +} +if($_requestMode === "auth") { + # very simple security check. + # can/should be extended in the future. + Summoner::simpleAuth(); +} + if((isset($_POST['password']) && !empty($_POST['password'])) || (isset($_POST['username']) && !empty($_POST['username']))) { # those are hidden fields. A robot may input these. A valid user does not. $honeypotCheck = true; @@ -48,6 +59,8 @@ if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['submitsearch # search for URL $queryStr = "SELECT * FROM `".DB_PREFIX."_link` WHERE `link` = '".$DB->real_escape_string($searchValue)."'"; + + $searchResult = $Management->searchForLinkByURL($searchValue); } elseif(Summoner::validate($searchValue,'text')) { $queryStr = "SELECT *, @@ -55,21 +68,24 @@ if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['submitsearch FROM `".DB_PREFIX."_link` WHERE MATCH (`search`) AGAINST ('".$DB->real_escape_string($searchValue)."' IN BOOLEAN MODE) ORDER BY score DESC"; + + $searchResult = $Management->searchForLinkBySearchData($searchValue); } else { $submitFeedback['message'] = 'Invalid input'; $submitFeedback['status'] = 'error'; } - +/* if(!empty($queryStr)) { $query = $DB->query($queryStr); if(!empty($query) && $query->num_rows > 0) { $searchResult = $query->fetch_all(MYSQLI_ASSOC); } } +*/ # new one? - if(empty($searchResult) && $isUrl === true) { + if(empty($searchResult) && $isUrl === true && Summoner::simpleAuthCheck() === true) { # try to gather some information automatically $linkInfo = Summoner::gatherInfoFromURL($searchValue); if(!empty($linkInfo)) { @@ -98,13 +114,11 @@ if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['submitsearch } # add a new one -if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['addnewone']) && $honeypotCheck === false) { +if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['addnewone']) && $honeypotCheck === false + && Summoner::simpleAuthCheck() === true +) { $fData = $_POST['data']; - # very simple security check. - # can/should be extended in the future. - Summoner::simpleAuth(); - $formData['private'] = 2; if(isset($fData['private'])) { $formData['private'] = 1; diff --git a/webroot/view/home.php b/webroot/view/home.php index 58128e9..cdf4a64 100644 --- a/webroot/view/home.php +++ b/webroot/view/home.php @@ -29,7 +29,7 @@
-
+
@@ -61,10 +61,8 @@

- - -
+
diff --git a/webroot/view/linkinfo.inc.php b/webroot/view/linkinfo.inc.php index ab36e2e..00c9cdb 100644 --- a/webroot/view/linkinfo.inc.php +++ b/webroot/view/linkinfo.inc.php @@ -25,11 +25,6 @@ * along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0. * */ -$_requestMode = false; -if(isset($_GET['m']) && !empty($_GET['m'])) { - $_requestMode = trim($_GET['m']); - $_requestMode = Summoner::validate($_requestMode,'nospace') ? $_requestMode : "all"; -} $_id = false; if(isset($_GET['id']) && !empty($_GET['id'])) { @@ -41,4 +36,9 @@ $linkObj = new Link($DB); $linkData = $linkObj->load($_id); if(empty($linkData)) { header("HTTP/1.0 404 Not Found"); -} \ No newline at end of file +} + +$_displayEditButton = false; +if(Summoner::simpleAuthCheck() === true) { + $_displayEditButton = true; +} diff --git a/webroot/view/linkinfo.php b/webroot/view/linkinfo.php index ab270e7..ab9c7cc 100644 --- a/webroot/view/linkinfo.php +++ b/webroot/view/linkinfo.php @@ -141,6 +141,7 @@ ?> +
+ diff --git a/webroot/view/overview.inc.php b/webroot/view/overview.inc.php index 2aa80c6..8910eb0 100644 --- a/webroot/view/overview.inc.php +++ b/webroot/view/overview.inc.php @@ -48,6 +48,11 @@ $tagCollection = array(); $categoryCollection = array(); $pagination = array('pages' => 0); +$_displayEditButton = false; +if(Summoner::simpleAuthCheck() === true) { + $_displayEditButton = true; +} + switch($_requestMode) { case 'tag': if(!empty($_id)) { diff --git a/webroot/view/overview.php b/webroot/view/overview.php index 405cb24..4a40e09 100644 --- a/webroot/view/overview.php +++ b/webroot/view/overview.php @@ -138,6 +138,7 @@ +
+
@@ -163,6 +165,7 @@
+
+ -- 2.39.5