Restrict Proxy to Reddit Domains
This commit is contained in:
parent
f49bff9853
commit
5ea504e6e8
@ -7,13 +7,9 @@ version = "0.2.5"
|
|||||||
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["proxy"]
|
|
||||||
proxy = ["actix-web/rustls", "base64"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = { version = "0.13.0", optional = true }
|
base64 = "0.13.0"
|
||||||
actix-web = "3.2.0"
|
actix-web = { version = "3.2.0", features = ["rustls"] }
|
||||||
reqwest = { version = "0.10", default_features = false, features = ["rustls-tls"] }
|
reqwest = { version = "0.10", default_features = false, features = ["rustls-tls"] }
|
||||||
askama = "0.8.0"
|
askama = "0.8.0"
|
||||||
serde = "1.0.117"
|
serde = "1.0.117"
|
||||||
|
@ -5,6 +5,7 @@ use actix_web::{get, middleware::NormalizePath, web, App, HttpResponse, HttpServ
|
|||||||
mod post;
|
mod post;
|
||||||
mod proxy;
|
mod proxy;
|
||||||
mod search;
|
mod search;
|
||||||
|
// mod settings;
|
||||||
mod subreddit;
|
mod subreddit;
|
||||||
mod user;
|
mod user;
|
||||||
mod utils;
|
mod utils;
|
||||||
@ -50,6 +51,9 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.route("/style.css/", web::get().to(style))
|
.route("/style.css/", web::get().to(style))
|
||||||
.route("/favicon.ico/", web::get().to(HttpResponse::Ok))
|
.route("/favicon.ico/", web::get().to(HttpResponse::Ok))
|
||||||
.route("/robots.txt/", web::get().to(robots))
|
.route("/robots.txt/", web::get().to(robots))
|
||||||
|
// SETTINGS SERVICE
|
||||||
|
// .route("/settings/", web::get().to(settings::get))
|
||||||
|
// .route("/settings/save/", web::post().to(settings::set))
|
||||||
// PROXY SERVICE
|
// PROXY SERVICE
|
||||||
.route("/proxy/{url:.*}/", web::get().to(proxy::handler))
|
.route("/proxy/{url:.*}/", web::get().to(proxy::handler))
|
||||||
// SEARCH SERVICES
|
// SEARCH SERVICES
|
||||||
|
@ -16,7 +16,7 @@ struct PostTemplate {
|
|||||||
sort: String,
|
sort: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn item(req: HttpRequest) -> Result<HttpResponse> {
|
pub async fn item(req: HttpRequest) -> HttpResponse {
|
||||||
let path = format!("{}.json?{}&raw_json=1", req.path(), req.query_string());
|
let path = format!("{}.json?{}&raw_json=1", req.path(), req.query_string());
|
||||||
let sort = param(&path, "sort");
|
let sort = param(&path, "sort");
|
||||||
let id = req.match_info().get("id").unwrap_or("").to_string();
|
let id = req.match_info().get("id").unwrap_or("").to_string();
|
||||||
@ -35,7 +35,7 @@ pub async fn item(req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
|
|
||||||
// Use the Post and Comment structs to generate a website to show users
|
// Use the Post and Comment structs to generate a website to show users
|
||||||
let s = PostTemplate { comments, post, sort }.render().unwrap();
|
let s = PostTemplate { comments, post, sort }.render().unwrap();
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
HttpResponse::Ok().content_type("text/html").body(s)
|
||||||
}
|
}
|
||||||
// If the Reddit API returns an error, exit and send error page to user
|
// If the Reddit API returns an error, exit and send error page to user
|
||||||
Err(msg) => error(msg.to_string()).await,
|
Err(msg) => error(msg.to_string()).await,
|
||||||
|
54
src/proxy.rs
54
src/proxy.rs
@ -1,30 +1,40 @@
|
|||||||
use actix_web::{client::Client, web, Error, HttpResponse, Result};
|
use actix_web::{client::Client, error, web, Error, HttpResponse, Result};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[cfg(feature = "proxy")]
|
|
||||||
use base64::decode;
|
use base64::decode;
|
||||||
|
|
||||||
pub async fn handler(web::Path(url): web::Path<String>) -> Result<HttpResponse> {
|
pub async fn handler(web::Path(b64): web::Path<String>) -> Result<HttpResponse> {
|
||||||
if cfg!(feature = "proxy") {
|
let domains = vec![
|
||||||
#[cfg(feature = "proxy")]
|
"a.thumbs.redditmedia.com",
|
||||||
let media: String;
|
"b.thumbs.redditmedia.com",
|
||||||
|
"preview.redd.it",
|
||||||
|
"external-preview.redd.it",
|
||||||
|
"i.redd.it",
|
||||||
|
"v.redd.it",
|
||||||
|
];
|
||||||
|
|
||||||
#[cfg(not(feature = "proxy"))]
|
match decode(b64) {
|
||||||
let media = url;
|
Ok(bytes) => {
|
||||||
|
let media = String::from_utf8(bytes).unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "proxy")]
|
match Url::parse(media.as_str()) {
|
||||||
match decode(url) {
|
Ok(url) => {
|
||||||
Ok(bytes) => media = String::from_utf8(bytes).unwrap(),
|
let domain = url.domain().unwrap_or_default();
|
||||||
Err(_e) => return Ok(HttpResponse::Ok().body("")),
|
|
||||||
};
|
|
||||||
|
|
||||||
let client = Client::default();
|
if domains.contains(&domain) {
|
||||||
client
|
Client::default()
|
||||||
.get(media.replace("&", "&"))
|
.get(media.replace("&", "&"))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
.map(|res| HttpResponse::build(res.status()).streaming(res))
|
.map(|res| HttpResponse::build(res.status()).streaming(res))
|
||||||
} else {
|
} else {
|
||||||
Ok(HttpResponse::Ok().body(""))
|
Err(error::ErrorForbidden("Resource must be from Reddit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Err(error::ErrorBadRequest("Can't parse encoded base64 URL")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Err(error::ErrorBadRequest("Can't decode base64 URL")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use crate::utils::{error, fetch_posts, param, Post};
|
use crate::utils::{error, fetch_posts, param, Post};
|
||||||
use actix_web::{HttpRequest, HttpResponse, Result};
|
use actix_web::{HttpRequest, HttpResponse};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[allow(dead_code)]
|
|
||||||
#[template(path = "search.html", escape = "none")]
|
#[template(path = "search.html", escape = "none")]
|
||||||
struct SearchTemplate {
|
struct SearchTemplate {
|
||||||
posts: Vec<Post>,
|
posts: Vec<Post>,
|
||||||
@ -16,7 +15,7 @@ struct SearchTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SERVICES
|
// SERVICES
|
||||||
pub async fn find(req: HttpRequest) -> Result<HttpResponse> {
|
pub async fn find(req: HttpRequest) -> HttpResponse {
|
||||||
let path = format!("{}.json?{}", req.path(), req.query_string());
|
let path = format!("{}.json?{}", req.path(), req.query_string());
|
||||||
let q = param(&path, "q");
|
let q = param(&path, "q");
|
||||||
let sort = if param(&path, "sort").is_empty() {
|
let sort = if param(&path, "sort").is_empty() {
|
||||||
@ -27,8 +26,8 @@ pub async fn find(req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
let sub = req.match_info().get("sub").unwrap_or("").to_string();
|
let sub = req.match_info().get("sub").unwrap_or("").to_string();
|
||||||
|
|
||||||
match fetch_posts(&path, String::new()).await {
|
match fetch_posts(&path, String::new()).await {
|
||||||
Ok(posts) => {
|
Ok(posts) => HttpResponse::Ok().content_type("text/html").body(
|
||||||
let s = SearchTemplate {
|
SearchTemplate {
|
||||||
posts: posts.0,
|
posts: posts.0,
|
||||||
query: q,
|
query: q,
|
||||||
sub,
|
sub,
|
||||||
@ -36,9 +35,8 @@ pub async fn find(req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
ends: (param(&path, "after"), posts.1),
|
ends: (param(&path, "after"), posts.1),
|
||||||
}
|
}
|
||||||
.render()
|
.render()
|
||||||
.unwrap();
|
.unwrap(),
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
),
|
||||||
}
|
|
||||||
Err(msg) => error(msg.to_string()).await,
|
Err(msg) => error(msg.to_string()).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
src/settings.rs
Normal file
48
src/settings.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// // CRATES
|
||||||
|
// use crate::utils::cookies;
|
||||||
|
// use actix_web::{cookie::Cookie, web::Form, HttpRequest, HttpResponse, Result}; // http::Method,
|
||||||
|
// use askama::Template;
|
||||||
|
|
||||||
|
// // STRUCTS
|
||||||
|
// #[derive(Template)]
|
||||||
|
// #[template(path = "settings.html", escape = "none")]
|
||||||
|
// struct SettingsTemplate {
|
||||||
|
// pref_nsfw: String,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(serde::Deserialize)]
|
||||||
|
// pub struct Preferences {
|
||||||
|
// pref_nsfw: Option<String>,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // FUNCTIONS
|
||||||
|
|
||||||
|
// // Retrieve cookies from request "Cookie" header
|
||||||
|
// pub async fn get(req: HttpRequest) -> Result<HttpResponse> {
|
||||||
|
// let cookies = cookies(req);
|
||||||
|
|
||||||
|
// let pref_nsfw: String = cookies.get("pref_nsfw").unwrap_or(&String::new()).to_owned();
|
||||||
|
|
||||||
|
// let s = SettingsTemplate { pref_nsfw }.render().unwrap();
|
||||||
|
// Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Set cookies using response "Set-Cookie" header
|
||||||
|
// pub async fn set(form: Form<Preferences>) -> HttpResponse {
|
||||||
|
// let nsfw: Cookie = match &form.pref_nsfw {
|
||||||
|
// Some(value) => Cookie::build("pref_nsfw", value).path("/").secure(true).http_only(true).finish(),
|
||||||
|
// None => Cookie::build("pref_nsfw", "").finish(),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let body = SettingsTemplate {
|
||||||
|
// pref_nsfw: form.pref_nsfw.clone().unwrap_or_default(),
|
||||||
|
// }
|
||||||
|
// .render()
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
// HttpResponse::Found()
|
||||||
|
// .content_type("text/html")
|
||||||
|
// .set_header("Set-Cookie", nsfw.to_string())
|
||||||
|
// .set_header("Location", "/settings")
|
||||||
|
// .body(body)
|
||||||
|
// }
|
@ -22,7 +22,7 @@ struct WikiTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SERVICES
|
// SERVICES
|
||||||
pub async fn page(req: HttpRequest) -> Result<HttpResponse> {
|
pub async fn page(req: HttpRequest) -> HttpResponse {
|
||||||
let path = format!("{}.json?{}", req.path(), req.query_string());
|
let path = format!("{}.json?{}", req.path(), req.query_string());
|
||||||
let sub = req.match_info().get("sub").unwrap_or("popular").to_string();
|
let sub = req.match_info().get("sub").unwrap_or("popular").to_string();
|
||||||
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
|
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
|
||||||
@ -43,13 +43,13 @@ pub async fn page(req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
}
|
}
|
||||||
.render()
|
.render()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
HttpResponse::Ok().content_type("text/html").body(s)
|
||||||
}
|
}
|
||||||
Err(msg) => error(msg.to_string()).await,
|
Err(msg) => error(msg.to_string()).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wiki(req: HttpRequest) -> Result<HttpResponse> {
|
pub async fn wiki(req: HttpRequest) -> HttpResponse {
|
||||||
let sub = req.match_info().get("sub").unwrap_or("reddit.com");
|
let sub = req.match_info().get("sub").unwrap_or("reddit.com");
|
||||||
let page = req.match_info().get("page").unwrap_or("index");
|
let page = req.match_info().get("page").unwrap_or("index");
|
||||||
let path: String = format!("r/{}/wiki/{}.json?raw_json=1", sub, page);
|
let path: String = format!("r/{}/wiki/{}.json?raw_json=1", sub, page);
|
||||||
@ -63,7 +63,7 @@ pub async fn wiki(req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
}
|
}
|
||||||
.render()
|
.render()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
HttpResponse::Ok().content_type("text/html").body(s)
|
||||||
}
|
}
|
||||||
Err(msg) => error(msg.to_string()).await,
|
Err(msg) => error(msg.to_string()).await,
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ struct UserTemplate {
|
|||||||
ends: (String, String),
|
ends: (String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn profile(req: HttpRequest) -> Result<HttpResponse> {
|
// FUNCTIONS
|
||||||
|
pub async fn profile(req: HttpRequest) -> HttpResponse {
|
||||||
// Build the Reddit JSON API path
|
// Build the Reddit JSON API path
|
||||||
let path = format!("{}.json?{}&raw_json=1", req.path(), req.query_string());
|
let path = format!("{}.json?{}&raw_json=1", req.path(), req.query_string());
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ pub async fn profile(req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
}
|
}
|
||||||
.render()
|
.render()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
HttpResponse::Ok().content_type("text/html").body(s)
|
||||||
}
|
}
|
||||||
// If there is an error show error page
|
// If there is an error show error page
|
||||||
Err(msg) => error(msg.to_string()).await,
|
Err(msg) => error(msg.to_string()).await,
|
||||||
|
36
src/utils.rs
36
src/utils.rs
@ -1,17 +1,17 @@
|
|||||||
|
// use std::collections::HashMap;
|
||||||
|
|
||||||
//
|
//
|
||||||
// CRATES
|
// CRATES
|
||||||
//
|
//
|
||||||
use actix_web::{http::StatusCode, HttpResponse, Result};
|
use actix_web::{HttpResponse, Result};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use base64::encode;
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::from_str;
|
use serde_json::from_str;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
// use surf::{client, get, middleware::Redirect};
|
// use surf::{client, get, middleware::Redirect};
|
||||||
|
|
||||||
#[cfg(feature = "proxy")]
|
|
||||||
use base64::encode;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
//
|
//
|
||||||
@ -102,17 +102,31 @@ pub fn param(path: &str, value: &str) -> String {
|
|||||||
pairs.get(value).unwrap_or(&String::new()).to_owned()
|
pairs.get(value).unwrap_or(&String::new()).to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cookies from request
|
||||||
|
// pub fn cookies(req: HttpRequest) -> HashMap<String, String> {
|
||||||
|
// let mut result: HashMap<String, String> = HashMap::new();
|
||||||
|
|
||||||
|
// let cookies: Vec<Cookie> = req
|
||||||
|
// .headers()
|
||||||
|
// .get_all("Cookie")
|
||||||
|
// .map(|value| value.to_str().unwrap())
|
||||||
|
// .map(|unparsed| Cookie::parse(unparsed).unwrap())
|
||||||
|
// .collect();
|
||||||
|
|
||||||
|
// for cookie in cookies {
|
||||||
|
// result.insert(cookie.name().to_string(), cookie.value().to_string());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// result
|
||||||
|
// }
|
||||||
|
|
||||||
// Direct urls to proxy if proxy is enabled
|
// Direct urls to proxy if proxy is enabled
|
||||||
pub fn format_url(url: String) -> String {
|
pub fn format_url(url: String) -> String {
|
||||||
if url.is_empty() {
|
if url.is_empty() {
|
||||||
return String::new();
|
return String::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "proxy")]
|
format!("/proxy/{}", encode(url).as_str())
|
||||||
return "/proxy/".to_string() + encode(url).as_str();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "proxy"))]
|
|
||||||
return url.to_string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite Reddit links to Libreddit in body of text
|
// Rewrite Reddit links to Libreddit in body of text
|
||||||
@ -217,10 +231,10 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
|
|||||||
// NETWORKING
|
// NETWORKING
|
||||||
//
|
//
|
||||||
|
|
||||||
pub async fn error(message: String) -> Result<HttpResponse> {
|
pub async fn error(message: String) -> HttpResponse {
|
||||||
let msg = if message.is_empty() { "Page not found".to_string() } else { message };
|
let msg = if message.is_empty() { "Page not found".to_string() } else { message };
|
||||||
let body = ErrorTemplate { message: msg }.render().unwrap_or_default();
|
let body = ErrorTemplate { message: msg }.render().unwrap_or_default();
|
||||||
Ok(HttpResponse::Ok().status(StatusCode::NOT_FOUND).content_type("text/html").body(body))
|
HttpResponse::NotFound().content_type("text/html").body(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a request to a Reddit API and parse the JSON response
|
// Make a request to a Reddit API and parse the JSON response
|
||||||
|
@ -599,8 +599,15 @@ td, th {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
@media screen and (max-width: 800px) {
|
||||||
main { flex-direction: column-reverse; }
|
main {
|
||||||
nav { flex-direction: column; }
|
flex-direction: column-reverse;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
aside, #subreddit, #user {
|
aside, #subreddit, #user {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
{% block head %}
|
{% block head %}
|
||||||
<title>{% block title %}Libreddit{% endblock %}</title>
|
<title>{% block title %}Libreddit{% endblock %}</title>
|
||||||
<meta http-equiv="Referrer-Policy" content="no-referrer">
|
<meta http-equiv="Referrer-Policy" content="no-referrer">
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self';
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self';">
|
||||||
{% if cfg!(not(feature = "proxy")) %}img-src https://*; media-src https://*{% endif %}">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
<meta name="description" content="View on Libreddit, an alternative private front-end to Reddit.">
|
<meta name="description" content="View on Libreddit, an alternative private front-end to Reddit.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<input id="search" type="text" name="q" placeholder="Search" value="{{ query }}">
|
<input id="search" type="text" name="q" placeholder="Search" value="{{ query }}">
|
||||||
{% if sub != "" %}
|
{% if sub != "" %}
|
||||||
<div id="inside">
|
<div id="inside">
|
||||||
<input type="checkbox" name="restrict_sr" id="restrict_sr" checked="checked" data-com.bitwarden.browser.user-edited="yes">
|
<input type="checkbox" name="restrict_sr" id="restrict_sr">
|
||||||
<label for="restrict_sr">in r/{{ sub }}</label>
|
<label for="restrict_sr">in r/{{ sub }}</label>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
18
templates/settings.html
Normal file
18
templates/settings.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import "utils.html" as utils %}
|
||||||
|
|
||||||
|
{% block title %}Libreddit Settings{% endblock %}
|
||||||
|
|
||||||
|
{% block search %}
|
||||||
|
{% call utils::search("".to_owned(), "", "") %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<form action="/settings/save" method="POST">
|
||||||
|
<label for="pref_nsfw">NSFW</label>
|
||||||
|
<input type="checkbox" name="pref_nsfw" id="pref_nsfw" {% if pref_nsfw == "on" %}checked{% endif %}>
|
||||||
|
<input id="sort_submit" type="submit" value="→">
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
@ -19,7 +19,7 @@
|
|||||||
<input id="search" type="text" name="q" placeholder="Search" value="{{ search }}">
|
<input id="search" type="text" name="q" placeholder="Search" value="{{ search }}">
|
||||||
{% if root != "/r/" && !root.is_empty() %}
|
{% if root != "/r/" && !root.is_empty() %}
|
||||||
<div id="inside">
|
<div id="inside">
|
||||||
<input type="checkbox" name="restrict_sr" id="restrict_sr" checked="checked" data-com.bitwarden.browser.user-edited="yes">
|
<input type="checkbox" name="restrict_sr" id="restrict_sr">
|
||||||
<label for="restrict_sr">in {{ root }}</label>
|
<label for="restrict_sr">in {{ root }}</label>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user