mirror of
https://github.com/Piwigo/Piwigo.git
synced 2026-07-21 09:03:38 +02:00
issue #1953 improved privacy on searches and associate each search to its creator
* remove temporary functions ws_gallery_getSearch and ws_gallery_updateSearch * split get_search_array into sub-functions to use them in web API * use search_uuid as search_id instead of the numeric search.id : better privacy * only the creator of the search can update it * if a visitors tries to open the search of another user, it (the search) gets forked into a new search
This commit is contained in:
@@ -10,6 +10,45 @@
|
|||||||
* @package functions\search
|
* @package functions\search
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
function get_search_id_pattern($candidate)
|
||||||
|
{
|
||||||
|
$clause_pattern = null;
|
||||||
|
if (preg_match('/^psk-\d{8}-[a-z0-9]{10}$/i', $candidate))
|
||||||
|
{
|
||||||
|
$clause_pattern = 'search_uuid = \'%s\'';
|
||||||
|
}
|
||||||
|
elseif (preg_match('/^\d+$/', $candidate))
|
||||||
|
{
|
||||||
|
$clause_pattern = 'id = %u';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $clause_pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_search_info($candidate)
|
||||||
|
{
|
||||||
|
// $candidate might be a search.id or a search_uuid
|
||||||
|
$clause_pattern = get_search_id_pattern($candidate);
|
||||||
|
|
||||||
|
if (empty($clause_pattern))
|
||||||
|
{
|
||||||
|
die('Invalid search identifier');
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = '
|
||||||
|
SELECT *
|
||||||
|
FROM '.SEARCH_TABLE.'
|
||||||
|
WHERE '.sprintf($clause_pattern, $candidate).'
|
||||||
|
;';
|
||||||
|
$searches = query2array($query);
|
||||||
|
|
||||||
|
if (count($searches) > 0)
|
||||||
|
{
|
||||||
|
return $searches[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns search rules stored into a serialized array in "search"
|
* Returns search rules stored into a serialized array in "search"
|
||||||
@@ -20,24 +59,24 @@
|
|||||||
*/
|
*/
|
||||||
function get_search_array($search_id)
|
function get_search_array($search_id)
|
||||||
{
|
{
|
||||||
if (!is_numeric($search_id))
|
global $user;
|
||||||
{
|
|
||||||
die('Search id must be an integer');
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = '
|
$search = get_search_info($search_id);
|
||||||
SELECT rules
|
|
||||||
FROM '.SEARCH_TABLE.'
|
|
||||||
WHERE id = '.$search_id.'
|
|
||||||
;';
|
|
||||||
$rules_list = query2array($query);
|
|
||||||
|
|
||||||
if (count($rules_list) == 0)
|
if (empty($search))
|
||||||
{
|
{
|
||||||
bad_request('this search identifier does not exist');
|
bad_request('this search identifier does not exist');
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!empty($search['created_by']) and $search['created_by'] != $user['user_id'])
|
||||||
|
{
|
||||||
|
// we need to fork this search
|
||||||
|
save_search_and_redirect(unserialize($search['rules']), $search['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return unserialize($rules_list[0]['rules']);
|
return unserialize($search['rules']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1614,4 +1653,54 @@ function split_allwords($raw_allwords)
|
|||||||
return $words;
|
return $words;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_available_search_uuid()
|
||||||
|
{
|
||||||
|
$candidate = 'psk-'.date('Ymd').'-'.generate_key(10);
|
||||||
|
|
||||||
|
$query = '
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
FROM '.SEARCH_TABLE.'
|
||||||
|
WHERE search_uuid = \''.$candidate.'\'
|
||||||
|
;';
|
||||||
|
list($counter) = pwg_db_fetch_row(pwg_query($query));
|
||||||
|
if (0 == $counter)
|
||||||
|
{
|
||||||
|
return $candidate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return get_available_search_uuid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_search_and_redirect($rules, $forked_from=null)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
|
||||||
|
list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW()'));
|
||||||
|
$search_uuid = get_available_search_uuid();
|
||||||
|
|
||||||
|
single_insert(
|
||||||
|
SEARCH_TABLE,
|
||||||
|
array(
|
||||||
|
'rules' => pwg_db_real_escape_string(serialize($rules)),
|
||||||
|
'created_on' => $dbnow,
|
||||||
|
'created_by' => $user['user_id'],
|
||||||
|
'search_uuid' => $search_uuid,
|
||||||
|
'last_seen' => $dbnow,
|
||||||
|
'forked_from' => $forked_from,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
redirect(
|
||||||
|
make_index_url(
|
||||||
|
array(
|
||||||
|
'section' => 'search',
|
||||||
|
'search' => $search_uuid,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -648,10 +648,14 @@ function parse_section_url( $tokens, &$next_token)
|
|||||||
$page['section'] = 'search';
|
$page['section'] = 'search';
|
||||||
$next_token++;
|
$next_token++;
|
||||||
|
|
||||||
preg_match('/(\d+)/', @$tokens[$next_token], $matches);
|
preg_match('/^(psk-\d{8}-[a-zA-Z0-9]{10})$/', @$tokens[$next_token], $matches);
|
||||||
if (!isset($matches[1]))
|
if (!isset($matches[1]))
|
||||||
{
|
{
|
||||||
bad_request('search identifier is missing');
|
preg_match('/(\d+)/', @$tokens[$next_token], $matches);
|
||||||
|
if (!isset($matches[1]))
|
||||||
|
{
|
||||||
|
bad_request('search identifier is missing');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$page['search'] = $matches[1];
|
$page['search'] = $matches[1];
|
||||||
$next_token++;
|
$next_token++;
|
||||||
|
|||||||
@@ -362,6 +362,7 @@ else
|
|||||||
include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' );
|
include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' );
|
||||||
|
|
||||||
$search_result = get_search_results($page['search'], @$page['super_order_by'] );
|
$search_result = get_search_results($page['search'], @$page['super_order_by'] );
|
||||||
|
|
||||||
//save the details of the query search
|
//save the details of the query search
|
||||||
if ( isset($search_result['qs']) )
|
if ( isset($search_result['qs']) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -699,24 +699,28 @@ SELECT *
|
|||||||
*/
|
*/
|
||||||
function ws_images_filteredSearch_update($params, $service)
|
function ws_images_filteredSearch_update($params, $service)
|
||||||
{
|
{
|
||||||
// echo json_encode($params); exit();
|
global $user;
|
||||||
|
|
||||||
include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
|
include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
|
||||||
|
|
||||||
// * check the search exists
|
// * check the search exists
|
||||||
$query = '
|
if (empty(get_search_id_pattern($params['search_id'])))
|
||||||
SELECT id
|
{
|
||||||
FROM '.SEARCH_TABLE.'
|
return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid search_id input parameter.');
|
||||||
WHERE id = '.$params['search_id'].'
|
}
|
||||||
;';
|
|
||||||
|
|
||||||
if (count(query2array($query)) == 0)
|
$search_info = get_search_info($params['search_id']);
|
||||||
|
if (empty($search_info))
|
||||||
{
|
{
|
||||||
return new PwgError(WS_ERR_INVALID_PARAM, 'This search does not exist.');
|
return new PwgError(WS_ERR_INVALID_PARAM, 'This search does not exist.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$search = array('mode' => 'AND');
|
if (!empty($search_info['created_by']) and $search_info['created_by'] != $user['user_id'])
|
||||||
|
{
|
||||||
|
return new PwgError(WS_ERR_INVALID_PARAM, 'This search was created by another user.');
|
||||||
|
}
|
||||||
|
|
||||||
// TODO we should check that this search is updated by the user who created the search.
|
$search = array('mode' => 'AND');
|
||||||
|
|
||||||
// * check all parameters
|
// * check all parameters
|
||||||
if (isset($params['allwords']))
|
if (isset($params['allwords']))
|
||||||
@@ -848,7 +852,7 @@ SELECT id
|
|||||||
UPDATE '.SEARCH_TABLE.'
|
UPDATE '.SEARCH_TABLE.'
|
||||||
SET rules = \''.pwg_db_real_escape_string(serialize($search)).'\'
|
SET rules = \''.pwg_db_real_escape_string(serialize($search)).'\'
|
||||||
, last_seen = NOW()
|
, last_seen = NOW()
|
||||||
WHERE id = '.$params['search_id'].'
|
WHERE id = '.$search_info['id'].'
|
||||||
;';
|
;';
|
||||||
pwg_query($query);
|
pwg_query($query);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1083,43 +1083,4 @@ SELECT
|
|||||||
'summary' => $search_summary
|
'summary' => $search_summary
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ws_gallery_getSearch($param, &$service)
|
|
||||||
{
|
|
||||||
// return $param;
|
|
||||||
if (is_null($param['search_id']))
|
|
||||||
{
|
|
||||||
// Créer une recherche
|
|
||||||
return new PwgError(404, 'Search id is null');
|
|
||||||
}
|
|
||||||
include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
|
|
||||||
|
|
||||||
if (get_search_array($param['search_id']) == false)
|
|
||||||
{
|
|
||||||
return new PwgError(1404, 'Search associated to id '.$param['search_id'].' not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return get_search_array($param['search_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ws_gallery_updateSearch($param, &$service)
|
|
||||||
{
|
|
||||||
// return $param;
|
|
||||||
if (is_null($param['search_id']))
|
|
||||||
{
|
|
||||||
// Créer une recherche
|
|
||||||
return new PwgError(404, 'Search id is null');
|
|
||||||
}
|
|
||||||
include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
|
|
||||||
|
|
||||||
if (get_search_array($param['search_id']) == false)
|
|
||||||
{
|
|
||||||
return new PwgError(404, 'Search associated to id '.$param['search_id'].' not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
$tmp = get_search_array($param['search_id']);
|
|
||||||
|
|
||||||
// return 'search #'.$param['search_id'].' updated';
|
|
||||||
return $param;
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | This file is part of Piwigo. |
|
||||||
|
// | |
|
||||||
|
// | For copyright and license information, please view the COPYING.txt |
|
||||||
|
// | file that was distributed with this source code. |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
|
||||||
|
if (!defined('PHPWG_ROOT_PATH'))
|
||||||
|
{
|
||||||
|
die('Hacking attempt!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$upgrade_description = 'Create new columns for search (search_uuid, created_on, user_idx, forked_from).';
|
||||||
|
|
||||||
|
pwg_query('
|
||||||
|
ALTER TABLE `'.PREFIX_TABLE.'search`
|
||||||
|
ADD COLUMN `search_uuid` CHAR(23) DEFAULT NULL,
|
||||||
|
ADD COLUMN `created_on` DATETIME DEFAULT NULL,
|
||||||
|
ADD COLUMN `created_by` MEDIUMINT(8) UNSIGNED,
|
||||||
|
ADD COLUMN `forked_from` INT(10) UNSIGNED
|
||||||
|
;');
|
||||||
|
|
||||||
|
echo "\n".$upgrade_description."\n";
|
||||||
|
|
||||||
|
?>
|
||||||
+2
-21
@@ -9,6 +9,7 @@
|
|||||||
//--------------------------------------------------------------------- include
|
//--------------------------------------------------------------------- include
|
||||||
define('PHPWG_ROOT_PATH','./');
|
define('PHPWG_ROOT_PATH','./');
|
||||||
include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
|
include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
|
||||||
|
include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
|
||||||
|
|
||||||
// +-----------------------------------------------------------------------+
|
// +-----------------------------------------------------------------------+
|
||||||
// | Check Access and exit when user status is not ok |
|
// | Check Access and exit when user status is not ok |
|
||||||
@@ -24,7 +25,6 @@ trigger_notify('loc_begin_search');
|
|||||||
$words = array();
|
$words = array();
|
||||||
if (!empty($_GET['q']))
|
if (!empty($_GET['q']))
|
||||||
{
|
{
|
||||||
include_once(PHPWG_ROOT_PATH.'include/functions_search.inc.php');
|
|
||||||
$words = split_allwords($_GET['q']);
|
$words = split_allwords($_GET['q']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,24 +78,5 @@ if (count($first_author) > 0)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW()'));
|
save_search_and_redirect($search);
|
||||||
|
|
||||||
single_insert(
|
|
||||||
SEARCH_TABLE,
|
|
||||||
array(
|
|
||||||
'rules' => pwg_db_real_escape_string(serialize($search)),
|
|
||||||
'last_seen' => $dbnow,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$search_id = pwg_db_insert_id(SEARCH_TABLE);
|
|
||||||
|
|
||||||
redirect(
|
|
||||||
make_index_url(
|
|
||||||
array(
|
|
||||||
'section' => 'search',
|
|
||||||
'search' => $search_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ fullname_of_cat = {$fullname_of};
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if isset($SEARCH_ID)}
|
{if isset($SEARCH_ID)}
|
||||||
search_id = {$SEARCH_ID};
|
search_id = '{$SEARCH_ID}';
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
str_word_widget_label = "{'Search for words'|@translate|escape:javascript}";
|
str_word_widget_label = "{'Search for words'|@translate|escape:javascript}";
|
||||||
|
|||||||
@@ -1372,9 +1372,7 @@ enabled_high, registration_date, registration_date_string, registration_date_sin
|
|||||||
'pwg.images.filteredSearch.update',
|
'pwg.images.filteredSearch.update',
|
||||||
'ws_images_filteredSearch_update',
|
'ws_images_filteredSearch_update',
|
||||||
array(
|
array(
|
||||||
'search_id' => array(
|
'search_id' => array(),
|
||||||
'type' => WS_TYPE_ID,
|
|
||||||
),
|
|
||||||
'allwords' => array(
|
'allwords' => array(
|
||||||
'flags' => WS_PARAM_OPTIONAL,
|
'flags' => WS_PARAM_OPTIONAL,
|
||||||
'info' => 'query to search by words',
|
'info' => 'query to search by words',
|
||||||
|
|||||||
Reference in New Issue
Block a user