mirror of
https://github.com/Terranom674/Piwigo_Bratonien_Tools.git
synced 2026-09-19 18:44:30 +00:00
Add password-protected album sharing module
This commit is contained in:
241
include/album_shares.inc.php
Normal file
241
include/album_shares.inc.php
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<?php
|
||||||
|
if (!defined('PHPWG_ROOT_PATH'))
|
||||||
|
{
|
||||||
|
die('Hacking attempt!');
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_shares_table()
|
||||||
|
{
|
||||||
|
return $GLOBALS['prefixeTable'].'bratonien_tools_album_shares';
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_create_album_shares_table()
|
||||||
|
{
|
||||||
|
$table = bratonien_tools_shares_table();
|
||||||
|
pwg_query("CREATE TABLE IF NOT EXISTS `$table` (
|
||||||
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
category_id int(11) NOT NULL,
|
||||||
|
user_id mediumint(8) unsigned NOT NULL,
|
||||||
|
token_hash char(64) NOT NULL,
|
||||||
|
password_hash varchar(255) NOT NULL,
|
||||||
|
created_by mediumint(8) unsigned NOT NULL,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
expires_at datetime DEFAULT NULL,
|
||||||
|
active tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY token_hash (token_hash),
|
||||||
|
KEY category_id (category_id),
|
||||||
|
KEY user_id (user_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_drop_album_shares_table()
|
||||||
|
{
|
||||||
|
pwg_query('DROP TABLE IF EXISTS `'.bratonien_tools_shares_table().'`');
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_album_shares_init()
|
||||||
|
{
|
||||||
|
if (!isset($_GET['brshare']))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = strtolower(trim((string)$_GET['brshare']));
|
||||||
|
if (!preg_match('/^[a-f0-9]{48}$/', $token))
|
||||||
|
{
|
||||||
|
bratonien_tools_share_access_page('Ungültiger Freigabelink.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$share = bratonien_tools_get_share_by_token($token);
|
||||||
|
if (!$share)
|
||||||
|
{
|
||||||
|
bratonien_tools_share_access_page('Diese Freigabe existiert nicht oder wurde widerrufen.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($share['expires_at']) && strtotime($share['expires_at']) < time())
|
||||||
|
{
|
||||||
|
bratonien_tools_share_access_page('Diese Freigabe ist abgelaufen.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$session_key = 'bratonien_share_'.(int)$share['id'];
|
||||||
|
$authorized = !empty($_SESSION[$session_key]);
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if (!$authorized && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['bratonien_share_password']))
|
||||||
|
{
|
||||||
|
$password = (string)$_POST['bratonien_share_password'];
|
||||||
|
if (password_verify($password, $share['password_hash']))
|
||||||
|
{
|
||||||
|
$_SESSION[$session_key] = true;
|
||||||
|
$authorized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$error = 'Das Passwort ist nicht korrekt.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$authorized)
|
||||||
|
{
|
||||||
|
bratonien_tools_share_access_page($error, $token, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('is_a_guest') && is_a_guest())
|
||||||
|
{
|
||||||
|
log_user((int)$share['user_id'], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect(PHPWG_ROOT_PATH.'index.php?/category/'.(int)$share['category_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_get_share_by_token($token)
|
||||||
|
{
|
||||||
|
$hash = hash('sha256', $token);
|
||||||
|
$query = '\nSELECT s.*, c.name AS category_name\n FROM '.bratonien_tools_shares_table().' s\n JOIN '.CATEGORIES_TABLE.' c ON c.id = s.category_id\n WHERE s.token_hash = \''.pwg_db_real_escape_string($hash).'\'\n AND s.active = 1\n LIMIT 1\n;';
|
||||||
|
$result = pwg_query($query);
|
||||||
|
return pwg_db_num_rows($result) ? pwg_db_fetch_assoc($result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_get_album_shares()
|
||||||
|
{
|
||||||
|
$query = '\nSELECT s.*, c.name AS category_name, u.username AS created_by_name\n FROM '.bratonien_tools_shares_table().' s\n LEFT JOIN '.CATEGORIES_TABLE.' c ON c.id = s.category_id\n LEFT JOIN '.USERS_TABLE.' u ON u.id = s.created_by\n ORDER BY s.created_at DESC\n;';
|
||||||
|
return query2array($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_get_private_albums()
|
||||||
|
{
|
||||||
|
$query = '\nSELECT id, name, uppercats\n FROM '.CATEGORIES_TABLE.'\n WHERE status = \'private\'\n ORDER BY global_rank ASC, name ASC\n;';
|
||||||
|
return query2array($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_create_album_share()
|
||||||
|
{
|
||||||
|
global $user, $page;
|
||||||
|
|
||||||
|
$category_id = isset($_POST['share_category_id']) ? (int)$_POST['share_category_id'] : 0;
|
||||||
|
$password = (string)($_POST['share_password'] ?? '');
|
||||||
|
$expires = trim((string)($_POST['share_expires_at'] ?? ''));
|
||||||
|
|
||||||
|
if ($category_id < 1)
|
||||||
|
{
|
||||||
|
throw new Exception('Bitte ein privates Album auswählen.');
|
||||||
|
}
|
||||||
|
if ($password === '')
|
||||||
|
{
|
||||||
|
throw new Exception('Für eine geschützte Freigabe ist ein Passwort erforderlich.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = 'SELECT id FROM '.CATEGORIES_TABLE.' WHERE id = '.$category_id.' AND status = \'private\' LIMIT 1';
|
||||||
|
if (pwg_db_num_rows(pwg_query($query)) === 0)
|
||||||
|
{
|
||||||
|
throw new Exception('Das gewählte Album ist nicht privat oder existiert nicht.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$expires_at = null;
|
||||||
|
if ($expires !== '')
|
||||||
|
{
|
||||||
|
$ts = strtotime($expires);
|
||||||
|
if ($ts === false || $ts <= time())
|
||||||
|
{
|
||||||
|
throw new Exception('Das Ablaufdatum muss in der Zukunft liegen.');
|
||||||
|
}
|
||||||
|
$expires_at = date('Y-m-d H:i:s', $ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
$username = 'brshare_'.bin2hex(random_bytes(5));
|
||||||
|
$random_password = bin2hex(random_bytes(16));
|
||||||
|
$errors = array();
|
||||||
|
$new_user_id = register_user($username, $random_password, null, 0, $errors, false);
|
||||||
|
if (!$new_user_id || !empty($errors))
|
||||||
|
{
|
||||||
|
throw new Exception('Der Freigabebenutzer konnte nicht erstellt werden.');
|
||||||
|
}
|
||||||
|
|
||||||
|
pwg_query('UPDATE '.USER_INFOS_TABLE." SET status = 'generic' WHERE user_id = ".(int)$new_user_id);
|
||||||
|
bratonien_tools_grant_album_access((int)$new_user_id, $category_id);
|
||||||
|
|
||||||
|
$token = bin2hex(random_bytes(24));
|
||||||
|
$token_hash = hash('sha256', $token);
|
||||||
|
$password_hash = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
|
||||||
|
$query = '\nINSERT INTO '.bratonien_tools_shares_table().'\n (category_id, user_id, token_hash, password_hash, created_by, created_at, expires_at, active)\nVALUES\n ('.(int)$category_id.', '.(int)$new_user_id.', \' '.pwg_db_real_escape_string($token_hash).'\', \' '.pwg_db_real_escape_string($password_hash).'\', '.(int)$user['id'].', NOW(), '.($expires_at === null ? 'NULL' : '\''.pwg_db_real_escape_string($expires_at).'\'').', 1)\n;';
|
||||||
|
$query = str_replace("' ", "'", $query);
|
||||||
|
pwg_query($query);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'message' => 'Geschützte Albumfreigabe erstellt: '.get_absolute_root_url().'?brshare='.$token,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_revoke_album_share()
|
||||||
|
{
|
||||||
|
$share_id = isset($_POST['share_id']) ? (int)$_POST['share_id'] : 0;
|
||||||
|
if ($share_id < 1)
|
||||||
|
{
|
||||||
|
throw new Exception('Ungültige Freigabe.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = 'SELECT user_id FROM '.bratonien_tools_shares_table().' WHERE id = '.$share_id.' LIMIT 1';
|
||||||
|
$result = pwg_query($query);
|
||||||
|
if (!pwg_db_num_rows($result))
|
||||||
|
{
|
||||||
|
throw new Exception('Freigabe nicht gefunden.');
|
||||||
|
}
|
||||||
|
$row = pwg_db_fetch_assoc($result);
|
||||||
|
$user_id = (int)$row['user_id'];
|
||||||
|
|
||||||
|
pwg_query('DELETE FROM '.USER_ACCESS_TABLE.' WHERE user_id = '.$user_id);
|
||||||
|
if (defined('USER_GROUP_TABLE'))
|
||||||
|
{
|
||||||
|
pwg_query('DELETE FROM '.USER_GROUP_TABLE.' WHERE user_id = '.$user_id);
|
||||||
|
}
|
||||||
|
pwg_query('DELETE FROM '.USER_INFOS_TABLE.' WHERE user_id = '.$user_id);
|
||||||
|
pwg_query('DELETE FROM '.USERS_TABLE.' WHERE id = '.$user_id);
|
||||||
|
if (function_exists('delete_user_sessions'))
|
||||||
|
{
|
||||||
|
delete_user_sessions($user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pwg_query('DELETE FROM '.bratonien_tools_shares_table().' WHERE id = '.$share_id.' LIMIT 1');
|
||||||
|
|
||||||
|
return array('message' => 'Albumfreigabe wurde widerrufen.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_grant_album_access($user_id, $category_id)
|
||||||
|
{
|
||||||
|
$user_id = (int)$user_id;
|
||||||
|
$category_id = (int)$category_id;
|
||||||
|
|
||||||
|
$query = 'SELECT 1 FROM '.USER_ACCESS_TABLE.' WHERE user_id = '.$user_id.' AND cat_id = '.$category_id.' LIMIT 1';
|
||||||
|
if (pwg_db_num_rows(pwg_query($query)) === 0)
|
||||||
|
{
|
||||||
|
pwg_query('INSERT INTO '.USER_ACCESS_TABLE.' (user_id, cat_id) VALUES ('.$user_id.', '.$category_id.')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_ensure_private_album_access($category_id, $user_id = null)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
$uid = $user_id === null ? (int)$user['id'] : (int)$user_id;
|
||||||
|
if ($uid < 1 || (int)$category_id < 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bratonien_tools_grant_album_access($uid, (int)$category_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bratonien_tools_share_access_page($error = '', $token = '', $show_form = false)
|
||||||
|
{
|
||||||
|
header('Content-Type: text/html; charset=UTF-8');
|
||||||
|
$action = htmlspecialchars(get_absolute_root_url().'?brshare='.$token, ENT_QUOTES, 'UTF-8');
|
||||||
|
$message = $error !== '' ? '<p class="brshare-error">'.htmlspecialchars($error, ENT_QUOTES, 'UTF-8').'</p>' : '';
|
||||||
|
$form = '';
|
||||||
|
if ($show_form)
|
||||||
|
{
|
||||||
|
$form = '<form method="post" action="'.$action.'"><label for="brshare-password">Passwort</label><input id="brshare-password" type="password" name="bratonien_share_password" required autofocus><button type="submit">Album öffnen</button></form>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<!doctype html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Geschützte Albumfreigabe</title><style>body{margin:0;min-height:100vh;display:grid;place-items:center;background:#202428;color:#eee;font-family:system-ui,sans-serif}.brshare{width:min(92vw,460px);padding:28px;border:1px solid #555;background:#2b3035;box-shadow:0 12px 30px rgba(0,0,0,.35)}h1{font-size:1.4rem;margin:0 0 14px}p{line-height:1.5}.brshare-error{color:#ffb4b4}label{display:block;margin:16px 0 6px}input{box-sizing:border-box;width:100%;padding:11px;border:1px solid #666;background:#181b1e;color:#fff}button{margin-top:14px;padding:10px 16px;cursor:pointer}</style></head><body><main class="brshare"><h1>Geschütztes Album</h1><p>Für diese Freigabe ist ein Passwort erforderlich.</p>'.$message.$form.'</main></body></html>';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user