From 0f1783153fb8880e42f9573a0b6096c3b08fc098 Mon Sep 17 00:00:00 2001 From: serenissi Date: Mon, 24 Mar 2025 14:22:32 +0530 Subject: [PATCH] Add optional capability to load media (image and video) directly from reddit on client. Not that this might have privacy implication of leaking user's ip address to reddit. But this also means the server load and traffic will reduce. --- README.md | 5 +++-- app.json | 3 +++ contrib/redlib.conf | 1 + src/config.rs | 5 +++++ src/main.rs | 11 ++++++++++- src/utils.rs | 24 ++++++++++++++++++++++-- 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fcae126..2f54869 100644 --- a/README.md +++ b/README.md @@ -416,7 +416,8 @@ Assign a default value for each instance-specific setting by passing environment | `PUSHSHIFT_FRONTEND` | String | `undelete.pullpush.io` | Allows the server to set the Pushshift frontend to be used with "removed" links. | | `PORT` | Integer 0-65535 | `8080` | The **internal** port Redlib listens on. | | `ENABLE_RSS` | `["on", "off"]` | `off` | Enables RSS feed generation. | -| `FULL_URL` | String | (empty) | Allows for proper URLs (for now, only needed by RSS) +| `FULL_URL` | String | (empty) | Allows for proper URLs (for now, only needed by RSS) | +| `TAINTED_MEDIA` | `["on", "off"]` | `off` | ⚠️ Enable images and video load clientside from **reddit**. Trade privacy with server load. | ## Default user settings Assign a default value for each user-modifiable setting by passing environment variables to Redlib in the format `REDLIB_DEFAULT_{Y}`. Replace `{Y}` with the setting name (see list below) in capital letters. @@ -441,4 +442,4 @@ Assign a default value for each user-modifiable setting by passing environment v | `HIDE_SCORE` | `["on", "off"]` | `off` | | `HIDE_SIDEBAR_AND_SUMMARY` | `["on", "off"]` | `off` | | `FIXED_NAVBAR` | `["on", "off"]` | `on` | -| `REMOVE_DEFAULT_FEEDS` | `["on", "off"]` | `off` | \ No newline at end of file +| `REMOVE_DEFAULT_FEEDS` | `["on", "off"]` | `off` | diff --git a/app.json b/app.json index 4af7cfe..523d739 100644 --- a/app.json +++ b/app.json @@ -79,6 +79,9 @@ }, "REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS": { "required": false + }, + "REDLIB_TAINTED_MEDIA": { + "required": false } } } diff --git a/contrib/redlib.conf b/contrib/redlib.conf index e670455..f635076 100644 --- a/contrib/redlib.conf +++ b/contrib/redlib.conf @@ -15,3 +15,4 @@ PORT=12345 #REDLIB_DEFAULT_SUBSCRIPTIONS=(sub1+sub2+sub3) #REDLIB_DEFAULT_HIDE_AWARDS=off #REDLIB_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION=off +#REDLIB_TAINTED_MEDIA=off diff --git a/src/config.rs b/src/config.rs index 7b1c95c..f0bde58 100644 --- a/src/config.rs +++ b/src/config.rs @@ -112,6 +112,9 @@ pub struct Config { #[serde(rename = "REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS")] pub(crate) default_remove_default_feeds: Option, + + #[serde(rename = "REDLIB_TAINTED_MEDIA")] + pub(crate) tainted_media: Option, } impl Config { @@ -160,6 +163,7 @@ impl Config { enable_rss: parse("REDLIB_ENABLE_RSS"), full_url: parse("REDLIB_FULL_URL"), default_remove_default_feeds: parse("REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS"), + tainted_media: parse("REDLIB_TAINTED_MEDIA"), } } } @@ -190,6 +194,7 @@ fn get_setting_from_config(name: &str, config: &Config) -> Option { "REDLIB_ENABLE_RSS" => config.enable_rss.clone(), "REDLIB_FULL_URL" => config.full_url.clone(), "REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS" => config.default_remove_default_feeds.clone(), + "REDLIB_TAINTED_MEDIA" => config.tainted_media.clone(), _ => None, } } diff --git a/src/main.rs b/src/main.rs index e1b010d..52036c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -211,7 +211,16 @@ async fn main() { "Referrer-Policy" => "no-referrer", "X-Content-Type-Options" => "nosniff", "X-Frame-Options" => "DENY", - "Content-Security-Policy" => "default-src 'none'; font-src 'self'; script-src 'self' blob:; manifest-src 'self'; media-src 'self' data: blob: about:; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; connect-src 'self'; worker-src blob:;" + "Content-Security-Policy" => + if match config::get_setting("REDLIB_TAINTED_MEDIA") { + Some(val) => val == "on", + None => false, + } { + "default-src 'none'; font-src 'self'; script-src 'self' blob:; manifest-src 'self'; media-src 'self' i.redd.it v.redd.it data: blob: about:; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' i.redd.it data:; form-action 'self'; frame-ancestors 'none'; connect-src 'self' v.redd.it; worker-src blob:;" + } + else { + "default-src 'none'; font-src 'self'; script-src 'self' blob:; manifest-src 'self'; media-src 'self' data: blob: about:; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; connect-src 'self'; worker-src blob:;" + } }; if let Some(expire_time) = hsts { diff --git a/src/utils.rs b/src/utils.rs index f5046cb..dd4bfbc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1060,8 +1060,28 @@ pub fn format_url(url: &str) -> String { "old.reddit.com" => capture(®EX_URL_OLD, "/", 1), "np.reddit.com" => capture(®EX_URL_NP, "/", 1), "reddit.com" => capture(®EX_URL_PLAIN, "/", 1), - "v.redd.it" => chain!(capture(®EX_URL_VIDEOS, "/vid/", 2), capture(®EX_URL_VIDEOS_HLS, "/hls/", 2)), - "i.redd.it" => capture(®EX_URL_IMAGES, "/img/", 1), + "v.redd.it" => { + if match config::get_setting("REDLIB_TAINTED_MEDIA") { + Some(val) => val == "on", + None => false, + } { + url.to_string() + } + else { + chain!(capture(®EX_URL_VIDEOS, "/vid/", 2), capture(®EX_URL_VIDEOS_HLS, "/hls/", 2)) + } + }, + "i.redd.it" => { + if match config::get_setting("REDLIB_TAINTED_MEDIA") { + Some(val) => val == "on", + None => false, + } { + url.to_string() + } + else { + capture(®EX_URL_IMAGES, "/img/", 1) + } + }, "a.thumbs.redditmedia.com" => capture(®EX_URL_THUMBS_A, "/thumb/a/", 1), "b.thumbs.redditmedia.com" => capture(®EX_URL_THUMBS_B, "/thumb/b/", 1), "emoji.redditmedia.com" => capture(®EX_URL_EMOJI, "/emoji/", 2),