1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-12-22 17:44:22 +00:00

Use imgproxy to convert images on the fly

This commit is contained in:
Steffo 2023-03-24 00:51:18 +01:00
parent f469776a1d
commit 0d3c1329c4
Signed by: steffo
GPG key ID: 2A24051445686895
3 changed files with 128 additions and 41 deletions

37
Cargo.lock generated
View file

@ -347,6 +347,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
@ -652,6 +653,21 @@ dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "htmlescape"
version = "0.3.1"
@ -1088,8 +1104,11 @@ name = "patched_porobot"
version = "0.9.2"
dependencies = [
"anyhow",
"base64 0.21.0",
"data-encoding",
"glob",
"hex",
"hmac",
"itertools 0.10.5",
"lazy_static",
"log",
@ -1101,6 +1120,7 @@ dependencies = [
"serde",
"serde_json",
"serenity",
"sha2",
"tantivy",
"teloxide",
"tokio",
@ -1563,6 +1583,17 @@ dependencies = [
"digest",
]
[[package]]
name = "sha2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
@ -1624,6 +1655,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.107"

View file

@ -26,6 +26,11 @@ data-encoding = { version = "2.3.2" }
varint-rs = { version = "2.2.0" }
glob = { version = "0.3.0" }
reqwest = { version = "0.11.11", features = ["rustls-tls", "json"], default-features = false }
# jpg
hex = { version = "0.4.3", optional = true }
base64 = { version = "0.21.0", optional = true }
hmac = { version = "0.12.1", optional = true }
sha2 = { version = "0.10.6", optional = true }
# exec
pretty_env_logger = { version = "0.4.0", optional = true }
# data
@ -45,9 +50,10 @@ anyhow = { version = "^1.0.68", optional = true }
[features]
jpg = ["hmac", "sha2", "base64", "hex"]
exec = ["pretty_env_logger"]
search = ["tantivy"]
telegram = ["exec", "search", "teloxide", "tokio", "md5", "rand"]
telegram = ["exec", "search", "jpg", "teloxide", "tokio", "md5", "rand"]
discord = ["exec", "search", "serenity", "tokio", "anyhow"]
matrix = ["exec", "search"]

View file

@ -1,7 +1,8 @@
//! Module defining [CardArt].
use lazy_static::lazy_static;
use regex::Regex;
use base64::Engine;
use hmac::Mac;
use std::env;
/// The illustration of a [Card](super::card::Card), also referred to as an *art asset*.
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
@ -30,52 +31,95 @@ pub struct CardArt {
}
impl CardArt {
/// URL to the `.jpg` image of the `en_us` locale of the rendered card, via my custom S3 mirror.
///
/// # Example
///
/// ```text
/// https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/set1-en_us/en_us/img/cards/01DE001.jpg
/// ```
///
pub fn card_jpg(&self) -> String {
lazy_static! {
static ref GET_JPG: Regex = Regex::new(
r#"https?://dd[.]b[.]pvp[.]net/[^/]+/(?P<bundle>[^/]+)/(?P<locale>[^/]+)/img/cards/(?P<code>.+)[.]png$"#
)
.unwrap();
}
GET_JPG
.replace_all(
&self.card_png,
"https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/$bundle-$locale/$locale/img/cards/$code.jpg",
)
.to_string()
/// Get the URL to convert the image at the given URL into JPG using imgproxy.
#[cfg(feature = "jpg")]
fn imgproxy_convert_to_jpg(url: &str) -> String {
let url = base64::prelude::BASE64_URL_SAFE.encode(url);
let url = format!("/{url}.jpg");
log::trace!("Created JPG conversion URL: {url}");
url
}
/// URL to the `.jpg` image of the `en_us` locale of the full card art, via my custom S3 mirror.
/// Add the HMAC required by imgproxy to authenticate the source of the image requester to the URL.
///
/// # Example
/// # Panics
///
/// ```text
/// https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/set1-en_us/en_us/img/cards/01DE001-full.jpg
/// ```
/// If the `POROXY_KEY` or `POROXY_SALT` variables are not defined.
///
pub fn full_jpg(&self) -> String {
lazy_static! {
static ref GET_JPG: Regex = Regex::new(
r#"https?://dd[.]b[.]pvp[.]net/[^/]+/(?P<bundle>[^/]+)/(?P<locale>[^/]+)/img/cards/(?P<code>.+)[.]png$"#
)
.unwrap();
}
#[cfg(feature = "jpg")]
fn imgproxy_authenticate_url(url: &str) -> String {
let key = env::var("POROXY_KEY")
.expect("POROXY_KEY to be set");
let key = hex::decode(key)
.expect("POROXY_KEY to be a valid hex code");
GET_JPG
.replace_all(
&self.full_png,
"https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/$bundle-$locale/$locale/img/cards/$code.jpg",
let salt = env::var("POROXY_SALT")
.expect("POROXY_SALT to be set");
let salt = hex::decode(salt)
.expect("POROXY_SALT to be a valid hex code");
let salt: String = String::from_utf8(salt)
.expect("salt to be a valid UTF-8 string");
let mut hmac = hmac::Hmac::<sha2::Sha256>::new_from_slice(key.as_slice())
.expect("HMAC to be initialized successfully");
hmac.update(&format!("{salt}{url}").into_bytes());
let hmac = hmac.finalize().into_bytes();
let hmac = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(hmac);
let url = format!("/{hmac}{url}");
log::trace!("Created authenticated URL: {url}");
url
}
/// URL to the `.jpg` image of the rendered card, via imgproxy.
///
/// # Panics
///
/// If the `POROXY_HOST`, `POROXY_KEY` and `POROXY_SALT` variables are not defined.
///
#[cfg(feature = "jpg")]
pub fn card_jpg(&self) -> String {
let host = env::var("POROXY_HOST")
.expect("POROXY_HOST to be set");
let url = Self::imgproxy_authenticate_url(
&Self::imgproxy_convert_to_jpg(
&self.card_png
)
.to_string()
);
let url = format!("{host}{url}");
log::trace!("Accessed card_jpg: {url}");
url
}
/// URL to the `.jpg` image of the rendered card, via imgproxy.
///
/// # Panics
///
/// If the `POROXY_HOST`, `POROXY_KEY` and `POROXY_SALT` variables are not defined.
///
#[cfg(feature = "jpg")]
pub fn full_jpg(&self) -> String {
let host = env::var("POROXY_HOST")
.expect("POROXY_HOST to be set");
let url = Self::imgproxy_authenticate_url(
&Self::imgproxy_convert_to_jpg(
&self.full_png
)
);
let url = format!("{host}{url}");
log::trace!("Accessed full_jpg: {url}");
url
}
}