Let Firefox users dismiss the media tracking warning.

The choice is remembered for a year, and resetting preferences shows the warning again.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
4cuckandCursor committed 2026-10-12 23:21:52 +00:00
1 parent bd6db0a940
commit 12dba443f6
7 files changed
+90 -14

No files matched your search

+15
View File
@@ -1096,6 +1096,21 @@ input[type="text"], input[type="date"], input[type="number"], select {
}
.firefox-media-warning strong { display: block; margin-bottom: 4px; }
.firefox-media-warning p { margin: 0; }
.firefox-warning-ignore { display: none; }
.firefox-media-warning button {
min-height: 0;
margin-top: 8px;
padding: 2px 8px;
background: transparent;
color: var(--accent);
font-size: 12px;
font-weight: 650;
border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--line));
}
.firefox-media-warning button:hover {
background: var(--accent);
color: var(--icon_text);
}
.preferences .firefox-media-warning { width: auto; margin: 0 0 8px; }
.preferences-panel {
+7
View File
@@ -0,0 +1,7 @@
(function () {
if (!/(?:^|; )hideFirefoxWarning=on(?:;|$)/.test(document.cookie)) return;
var warning = document.querySelector(".firefox-media-warning");
if (warning) warning.remove();
var form = document.getElementById("ignore-firefox-warning");
if (form) form.remove();
})();
+16 -6
View File
@@ -3,8 +3,8 @@
use axum::{
Router,
extract::State,
http::HeaderMap,
response::{Html, IntoResponse, Redirect},
http::{HeaderMap, HeaderValue, header},
response::{Html, IntoResponse, Redirect, Response},
routing::get,
};
use axum_extra::extract::CookieJar;
@@ -78,12 +78,15 @@ async fn home(
State(state): State<AppState>,
jar: CookieJar,
headers: HeaderMap,
) -> impl IntoResponse {
) -> Response {
let prefs = Prefs::from_cookies(&jar, &state.config);
let firefox = headers
.get(axum::http::header::USER_AGENT)
.get(header::USER_AGENT)
.and_then(|value| value.to_str().ok())
.is_some_and(crate::views::preferences::is_firefox);
let warning_hidden = jar
.get("hideFirefoxWarning")
.is_some_and(|cookie| cookie.value() == "on");
let hub = html! {
section class="landing-hub" aria-label="Popular profiles" {
h2 { "Browse public profiles" }
@@ -104,7 +107,7 @@ async fn home(
}
}
};
let notice = (firefox && !prefs.proxy_media).then(|| {
let notice = (firefox && !prefs.proxy_media && !warning_hidden).then(|| {
crate::views::preferences::firefox_media_warning(false)
});
let content = search_view::render_search_page(notice, Some(hub));
@@ -121,7 +124,14 @@ async fn home(
.referer("/")
.head_extra(&head)
.render();
Html(markup.into_string())
let mut response = Html(markup.into_string()).into_response();
// The warning depends on the browser and a dismiss cookie, so a shared cache
// must not store one visitor's copy for everyone else.
response.headers_mut().insert(
header::CACHE_CONTROL,
HeaderValue::from_static("private, no-store"),
);
response
}
async fn about(State(state): State<AppState>, jar: CookieJar) -> impl IntoResponse {
+26 -4
View File
@@ -137,6 +137,7 @@ pub fn router() -> Router<AppState> {
.route("/resetprefs", post(reset_prefs))
.route("/enablemp4", post(enable_mp4))
.route("/enablehls", post(enable_hls))
.route("/ignorefirefoxwarning", post(ignore_firefox_warning))
}
#[derive(Debug, Deserialize)]
@@ -243,10 +244,14 @@ async fn settings(
) -> Result<Response> {
let prefs = Prefs::from_cookies(&jar, &state.config);
let themes = find_themes(&state.config.server.static_dir);
let firefox = headers
.get(axum::http::header::USER_AGENT)
.and_then(|value| value.to_str().ok())
.is_some_and(crate::views::preferences::is_firefox);
let warning_hidden = jar
.get("hideFirefoxWarning")
.is_some_and(|cookie| cookie.value() == "on");
let firefox = !warning_hidden
&& headers
.get(axum::http::header::USER_AGENT)
.and_then(|value| value.to_str().ok())
.is_some_and(crate::views::preferences::is_firefox);
let referer = local_redirect_target(query.referer.as_deref(), "/");
let prefs_code = encode_prefs(&prefs, &state.config);
@@ -302,6 +307,23 @@ async fn reset_prefs(jar: CookieJar, Form(form): Form<ResetPrefsForm>) -> Result
Ok((updated_jar, Redirect::to(&redirect_to)).into_response())
}
async fn ignore_firefox_warning(
State(state): State<AppState>,
jar: CookieJar,
Form(form): Form<ResetPrefsForm>,
) -> Result<Response> {
let cookie = make_cookie(
"hideFirefoxWarning",
"on",
Duration::days(365),
state.config.server.https,
false,
);
let updated_jar = jar.add(cookie);
let redirect_to = local_redirect_target(form.referer.as_deref(), "/");
Ok((updated_jar, Redirect::to(&redirect_to)).into_response())
}
async fn enable_mp4(jar: CookieJar, headers: HeaderMap) -> Result<Response> {
let cookie = Cookie::build(("mp4Playback".to_owned(), "on".to_owned()))
.path("/")
+1
View File
@@ -164,6 +164,7 @@ impl Prefs {
"mediaView",
"gallerySize",
"compactGallery",
"hideFirefoxWarning",
];
/// Preference names accepted from shareable URL preference imports.
+1 -1
View File
@@ -6,7 +6,7 @@ use regex::Regex;
use crate::{config::Config, types::Prefs};
pub const STYLE_CSS: &str = "/css/style.css?teapawt8";
pub const CLEAN_CSS: &str = "/css/clean.css?teapawt20";
pub const CLEAN_CSS: &str = "/css/clean.css?teapawt21";
pub const FONTELLO_CSS: &str = "/css/fontello.css";
/// Builder for rendering a full page layout.
+24 -3
View File
@@ -74,9 +74,26 @@ pub fn is_firefox(user_agent: &str) -> bool {
ua.contains("firefox/") || ua.contains("fxios/")
}
/// Shown to Firefox visitors. On the homepage it links to settings; in settings
/// it sits next to the proxy checkbox.
/// Homepage warning plus its dismiss form. Settings renders the two pieces
/// separately so the form is not nested inside the preferences form.
pub fn firefox_media_warning(in_settings: bool) -> Markup {
html! {
(firefox_media_warning_body(in_settings))
(firefox_ignore_form(in_settings))
}
}
fn firefox_ignore_form(in_settings: bool) -> Markup {
let return_to = if in_settings { "/settings" } else { "/" };
html! {
form id="ignore-firefox-warning" method="post" action="/ignorefirefoxwarning" class="firefox-warning-ignore" {
input type="hidden" name="referer" value=(return_to);
script src="/js/firefoxWarning.js" defer {}
}
}
}
fn firefox_media_warning_body(in_settings: bool) -> Markup {
html! {
aside class="firefox-media-warning" {
strong { "Firefox can block photos and videos." }
@@ -89,6 +106,7 @@ pub fn firefox_media_warning(in_settings: bool) -> Markup {
" and they load from this site instead."
}
}
button type="submit" form="ignore-firefox-warning" { "Ignore warning" }
}
}
}
@@ -113,6 +131,9 @@ pub fn render_preferences_form(
p { "Customize your teapawt experience" }
}
@if firefox {
(firefox_ignore_form(true))
}
form method="post" action="/saveprefs" autocomplete="off" class="preferences-form" id="saveprefs-form" {
input type="hidden" name="referer" value=(referer);
@@ -140,7 +161,7 @@ pub fn render_preferences_form(
div class="pref-section" data-section="media" {
legend { "Media" }
@if firefox {
(firefox_media_warning(true))
(firefox_media_warning_body(true))
}
div class="pref-grid" {
(gen_checkbox("proxyMedia", "Proxy media streaming through the server", prefs.proxy_media))