poke/html/priv.ejs
2025-10-03 00:20:23 +02:00

858 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
This Source Code Form is subject to the terms of the GNU General Public License:
Copyright (C) 2021-2025 Poke (https://codeberg.org/ashley/poke)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 3 of the License,
or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see https://www.gnu.org/licenses/.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Poke — Privacy Policy</title>
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
<meta content="website" property="og:type">
<meta content="PokeTube - Legal thingy to put you into sleep" property="og:title">
<meta content="This is the PokeTube Privacy Policy meta description. Wow, helpful meta description Poke. Thanks!" property="twitter:description">
<meta property="og:image" content="/static/poke.webp">
<meta content="summary_large_image" name="twitter:card">
<link href="/css/yt-ukraine.svg?v=7" rel="icon">
<style>
/* ===== Base ===== */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
font-family: "poketube flex", sans-serif;
line-height: 1.6;
color: #eaeaea;
background:
radial-gradient(1200px 600px at 0% 0%, #0ea5e9 0%, #0ea5e900 60%),
radial-gradient(1000px 700px at 100% 0%, #8b5cf6 0%, #8b5cf600 65%),
radial-gradient(1000px 700px at 0% 100%, #14b8a6 0%, #14b8a600 65%),
#0b0b0b;
}
a { color: #7dd3fc; text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid #54c8ff; outline-offset: 2px; }
img { max-width: 100%; height: auto; }
code, pre, kbd, samp {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
font-size: 0.95em;
}
@font-face {
src: url("https://p.poketube.fun/https://cdn.glitch.global/43b6691a-c8db-41d4-921c-8cf6aa0d9108/robotoflex.ttf?v=16683434286881");
font-family: "PokeTube Flex";
font-style: normal;
font-stretch: 1% 800%;
font-display: swap;
}
/* ===== Document Layout ===== */
.shell {
max-width: 1200px;
margin: 0 auto;
padding: 24px;
}
header.site {
position: sticky;
top: 0;
z-index: 10;
backdrop-filter: saturate(140%) blur(10px);
background: color-mix(in oklab, #0b0b0b 80%, transparent);
border-bottom: 1px solid #222;
width: 100%;
}
.site-row {
display: flex; align-items: center; justify-content: space-between;
gap: 16px;
padding: 12px clamp(12px, 4vw, 24px);
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.brand {
display: inline-flex; align-items: center; gap: 12px;
text-decoration: none; color: #fff; font-weight: 800; letter-spacing: .2px;
min-width: 0;
}
.brand img { width: 8.5em; transform: scale(1.2); height: auto; }
/* Two-column doc: sticky sidebar + paper article */
.doc {
display: grid;
grid-template-columns: 280px 1fr;
gap: 20px;
margin-top: 22px;
}
nav.toc {
position: sticky; top: 76px;
align-self: start;
background: #0f0f10;
border: 1px solid #1f1f22;
border-radius: 16px;
padding: 14px;
max-height: calc(100vh - 96px);
overflow: auto;
}
nav.toc h2 {
margin: 0 0 10px 0; font-size: 1rem; letter-spacing: .2px; color: #e8f6ff;
}
.toc ul { list-style: none; padding: 0; margin: 0; }
.toc li { margin: 6px 0; }
.toc a { color: #cfe8ff; font-size: .95rem; }
article.paper {
background: #0f0f10;
border: 1px solid #1f1f22;
border-radius: 18px;
padding: clamp(18px, 2.6vw, 28px);
box-shadow:
0 0 0 1px rgba(255,255,255,0.02) inset,
0 20px 60px rgba(0,0,0,0.35);
}
/* Article typographic styling */
.doc-title { margin: 0 0 6px 0; font-size: clamp(1.6rem, 3vw, 2.2rem); letter-spacing:.2px; font-stretch: extra-expanded;}
.doc-lede { margin: 6px 0 16px 0; color: #cfcfcf; }
.meta-row {
display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
margin: 10px 0 18px 0;
}
.meta {
background: #0c1114; border: 1px solid #132029; color: #d2ebff;
border-radius: 12px; padding: 8px 10px; font-size: .93rem;
}
.callout {
background: #0c1114; border: 1px solid #132029; color: #d2ebff;
padding: 12px 14px; border-radius: 14px; margin: 10px 0 18px 0;
}
h2.section {
margin: 22px 0 8px 0;
font-size: clamp(1.24rem, 2.4vw, 1.6rem);
border-bottom: 1px solid #1f1f22;
padding-bottom: 6px;
font-stretch: extra-expanded;
}
p { margin: 10px 0; color: #e7e7e7; }
ul { margin: 10px 0 10px 22px; }
.grid-2 {
display: grid; gap: 12px; grid-template-columns: 1fr 1fr;
}
/* --- Mobile enhancements (desktop unchanged) --- */
@media (max-width: 900px) {
html { font-size: 17px; }
.brand img { width: 7.2em; transform: none; }
.doc { grid-template-columns: 1fr; }
nav.toc { display: none; }
.mobile-toc { display: block; }
article.paper { padding: 20px; }
.doc-title { font-size: 1.6rem; }
.grid-2 { grid-template-columns: 1fr; }
.meta { font-size: .95rem; }
.shell { padding: 18px; }
}
/* Mobile TOC block (hidden on desktop) */
.mobile-toc {
display: none;
margin: 10px 0 16px 0;
background: #0f0f10;
border: 1px solid #1f1f22;
border-radius: 14px;
overflow: hidden;
}
.mobile-toc summary {
cursor: pointer;
padding: 12px 14px;
font-weight: 700;
color: #e6f7ff;
list-style: none;
display: flex; align-items: center; gap: 10px;
}
.mobile-toc summary::before {
content: "▸"; color: #8bd2ff; transition: transform .15s ease;
}
.mobile-toc[open] summary::before { transform: rotate(90deg); }
.mobile-toc .toc-links { padding: 8px 14px 14px; }
.mobile-toc .toc-links a { display: block; padding: 8px 6px; color: #cfe8ff; }
/* Floating search (works on desktop & mobile without altering layout) */
.search-fab {
position: fixed;
right: 20px; bottom: 24px;
z-index: 60;
}
.search-fab button {
appearance: none; border: 0; cursor: pointer;
border-radius: 999px;
padding: 10px 12px;
background: linear-gradient(135deg, #0ea5e9, #8b5cf6);
color: #0b0b0b; font-weight: 800;
box-shadow: 0 10px 30px rgba(0,0,0,.35);
}
.search-panel {
position: fixed;
right: 20px; bottom: 72px;
background: #0f0f10;
border: 1px solid #1f1f22;
border-radius: 14px;
padding: 10px;
width: min(520px, calc(100vw - 36px));
box-shadow: 0 12px 36px rgba(0,0,0,.45);
display: none;
}
.search-panel.active { display: block; }
.search-row {
display: flex; gap: 8px;
}
.search-row input[type="search"] {
flex: 1;
border-radius: 10px;
border: 1px solid #232327;
background: #0c0c0d;
color: #eaeaea;
padding: 10px 12px;
}
.search-row button {
appearance: none; border: 0; cursor: pointer;
padding: 10px 14px; border-radius: 10px;
background: #111; color: #ddd; border: 1px solid #222;
}
.search-row button:hover { background: #161616; border-color: #2a2a2a; }
.search-hint { margin-top: 6px; color: #a9a9a9; font-size: .925rem; }
@supports (padding: max(0px)) {
.search-fab { right: max(20px, env(safe-area-inset-right)); bottom: max(24px, env(safe-area-inset-bottom)); }
.search-panel { right: max(20px, env(safe-area-inset-right)); bottom: max(72px, calc(env(safe-area-inset-bottom) + 48px)); }
}
/* Footer */
footer.site {
color: #bdbdbd; text-align: center; margin: 28px auto 50px;
}
.small { font-size: .925rem; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace; }
/* Print */
@media print {
header.site, nav.toc, .mobile-toc, .search-fab, .search-panel, noscript { display: none !important; }
body { background: #fff; color: #000; }
article.paper { background: #fff; border-color: #999; box-shadow: none; }
a { color: #0645ad; }
}
/* ===== Update Box (What's New) ===== */
.update-box {
position: relative;
margin: 14px 0 22px 0;
padding: 14px 14px 14px 48px;
border-radius: 14px;
background:
radial-gradient(900px 400px at 10% 0%, #0b1220 0%, rgba(11,18,32,0) 70%),
linear-gradient(180deg, #0b1117, #0a0f14);
border: 1px solid #152234;
box-shadow:
0 0 0 1px rgba(125, 211, 252, 0.06) inset,
0 14px 40px rgba(0,0,0,.35);
}
.update-box::before {
content: "★";
position: absolute;
left: 14px; top: 12px;
font-size: 1.1rem;
color: #7dd3fc;
filter: drop-shadow(0 0 6px rgba(125,211,252,.25));
}
.update-box h3 {
margin: 0 0 8px 0;
font-size: 1.05rem;
color: #e9f7ff;
letter-spacing: .2px;
}
.update-box .when {
display: inline-block;
margin-left: 8px;
padding: 2px 8px;
border-radius: 999px;
font-size: .85rem;
color: #cfe8ff;
background: #0c1b27;
border: 1px solid #193347;
}
.update-box ul {
margin: 8px 0 0 20px;
}
.update-actions {
margin-top: 10px;
display: flex; gap: 8px; flex-wrap: wrap;
}
.update-actions a,
.update-actions button {
appearance: none;
border: 1px solid #234a61;
background: #0d1d28;
color: #cfe8ff;
padding: 6px 10px;
border-radius: 10px;
cursor: pointer;
font-size: .92rem;
}
.update-actions a:hover,
.update-actions button:hover {
background: #0f2432;
border-color: #2d5d7a;
}
.update-box[hidden] { display: none !important; }
</style>
</head>
<body>
<!-- Site Header -->
<header class="site" role="banner" aria-label="Site header">
<div class="site-row">
<a class="brand" href="/" aria-label="Poke home">
<img src="/css/logo-poke.svg?v=5" alt="Poke logo">
</a>
<noscript>
<form action="/search" method="GET" style="margin-left:auto">
<input type="search" name="query" placeholder="Search…" aria-label="Search Poke"
style="border-radius:10px;border:1px solid #232327;background:#0c0c0d;color:#eaeaea;padding:8px 10px;">
<button type="submit" style="margin-left:6px;border:1px solid #222;background:#111;color:#ddd;border-radius:10px;padding:8px 12px;">
Go
</button>
</form>
</noscript>
</div>
</header>
<!-- Document Body -->
<div class="shell doc" id="top">
<!-- Sidebar TOC (desktop only) -->
<nav class="toc" aria-label="Table of contents">
<h2>Contents</h2>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#summary">TL;DR</a></li>
<li><a href="#ownership">Ownership</a></li>
<li><a href="#initiative-privacy">Initiative Site Privacy</a></li>
<li><a href="#what-we-collect">What We Do/Dont Collect</a></li>
<li><a href="#cookies">Cookies &amp; Storage</a></li>
<li><a href="#openstreetmap">OpenStreetMap</a></li>
<li><a href="#weather">Weather Pages &amp; Services</a></li>
<li><a href="#translate">Translate Page (SimplyTranslate)</a></li>
<li><a href="#third-parties">Third-Party Requests &amp; Proxy</a></li>
<li><a href="#api-logs">API Logs Policy</a></li>
<li><a href="#nginx-analytics">Server Admin Tool: poke-nginx-analytics</a></li>
<li><a href="#legal-bases">Legal Bases (GDPR)</a></li>
<li><a href="#your-rights">Your Rights</a></li>
<li><a href="#retention">Data Retention</a></li>
<li><a href="#javascript">JavaScript &amp; No-JS</a></li>
<li><a href="#self-host">Self-Hosting</a></li>
<li><a href="#changes">Changes to this Policy</a></li>
<li><a href="#history">Document History</a></li>
<li><a href="#warranty">Warranty Disclaimer</a></li>
<li><a href="#contact">Contact</a></li>
<li><a href="#license">Policy License</a></li>
</ul>
</nav>
<!-- Paper Article -->
<article class="paper" role="article" aria-label="Poke Privacy Policy">
<details class="mobile-toc">
<summary>Contents</summary>
<div class="toc-links">
<a href="#overview">Overview</a>
<a href="#summary">TL;DR</a>
<a href="#ownership">Ownership</a>
<a href="#initiative-privacy">Initiative Site Privacy</a>
<a href="#what-we-collect">What We Do/Dont Collect</a>
<a href="#cookies">Cookies &amp; Storage</a>
<a href="#openstreetmap">OpenStreetMap</a>
<a href="#weather">Weather Pages &amp; Services</a>
<a href="#translate">Translate Page (SimplyTranslate)</a>
<a href="#third-parties">Third-Party Requests &amp; Proxy</a>
<a href="#api-logs">API Logs Policy</a>
<a href="#nginx-analytics">Server Admin Tool: poke-nginx-analytics</a>
<a href="#legal-bases">Legal Bases (GDPR)</a>
<a href="#your-rights">Your Rights</a>
<a href="#retention">Data Retention</a>
<a href="#javascript">JavaScript &amp; No-JS</a>
<a href="#self-host">Self-Hosting</a>
<a href="#changes">Changes to this Policy</a>
<a href="#history">Document History</a>
<a href="#warranty">Warranty Disclaimer</a>
<a href="#contact">Contact</a>
<a href="#license">Policy License</a>
</div>
</details>
<header>
<h1 class="doc-title">Poke Privacy Policy</h1>
<p class="doc-lede">
<strong>We dont collect personal data about you.</strong> No telemetry, no trackers, no profiling. The only “analytics” we ship is an optional <code>poke-nginx-analytics</code> script for server admins — and it runs <em>locally</em>, never phones home, and just reads your own logs. Because Poke is <strong>free software</strong>, you can check the source, self-host, and audit everything yourself.
</p>
<div class="meta-row" aria-label="Document metadata">
<span class="meta">Instance: <span class="mono">poketube.fun</span></span>
<span class="meta">Version date: <time datetime="2025-10-03">October 3, 2025</time></span>
</div>
</header>
<!-- What's New / Privacy Update -->
<section id="whats-new" class="update-box" aria-labelledby="whats-new-heading" role="region">
<h3 id="whats-new-heading">
Whats New — Policy Updates
<span class="when">October 3, 2025</span>
</h3>
<p style="margin-top:6px">
Added a section for our server-admin script <strong>poke-nginx-analytics</strong>. TL;DR: its local-only, read-only, and configurable for privacy (IP masking, bot filtering). Source code is linked.
</p>
<ul>
<li><a href="#nginx-analytics">Read the new “Server Admin Tool” section</a></li>
<li>Script source: <a href="https://codeberg.org/ashley/poke/src/branch/main/backend-services/scripts/poke-nginx-analytics.sh" target="_blank" rel="noopener">backend-services/scripts/poke-nginx-analytics.sh</a></li>
</ul>
</section>
<!-- Overview / Preamble -->
<section id="overview" aria-labelledby="preamble-heading">
<h2 id="preamble-heading" class="section">Preamble</h2>
<p>
Welcome to Pokes Privacy Policy. We dont collect personal data about you, we dont run telemetry, and we dont track you around the web.
The only “analytics” involved is an optional <code>poke-nginx-analytics</code> script for server operators, which runs locally on their own machines,
never phones home, and only summarizes their own access logs.
Poke is <strong>free software</strong> you can read, remix, and run yourself.
</p>
<p class="callout">Not legal advice lol</p>
</section>
<!-- TL;DR -->
<section id="summary" aria-labelledby="summary-heading">
<h2 id="summary-heading" class="section">TL;DR</h2>
<div class="grid-2">
<div>
<ul>
<li><strong>No personal data collected.</strong> nothing about you is stored.</li>
<li><strong>No telemetry.</strong> We dont phone home.</li>
<li><strong>No third-party trackers.</strong> Yippe!!</li>
<li><strong>YouTube cant see what you watch here.</strong> Its all done on the backend.</li>
</ul>
</div>
<div>
<ul>
<li><strong>Poke Account:</strong> no email required, no personal info needed.</li>
<li><strong>Poke Maps:</strong> uses OpenStreetMap data; tile servers have their own privacy rules.</li>
<li><strong>Optional server admin tool:</strong> <code>poke-nginx-analytics</code> is local-only, read-only, and never sends data anywhere.</li>
<li><strong>No required cookies.</strong> Preferences (like theme or layout) may live in local storage on your device.</li>
</ul>
</div>
</div>
</section>
<!-- Ownership -->
<section id="ownership" aria-labelledby="ownership-heading">
<h2 id="ownership-heading" class="section">Ownership</h2>
<p>
The Poke service and this default instance (<span class="mono">poketube.fun</span>) are owned and operated by the <strong>Poke Project</strong>.
Learn more at <a href="https://initiative.poketube.fun/" rel="noopener">initiative.poketube.fun</a>.
</p>
</section>
<!-- Initiative site privacy -->
<section id="initiative-privacy" aria-labelledby="initiative-privacy-heading">
<h2 id="initiative-privacy-heading" class="section">Initiative Site Privacy</h2>
<p>
The informational website at <a href="https://initiative.poketube.fun/" rel="noopener">initiative.poketube.fun</a> does not collect personal information.
For hosting-related processing, the <strong>Codeberg</strong> privacy policy applies:
<a href="https://codeberg.org/Codeberg/org/src/branch/main/PrivacyPolicy.md" target="_blank" rel="noopener">codeberg.org/Codeberg/org/src/branch/main/PrivacyPolicy.md</a>.
</p>
</section>
<!-- What we collect -->
<section id="what-we-collect" aria-labelledby="collect-heading">
<h2 id="collect-heading" class="section">What We Do/Dont Collect</h2>
<details class="block" open>
<summary>We collect <em>nothing</em> about you</summary>
<p>
We dont store IP addresses, user-agent fingerprints, unique identifiers, emails, names—none of it. Theres no telemetry or “anonymous crash reports.”
</p>
</details>
<details class="block">
<summary>What exists briefly so the internet works</summary>
<p>
Your browser and our server exchange data to deliver pages (thats how HTTP works). That info is handled <em>transiently</em> and not logged in a way that identifies you on our primary instance.
</p>
</details>
<details class="block">
<summary>Poke Account</summary>
<p>
If you make a Poke account, we dont require an email or personal details.
</p>
</details>
</section>
<!-- Cookies & storage -->
<section id="cookies" aria-labelledby="cookies-heading">
<h2 id="cookies-heading" class="section">Cookies &amp; Local Storage</h2>
<ul>
<li><strong>No cookies :D!</strong></li>
<li><strong>Local storage only for preferences</strong> (e.g., theme, layout). This stays on your device.</li>
</ul>
<p class="small">
To remove data stored in your browser, you can use your browsers cookie/site-data controls: <br>
<a href="https://support.google.com/chrome/answer/2392709" rel="noopener" target="_blank">· Chrome</a> <br>
<a href="https://support.mozilla.org/kb/clear-cookies-and-site-data-firefox" rel="noopener" target="_blank">· Firefox</a> <br>
<a href="https://support.apple.com/HT201265" rel="noopener" target="_blank">· Safari (iOS)</a> <br>
<a href="https://support.apple.com/guide/safari/manage-cookies-and-website-data-sfri11471/mac" rel="noopener" target="_blank"> · Safari (macOS)</a> <br>
<a href="https://support.microsoft.com/en-us/windows/manage-cookies-in-microsoft-edge-view-allow-block-delete-and-use-168dab11-0753-043d-7c16-ede5947fc64d" rel="noopener" target="_blank">· Edge</a> <br>
<a href="https://support.brave.app/hc/en-us/articles/360048833872-How-Do-I-Clear-Cookies-And-Site-Data-In-Brave" rel="noopener" target="_blank">· Brave</a>
</p>
</section>
<!-- OpenStreetMap -->
<section id="openstreetmap" aria-labelledby="osm-heading">
<h2 id="osm-heading" class="section">OpenStreetMap</h2>
<p>
Poke Maps uses <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener">OpenStreetMap</a> data. That means when you explore maps at <a href="/map">/map</a>, we embed OSM via an <strong>iframe</strong> directly into the Poke site. The tiles and geographic info are delivered from OSM contributors servers.
While Poke itself doesnt collect any of your data, OpenStreetMaps tile servers have their own
<a href="https://wiki.osmfoundation.org/wiki/Privacy_Policy" target="_blank" rel="noopener">privacy policy</a>.
</p>
</section>
<!-- Weather -->
<section id="weather" aria-labelledby="weather-heading">
<h2 id="weather-heading" class="section">Weather Pages &amp; Services</h2>
<p>
Pokes weather pages use third-party, privacy-respecting services to resolve places and fetch forecasts:
</p>
<ul>
<li>
<strong>Geocoding / place lookup:</strong>
<a href="https://nominatim.openstreetmap.org/" rel="noopener" target="_blank">nominatim.openstreetmap.org</a>.
Requests are proxied through Pokes backend.
</li>
<li>
<strong>Forecast data:</strong>
<a href="https://open-meteo.com/" rel="noopener" target="_blank">open-meteo.com</a>.
Forecast queries are proxied through Pokes backend so your browser never connects to Open-Meteo directly.
</li>
</ul>
<p class="callout">
Poke does not add trackers to these requests. However, when third-party services are contacted (directly or via proxy),
their respective privacy policies apply to those specific requests.
</p>
</section>
<!-- Translate -->
<section id="translate" aria-labelledby="translate-heading">
<h2 id="translate-heading" class="section">Translate Page (SimplyTranslate)</h2>
<p>
Our translate page does <strong>not</strong> send your data directly to Google or SimplyTranslate.org from your browser.
Instead, all requests are proxied through our own backend servers.
When you use the page, only the necessary parameters are passed securely on the server side:
<code>from</code> (source language), <code>to</code> (target language), and <code>text</code> (the content you entered).
Your browser never connects to SimplyTranslate.org directly.
</p>
</section>
<!-- Third-party requests -->
<section id="third-parties" aria-labelledby="third-parties-heading">
<h2 id="third-parties-heading" class="section">Third-Party Requests &amp; Proxy</h2>
<p>
Where external services are necessary (maps, weather, translation), Poke uses server-side proxying to avoid exposing your browser directly.
We dont inject trackers into proxied calls. External services have their own privacy terms that apply to those specific requests.
</p>
</section>
<!-- API Logs Policy -->
<section id="api-logs" aria-labelledby="api-logs-heading">
<h2 id="api-logs-heading" class="section">API Logs Policy</h2>
<p>
When you request any resource from the Poke API (for example: thumbnails, API endpoint) information about the request may be logged.
</p>
<p>Information about a request is limited to:</p>
<ul>
<li>the time the request was made</li>
<li>the status code of the response</li>
<li>the method of the request</li>
<li>the requested URL</li>
<li>how long it took to complete the request.</li>
</ul>
<p>
<strong>No identifying information is logged</strong>, such as the visitors cookie, user-agent, or IP address. Here are a couple lines to serve as an example:
</p>
<pre class="small" style="white-space:pre-wrap;margin:8px 0;">
2019-01-19 16:37:47 +00:00 200 GET /api/v1/comments/xrlETJYzH-c?format=html&amp;hl=en-US 1345.88ms
2019-01-19 16:37:53 +00:00 200 GET /vi/r5P-f5arPXE/maxres.jpg 1085.41ms
2019-01-19 16:37:54 +00:00 200 GET /watch 7.04ms
</pre>
<p>
This website does not store the visitors user-agent and does not use fingerprinting, advertisements, or tracking of any form.
</p>
</section>
<section id="nginx-analytics" aria-labelledby="nginx-analytics-heading">
<h2 id="nginx-analytics-heading" class="section">Server Admin Tool: <span class="mono">poke-nginx-analytics</span></h2>
<p>
We ship an optional, admin-side shell script to help operators understand IPv4/IPv6 traffic and status codes from their own servers Nginx access logs.
Its free software and lives here:
<a href="https://codeberg.org/ashley/poke/src/branch/main/backend-services/scripts/poke-nginx-analytics.sh" target="_blank" rel="noopener">
backend-services/scripts/poke-nginx-analytics.sh
</a>.
</p>
<div class="callout">
<strong>Privacy :</strong> the script is <em>local-only</em> and <em>read-only</em>. It makes no network requests, writes no files by default, and sends nothing anywhere. It just reads the log files you point it at and prints aggregate counts to your terminal.
</div>
<h3 class="section" style="margin-top:18px;font-size:1.05rem">What it reads from your logs</h3>
<p>
The script parses standard Nginx <em>access</em> logs (including rotated <code>.1</code> and compressed <code>.gz</code>) using the fields already present in your log format:
</p>
<ul>
<li><strong>Client IP</strong> (first field) — used to tell IPv4 vs IPv6 and to compute counts/uniques; display can be masked via <code>--anonip</code>.</li>
<li><strong>Timestamp</strong> (e.g., <code>[02/Oct/2025:14:03:12 +0000]</code>) — used for <code>--date</code>, <code>--since</code>, <code>--until</code>, and hourly breakdowns.</li>
<li><strong>Status code</strong> (e.g., <code>200</code>, <code>404</code>, <code>502</code>) — used for success/fail tallies and “top fail reasons.”</li>
<li><strong>User-Agent</strong> (last quoted field) — only to optionally filter bots when <code>--ignore-bots</code> (or a custom <code>--bot-regex</code>) is used.</li>
</ul>
<p class="small">It does <strong>not</strong> collect any new data, fingerprint users, or correlate logs with other sources.</p>
<h3 class="section" style="margin-top:18px;font-size:1.05rem">How it decides “success” vs “fail”</h3>
<ul>
<li>By default, “success” is the set <code>200,301,302,304</code>.</li>
<li>You can override with <code>--success-codes</code> or a regex via <code>--success-regex</code> (e.g., <code>^(2..|3..)$</code>). If both are provided, regex wins.</li>
<li>“Fail” is simply “not success.”</li>
</ul>
<h3 class="section" style="margin-top:18px;font-size:1.05rem">What it outputs (to your terminal)</h3>
<ul>
<li><strong>Counts and percentages</strong> of IPv4 vs IPv6 for today (or a specified date/time window).</li>
<li><strong>Success-only</strong> and <strong>fail-only</strong> views; an overall <strong>success rate</strong> with totals.</li>
<li><strong>Hourly breakdown</strong> (v4/v6/total) and <strong>status-code breakdown</strong> for v4 or v6.</li>
<li><strong>Unique IP counts</strong> for v4 and v6; if <code>--anonip</code> is set, displayed IPs are masked (IPv4 → /24; IPv6 → /64).</li>
<li><strong>Top IPs</strong> (v4 or v6) with optional masking and bot filtering.</li>
<li><strong>Top 5 failure reasons</strong> (status codes aggregated across v4+v6). Some common meanings:
<ul>
<li><code>404 Not Found</code> — missing path or bad link.</li>
<li><code>400 Bad Request</code> — malformed client request.</li>
<li><code>401/403 Unauthorized/Forbidden</code> — blocked/needs auth.</li>
<li><code>429 Too Many Requests</code> — rate limiting kicked in.</li>
<li><code>500/502/503/504</code> — upstream/app issues or timeouts.</li>
</ul>
</li>
</ul>
<h3 class="section" style="margin-top:18px;font-size:1.05rem">How it works (under the hood)</h3>
<ul>
<li>Expands your <code>--file</code> glob (default <code>/var/log/nginx/access.log*</code>), reads each file with <code>cat</code>/<code>zcat</code>.</li>
<li>Uses <code>awk</code> to:
<ul>
<li>Detect <strong>IPv4</strong> vs <strong>IPv6</strong> by regex.</li>
<li>Match the requested <strong>date</strong> and optional <strong>time window</strong> (<code>--since</code>/<code>--until</code>).</li>
<li>Classify <strong>success/fail</strong> via your codes or regex.</li>
<li>Optionally <strong>filter bots</strong> by User-Agent (<code>--ignore-bots</code> / <code>--bot-regex</code>).</li>
<li>Optionally <strong>anonymize IPs</strong> for display (<code>--anonip</code>).</li>
<li>Aggregate counts and print sorted summaries; shows “top fails” by frequency.</li>
</ul>
</li>
<li>Handles rotated and <code>.gz</code> logs automatically.</li>
<li>Does not modify logs or your Nginx config.</li>
</ul>
<h3 class="section" style="margin-top:18px;font-size:1.05rem">What it does <em>not</em> do</h3>
<ul>
<li><strong>No storage by default.</strong> Output is ephemeral in your terminal unless <em>you</em> redirect it (e.g., <code>&gt; report.txt</code>).</li>
<li><strong>No identification or profiling.</strong> It does not attempt to identify people; it just counts whats already in your logs.</li>
</ul>
</section>
<!-- Legal bases -->
<section id="legal-bases" aria-labelledby="gdpr-heading">
<h2 id="gdpr-heading" class="section">Legal Bases for Processing (GDPR)</h2>
<ul>
<li><strong>Legitimate interests:</strong> Running Poke smoothly while collecting exactly zero personal data.</li>
<li><strong>Consent:</strong> If we ever invent an optional feature that needs info, well ask. But right now? Theres nothing to consent to.</li>
<li><strong>Legal obligation:</strong> Even if someone waves a fancy piece of paper at us, we literally have nothing personal to hand over. Empty pockets.</li>
</ul>
</section>
<!-- Your rights -->
<section id="your-rights" aria-labelledby="rights-heading">
<h2 id="rights-heading" class="section">Your Privacy Rights</h2>
<p>
Since Poke doesnt collect or store personal data, theres basically nothing for us to give, sell, or lose about you.
You dont have to worry about “export my data” or “delete my profile” requests because we dont have anything on you in the first place.
</p>
<p>
Poke Accounts dont require an email, name, or any other identifying info — and theres no way to add that kind of data even if you wanted to.
</p>
</section>
<!-- Data Retention -->
<section id="retention" aria-labelledby="retention-heading">
<h2 id="retention-heading" class="section">Data Retention</h2>
<ul>
<li><strong>Server logs:</strong> No personal identifiers on our main instance.</li>
<li><strong>Telemetry/analytics:</strong> Not enabled here.</li>
</ul>
</section>
<!-- JavaScript & No-JS -->
<section id="javascript" aria-labelledby="javascript-heading">
<h2 id="javascript-heading" class="section">JavaScript &amp; No-JS</h2>
<p>
JavaScript is <strong>optional</strong> on Pokes websites. Core features—including search—work without JavaScript.
</p>
</section>
<!-- Self-host -->
<section id="self-host" aria-labelledby="selfhost-heading">
<h2 id="selfhost-heading" class="section">Self-Hosting</h2>
<p>
Poke is free software under the <strong>GNU GPL v3.0 or later</strong>. you can self-host it yourself! <a href="https://codeberg.org/ashley/poke/#hosting-poke"> see here </a>
</p>
</section>
<!-- Changes -->
<section id="changes" aria-labelledby="changes-heading">
<h2 id="changes-heading" class="section">Changes to this Policy</h2>
<p>
If we ever change how privacy works here, well update the date at the top and announce major changes. Spoiler: changes would not include adding two bananas. this isnt minions LOL :3
</p>
</section>
<!-- Document History -->
<section id="history" aria-labelledby="history-heading">
<h2 id="history-heading" class="section">Document History</h2>
<p>
You can view the full edit history for this policy at:
<a href="https://codeberg.org/ashley/poke/commits/branch/main/html/priv.ejs" target="_blank" rel="noopener">codeberg.org</a>.
</p>
</section>
<!-- Warranty Disclaimer -->
<section id="warranty" aria-labelledby="warranty-heading">
<h2 id="warranty-heading" class="section">Warranty Disclaimer</h2>
<pre class="small" style="white-space:pre-wrap;margin:8px 0;">
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER,
OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
(E.G., LOSS OF DATA, DATA BEING RENDERED INACCURATE, OR FAILURES OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
</pre>
</section>
<!-- Contact -->
<section id="contact" aria-labelledby="contact-heading">
<h2 id="contact-heading" class="section">Contact</h2>
<p>
Questions or concerns? Open an issue on our project tracker :D
</p>
<ul>
<li>Project: <span class="mono">codeberg.org/Ashley/poke</span></li>
<li>Initiative: <a href="https://initiative.poketube.fun/" rel="noopener">initiative.poketube.fun</a></li>
</ul>
</section>
<!-- License -->
<section id="license" aria-labelledby="license-heading">
<h2 id="license-heading" class="section">Policy License</h2>
<p class="small">
© 20212025 Poke (Poke Project). This policy is licensed under the
<strong>Creative Commons AttributionShareAlike 4.0 International</strong> (CC BY-SA 4.0).
</p>
</section>
<footer class="site small" aria-label="Document footer">
<p><a href="#top">Return to Top</a></p>
</footer>
</article>
</div>
<div class="search-fab" aria-live="polite">
<button type="button" id="openSearch" aria-expanded="false" aria-controls="policySearchPanel" title="Search Poke">
🔎 Search
</button>
</div>
<div id="policySearchPanel" class="search-panel" role="dialog" aria-modal="false" aria-label="Search">
<form class="search-row" id="policySearchForm" action="/search" method="GET">
<input type="search" name="query" id="policySearchInput" placeholder="Search…"
aria-label="Search Poke" autocomplete="off" />
<button type="submit">Go</button>
<button type="button" id="closeSearch">Close</button>
</form>
</div>
<script>
(function () {
const openBtn = document.getElementById('openSearch');
const panel = document.getElementById('policySearchPanel');
const input = document.getElementById('policySearchInput');
const closeBtn = document.getElementById('closeSearch');
const form = document.getElementById('policySearchForm');
function openPanel() {
panel.classList.add('active');
openBtn.setAttribute('aria-expanded', 'true');
setTimeout(() => input && input.focus(), 0);
}
function closePanel() {
panel.classList.remove('active');
openBtn.setAttribute('aria-expanded', 'false');
openBtn.focus();
}
openBtn.addEventListener('click', () => {
if (panel.classList.contains('active')) closePanel(); else openPanel();
});
closeBtn.addEventListener('click', closePanel);
window.addEventListener('keydown', (e) => {
if (e.key === '/' && !e.metaKey && !e.ctrlKey && !e.altKey) {
e.preventDefault();
if (!panel.classList.contains('active')) openPanel();
input && input.focus();
} else if (e.key === 'Escape' && panel.classList.contains('active')) {
closePanel();
}
});
form.addEventListener('submit', (e) => {
const q = input.value.trim();
if (!q) { e.preventDefault(); return; }
});
// Dismissible privacy update (persists in localStorage)
const updateBox = document.getElementById('whats-new');
const dismissBtn = document.getElementById('dismissUpdate');
const STORAGE_KEY = 'poke_privacy_update_2025_10_03_dismissed';
try {
if (localStorage.getItem(STORAGE_KEY) === '1') {
updateBox && (updateBox.hidden = true);
}
} catch {}
if (dismissBtn && updateBox) {
dismissBtn.addEventListener('click', () => {
updateBox.hidden = true;
try { localStorage.setItem(STORAGE_KEY, '1'); } catch {}
});
}
})();
</script>
</body>
</html>