add opengraph metadata for preview cards

This commit is contained in:
xenofem 2022-06-29 20:00:58 -04:00
parent b0a2f7ec7c
commit 16e7ea4806
7 changed files with 44 additions and 5 deletions

2
Cargo.lock generated
View file

@ -1585,7 +1585,7 @@ dependencies = [
[[package]] [[package]]
name = "transbeam" name = "transbeam"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"actix", "actix",
"actix-files", "actix-files",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "transbeam" name = "transbeam"
version = "0.1.0" version = "0.2.0"
authors = ["xenofem <xenofem@xeno.science>"] authors = ["xenofem <xenofem@xeno.science>"]
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"

View file

@ -28,6 +28,8 @@ transbeam is configured with the following environment variables:
(default: `./storage`) (default: `./storage`)
- `TRANSBEAM_STATIC_DIR`: path where the web app's static files live - `TRANSBEAM_STATIC_DIR`: path where the web app's static files live
(default: `./static`) (default: `./static`)
- `TRANSBEAM_BASE_URL`: base URL for this transbeam instance, without
trailing `/`
- `TRANSBEAM_PORT`: port to listen on localhost for http requests - `TRANSBEAM_PORT`: port to listen on localhost for http requests
(default: 8080) (default: 8080)
- `TRANSBEAM_REVERSE_PROXY`: whether transbeam is running behind a - `TRANSBEAM_REVERSE_PROXY`: whether transbeam is running behind a

View file

@ -30,6 +30,7 @@ struct AppState {
} }
struct Config { struct Config {
base_url: String,
max_upload_size: u64, max_upload_size: u64,
max_lifetime: u16, max_lifetime: u16,
upload_password: String, upload_password: String,
@ -58,12 +59,14 @@ pub fn log_auth_failure(ip_addr: &str) {
#[template(path = "index.html")] #[template(path = "index.html")]
struct IndexPage { struct IndexPage {
cachebuster: String, cachebuster: String,
base_url: String,
} }
#[get("/")] #[get("/")]
async fn index(data: web::Data<AppState>) -> impl Responder { async fn index(data: web::Data<AppState>) -> impl Responder {
IndexPage { IndexPage {
cachebuster: data.config.cachebuster.clone(), cachebuster: data.config.cachebuster.clone(),
base_url: data.config.base_url.clone(),
} }
} }
@ -78,6 +81,7 @@ struct DownloadRequest {
struct DownloadPage<'a> { struct DownloadPage<'a> {
info: DownloadInfo, info: DownloadInfo,
cachebuster: &'a str, cachebuster: &'a str,
base_url: &'a str,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -134,6 +138,7 @@ async fn handle_download(
offsets, offsets,
}, },
cachebuster: &data.config.cachebuster, cachebuster: &data.config.cachebuster,
base_url: &data.config.base_url,
} }
.to_response()) .to_response())
} }
@ -175,6 +180,7 @@ async fn download_info(
#[template(path = "404.html")] #[template(path = "404.html")]
struct NotFoundPage<'a> { struct NotFoundPage<'a> {
cachebuster: &'a str, cachebuster: &'a str,
base_url: &'a str,
} }
fn not_found<T>(req: HttpRequest, data: web::Data<AppState>, report: bool) -> actix_web::Result<T> { fn not_found<T>(req: HttpRequest, data: web::Data<AppState>, report: bool) -> actix_web::Result<T> {
@ -184,6 +190,7 @@ fn not_found<T>(req: HttpRequest, data: web::Data<AppState>, report: bool) -> ac
} }
let mut resp = NotFoundPage { let mut resp = NotFoundPage {
cachebuster: &data.config.cachebuster, cachebuster: &data.config.cachebuster,
base_url: &data.config.base_url,
} }
.to_response(); .to_response();
*resp.status_mut() = StatusCode::NOT_FOUND; *resp.status_mut() = StatusCode::NOT_FOUND;
@ -269,6 +276,14 @@ where
.unwrap_or_else(default) .unwrap_or_else(default)
} }
fn env_or_panic<T: FromStr>(var: &str) -> T
where
<T as FromStr>::Err: Debug,
{
let val = std::env::var(var).unwrap_or_else(|_| panic!("{} must be set!", var));
val.parse::<T>().unwrap_or_else(|_| panic!("Invalid value {} for variable {}", val, var))
}
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
@ -276,6 +291,7 @@ async fn main() -> std::io::Result<()> {
let static_dir: PathBuf = env_or_else("TRANSBEAM_STATIC_DIR", || PathBuf::from("static")); let static_dir: PathBuf = env_or_else("TRANSBEAM_STATIC_DIR", || PathBuf::from("static"));
let storage_dir: PathBuf = env_or_else("TRANSBEAM_STORAGE_DIR", || PathBuf::from("storage")); let storage_dir: PathBuf = env_or_else("TRANSBEAM_STORAGE_DIR", || PathBuf::from("storage"));
let base_url: String = env_or_panic("TRANSBEAM_BASE_URL");
let port: u16 = env_or("TRANSBEAM_PORT", 8080); let port: u16 = env_or("TRANSBEAM_PORT", 8080);
let mnemonic_codes: bool = env_or("TRANSBEAM_MNEMONIC_CODES", true); let mnemonic_codes: bool = env_or("TRANSBEAM_MNEMONIC_CODES", true);
let reverse_proxy: bool = env_or("TRANSBEAM_REVERSE_PROXY", true); let reverse_proxy: bool = env_or("TRANSBEAM_REVERSE_PROXY", true);
@ -284,13 +300,13 @@ async fn main() -> std::io::Result<()> {
env_or::<ByteSize>("TRANSBEAM_MAX_UPLOAD_SIZE", ByteSize(16 * bytesize::GB)).as_u64(); env_or::<ByteSize>("TRANSBEAM_MAX_UPLOAD_SIZE", ByteSize(16 * bytesize::GB)).as_u64();
let max_storage_size: u64 = let max_storage_size: u64 =
env_or::<ByteSize>("TRANSBEAM_MAX_STORAGE_SIZE", ByteSize(64 * bytesize::GB)).as_u64(); env_or::<ByteSize>("TRANSBEAM_MAX_STORAGE_SIZE", ByteSize(64 * bytesize::GB)).as_u64();
let upload_password: String = let upload_password: String = env_or_panic("TRANSBEAM_UPLOAD_PASSWORD");
std::env::var("TRANSBEAM_UPLOAD_PASSWORD").expect("TRANSBEAM_UPLOAD_PASSWORD must be set!");
let cachebuster: String = env_or_else("TRANSBEAM_CACHEBUSTER", String::new); let cachebuster: String = env_or_else("TRANSBEAM_CACHEBUSTER", String::new);
let data = web::Data::new(AppState { let data = web::Data::new(AppState {
file_store: RwLock::new(FileStore::load(storage_dir.clone(), max_storage_size).await?), file_store: RwLock::new(FileStore::load(storage_dir.clone(), max_storage_size).await?),
config: Config { config: Config {
base_url,
max_upload_size, max_upload_size,
max_lifetime, max_lifetime,
upload_password, upload_password,

View file

@ -1,6 +1,8 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block title %}Download not found - transbeam{% endblock %} {% block title %}Download not found - transbeam{% endblock %}
{% block og_title %}Download not found{% endblock %}
{% block og_description %}{% endblock %}
{% block head %} {% block head %}
<script src="js/download-landing.js?{{ cachebuster }}"></script> <script src="js/download-landing.js?{{ cachebuster }}"></script>

View file

@ -3,12 +3,18 @@
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark"/>
<link rel="stylesheet" type="text/css" href="css/transbeam.css?{{ cachebuster }}"/> <link rel="stylesheet" type="text/css" href="css/transbeam.css?{{ cachebuster }}"/>
<link rel="stylesheet" type="text/css" href="css/colors.css?{{ cachebuster }}"/> <link rel="stylesheet" type="text/css" href="css/colors.css?{{ cachebuster }}"/>
<link rel="apple-touch-icon" href="images/site-icons/transbeam-apple.png"/> <link rel="apple-touch-icon" href="images/site-icons/transbeam-apple.png"/>
<link rel="manifest" href="manifest.json"/> <link rel="manifest" href="manifest.json"/>
<title>{% block title %}transbeam{% endblock %}</title> <title>{% block title %}transbeam{% endblock %}</title>
<meta name="og:type" content="website"/>
<meta name="og:site_name" content="transbeam"/>
<meta name="og:title" content="{% block og_title %}transbeam{% endblock %}"/>
<meta name="og:description" content="{% block og_description %}Low-latency file-drop web app{% endblock %}"/>
<meta name="og:image" content="{{ base_url }}/images/site-icons/transbeam-192.png"/>
<meta name="og:url" content="{{ base_url }}/{% block relative_path %}{% endblock %}"/>
{% block head %}{% endblock %} {% block head %}{% endblock %}
</head> </head>
<body {% block body_attrs %}{% endblock %}> <body {% block body_attrs %}{% endblock %}>

View file

@ -2,6 +2,19 @@
{% block title %}{{ info.file.name }} - transbeam{% endblock %} {% block title %}{{ info.file.name }} - transbeam{% endblock %}
{% block og_title %}{{ info.file.name }}{% endblock %}
{% block og_description -%}
{% let formatted_total_size = bytesize::to_string(info.file.size.clone(), false).replace(" ", "") -%}
{% match info.file.contents -%}
{% when Some with (files) -%}
{{ files.len() }} files, {{ formatted_total_size }} total
{%- else -%}
{{ formatted_total_size }}
{%- endmatch %}, expires {{ info.file.expiry.format(DATE_DISPLAY_FORMAT).unwrap() }}
{%- endblock %}
{% block relative_path %}download?code={{ info.code }}{% endblock %}
{% block head %} {% block head %}
<script src="js/util.js?{{ cachebuster }}"></script> <script src="js/util.js?{{ cachebuster }}"></script>
<script type="text/javascript"> <script type="text/javascript">