api/privacy.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../includes/core.php';
loadTranslations();
$site = trim((string)($_GET['site'] ?? ''));
if ($site !== '' && !isset(brivacia_sites()[$site])) {
$site = '';
}
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$baseUrl = $scheme . '://' . ($_SERVER['HTTP_HOST'] ?? '') . ($_SERVER['SCRIPT_NAME'] ?? '');
if (($_GET['frame'] ?? '') !== '1') {
header('Content-Type: application/javascript; charset=utf-8');
$src = $baseUrl . '?frame=1&site=' . rawurlencode($site);
$label = t('privacy.button');
$tooltip = t('privacy.title', [
'instance' => brivacia_setting('dashboard.instance_name', 'Brivacia'),
]);
?>
(() => {
const src = <?= json_encode($src, JSON_UNESCAPED_SLASHES) ?>;
const label = <?= json_encode($label, JSON_UNESCAPED_UNICODE) ?>;
const tooltip = <?= json_encode($tooltip, JSON_UNESCAPED_UNICODE) ?>;
const style = document.createElement('style');
style.textContent = `
.brivacia-privacy-button {
align-items: center;
background: transparent;
border: 0;
color: inherit;
cursor: pointer;
display: inline-flex;
font: inherit;
gap: .3em;
padding: 0;
}
.brivacia-privacy-button svg {
flex: 0 0 auto;
height: 1em;
width: 1em;
}
.brivacia-privacy-overlay {
background: rgba(0,0,0,.65);
display: none;
inset: 0;
overflow: hidden;
position: fixed;
z-index: 2147483647;
}
.brivacia-privacy-overlay.open {
display: block;
}
.brivacia-privacy-frame {
background: transparent;
border: 0;
height: 100vh;
inset: 0;
position: fixed;
width: 100vw;
}`;
document.head.appendChild(style);
const button = document.createElement('button');
button.className = 'brivacia-privacy-button';
button.type = 'button';
button.title = tooltip;
button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-shield-question-mark-icon lucide-shield-question-mark"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="M9.1 9a3 3 0 0 1 5.82 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg> ${label}`;
const overlay = document.createElement('div');
overlay.className = 'brivacia-privacy-overlay';
overlay.innerHTML = `<iframe class="brivacia-privacy-frame" src="${src}" loading="lazy"></iframe>`;
const openPrivacy = () => {
overlay.classList.add('open');
document.documentElement.style.overflow = 'hidden';
document.body.style.overflow = 'hidden';
};
const closePrivacy = () => {
overlay.classList.remove('open');
document.documentElement.style.overflow = '';
document.body.style.overflow = '';
};
button.addEventListener('click', openPrivacy);
window.addEventListener('message', event => {
if (event.data === 'brivacia:privacy:close') {
closePrivacy();
}
});
document.addEventListener('keydown', event => {
if (event.key === 'Escape') {
closePrivacy();
}
});
document.currentScript.after(button);
document.body.appendChild(overlay);
})();
<?php
exit;
}
$db = brivaciaDb();
function one(PDO $db, string $sql, array $params = []): array {
return fetchAll($db, $sql, $params)[0] ?? [];
}
require __DIR__ . '/../includes/dashboard/privacy.php';
header('Content-Type: text/html; charset=utf-8');
header('X-Frame-Options: ALLOWALL');
?>
<!doctype html>
<html lang="<?= h(currentLang()) ?>" dir="<?= h(currentDir()) ?>" data-theme="<?= h(!empty(brivacia_setting('dashboard.light_theme')) ? 'light' : 'dark') ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/assets/css/style.min.css">
<style>
html,
body {
background: transparent;
height: 100%;
margin: 0;
overflow: hidden;
}
body {
align-items: center;
box-sizing: border-box;
display: flex;
justify-content: center;
padding: 2vh 0;
}
.modal {
display: block;
margin: 0;
max-height: 90vh;
max-width: 90vw;
overflow: auto;
position: static;
}
.modal>div {
overflow: visible;
}
.privacy-powered {
align-items: center;
display: flex;
flex-direction: column;
font-size: 1rem;
gap: .3em;
justify-content: flex-end;
margin-left: auto;
margin-top: -.5em;
pointer-events: auto;
z-index: 10000;
}
.modal h2,
.privacy-powered a,
.privacy-powered span {
align-items: center;
display: flex;
gap: .4em;
}
.privacy-powered a {
overflow-wrap: normal;
text-decoration: none;
}
.privacy-powered img {
height: 1em;
width: 1em;
}
@media (min-width: 3000px) {
.privacy-powered {
font-size: var(--font-size-normal-4k);
}
}
</style>
</head>
<body>
<?php
ob_start();
require __DIR__ . '/../includes/modals/privacy_modal.php';
$html = ob_get_clean();
$html = str_replace('<dialog class="modal"', '<dialog class="modal" open', $html);
$powered = '
<div class="privacy-powered">
<span>' . h(t('footer.powered')) . ' <a href="https://brivacia.breat.fr/" rel="noopener" target="_blank"><img src="/assets/images/logo.png" alt="" aria-hidden="true">Brivacia</a></span>
<span>' . h(t('footer.created')) . ' <a href="https://breat.fr/" rel="noopener" target="_blank"><img src="/assets/images/icons/breat.fr.png" alt="" aria-hidden="true">breat.fr</a></span>
</div>';
$html = preg_replace( '/<h2([^>]*)>(.*?)<\/h2>/s', '<h2$1><span>$2</span>' . $powered . '</h2>', $html, 1);
echo $html;
?>
<script>
const browserLanguage = document.querySelector('[data-browser-language]');
if (browserLanguage) {
browserLanguage.textContent = navigator.language || '';
}
const modal = document.querySelector('.modal');
document.addEventListener('click', event => {
if (modal && !modal.contains(event.target)) {
parent.postMessage('brivacia:privacy:close', '*');
}
});
document.addEventListener('keydown', event => {
if (event.key === 'Escape') {
parent.postMessage('brivacia:privacy:close', '*');
}
});
</script>
</body>
</html>