1
Fork 0
mirror of https://github.com/Steffo99/patched-porobot.git synced 2024-12-23 01:54: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 = [ dependencies = [
"block-buffer", "block-buffer",
"crypto-common", "crypto-common",
"subtle",
] ]
[[package]] [[package]]
@ -652,6 +653,21 @@ dependencies = [
"libc", "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]] [[package]]
name = "htmlescape" name = "htmlescape"
version = "0.3.1" version = "0.3.1"
@ -1088,8 +1104,11 @@ name = "patched_porobot"
version = "0.9.2" version = "0.9.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.21.0",
"data-encoding", "data-encoding",
"glob", "glob",
"hex",
"hmac",
"itertools 0.10.5", "itertools 0.10.5",
"lazy_static", "lazy_static",
"log", "log",
@ -1101,6 +1120,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serenity", "serenity",
"sha2",
"tantivy", "tantivy",
"teloxide", "teloxide",
"tokio", "tokio",
@ -1563,6 +1583,17 @@ dependencies = [
"digest", "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]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.4" version = "0.1.4"
@ -1624,6 +1655,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.107" version = "1.0.107"

View file

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

View file

@ -1,7 +1,8 @@
//! Module defining [CardArt]. //! Module defining [CardArt].
use lazy_static::lazy_static; use base64::Engine;
use regex::Regex; use hmac::Mac;
use std::env;
/// The illustration of a [Card](super::card::Card), also referred to as an *art asset*. /// 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)] #[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
@ -30,52 +31,95 @@ pub struct CardArt {
} }
impl 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 /// Get the URL to convert the image at the given URL into JPG using imgproxy.
.replace_all( #[cfg(feature = "jpg")]
&self.card_png, fn imgproxy_convert_to_jpg(url: &str) -> String {
"https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/$bundle-$locale/$locale/img/cards/$code.jpg", let url = base64::prelude::BASE64_URL_SAFE.encode(url);
) let url = format!("/{url}.jpg");
.to_string()
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 /// If the `POROXY_KEY` or `POROXY_SALT` variables are not defined.
/// https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/set1-en_us/en_us/img/cards/01DE001-full.jpg
/// ```
/// ///
pub fn full_jpg(&self) -> String { #[cfg(feature = "jpg")]
lazy_static! { fn imgproxy_authenticate_url(url: &str) -> String {
static ref GET_JPG: Regex = Regex::new( let key = env::var("POROXY_KEY")
r#"https?://dd[.]b[.]pvp[.]net/[^/]+/(?P<bundle>[^/]+)/(?P<locale>[^/]+)/img/cards/(?P<code>.+)[.]png$"# .expect("POROXY_KEY to be set");
) let key = hex::decode(key)
.unwrap(); .expect("POROXY_KEY to be a valid hex code");
}
GET_JPG let salt = env::var("POROXY_SALT")
.replace_all( .expect("POROXY_SALT to be set");
&self.full_png, let salt = hex::decode(salt)
"https://objectstorage.eu-milan-1.oraclecloud.com/n/axxdmk4y92aq/b/porobot-storage/o/$bundle-$locale/$locale/img/cards/$code.jpg", .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
} }
} }