add feature flagged support for migrating from base64 file name keys to sha256 ones
core implementation and tests from https://gitlab.com/famedly/conduit/-/merge_requests/467 feature flag, base64 encode update, and tweaks were me Signed-off-by: strawberry <strawberry@pupbrain.dev>
This commit is contained in:
parent
d092820699
commit
e9cd8caaed
6 changed files with 183 additions and 9 deletions
|
@ -3,6 +3,8 @@ use std::io::Cursor;
|
|||
|
||||
pub use data::Data;
|
||||
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
|
||||
use crate::{services, Result};
|
||||
use image::imageops::FilterType;
|
||||
|
||||
|
@ -35,7 +37,12 @@ impl Service {
|
|||
.db
|
||||
.create_file_metadata(mxc, 0, 0, content_disposition, content_type)?;
|
||||
|
||||
let path = services().globals.get_media_file(&key);
|
||||
let path: std::path::PathBuf;
|
||||
if cfg!(feature = "sha256_media") {
|
||||
path = services().globals.get_media_file_new(&key);
|
||||
} else {
|
||||
path = services().globals.get_media_file(&key);
|
||||
}
|
||||
let mut f = File::create(path).await?;
|
||||
f.write_all(file).await?;
|
||||
Ok(())
|
||||
|
@ -56,7 +63,12 @@ impl Service {
|
|||
self.db
|
||||
.create_file_metadata(mxc, width, height, content_disposition, content_type)?;
|
||||
|
||||
let path = services().globals.get_media_file(&key);
|
||||
let path: std::path::PathBuf;
|
||||
if cfg!(feature = "sha256_media") {
|
||||
path = services().globals.get_media_file_new(&key);
|
||||
} else {
|
||||
path = services().globals.get_media_file(&key);
|
||||
}
|
||||
let mut f = File::create(path).await?;
|
||||
f.write_all(file).await?;
|
||||
|
||||
|
@ -68,7 +80,12 @@ impl Service {
|
|||
if let Ok((content_disposition, content_type, key)) =
|
||||
self.db.search_file_metadata(mxc, 0, 0)
|
||||
{
|
||||
let path = services().globals.get_media_file(&key);
|
||||
let path: std::path::PathBuf;
|
||||
if cfg!(feature = "sha256_media") {
|
||||
path = services().globals.get_media_file_new(&key);
|
||||
} else {
|
||||
path = services().globals.get_media_file(&key);
|
||||
}
|
||||
let mut file = Vec::new();
|
||||
BufReader::new(File::open(path).await?)
|
||||
.read_to_end(&mut file)
|
||||
|
@ -121,7 +138,12 @@ impl Service {
|
|||
self.db.search_file_metadata(mxc.clone(), width, height)
|
||||
{
|
||||
// Using saved thumbnail
|
||||
let path = services().globals.get_media_file(&key);
|
||||
let path: std::path::PathBuf;
|
||||
if cfg!(feature = "sha256_media") {
|
||||
path = services().globals.get_media_file_new(&key);
|
||||
} else {
|
||||
path = services().globals.get_media_file(&key);
|
||||
}
|
||||
let mut file = Vec::new();
|
||||
File::open(path).await?.read_to_end(&mut file).await?;
|
||||
|
||||
|
@ -134,7 +156,12 @@ impl Service {
|
|||
self.db.search_file_metadata(mxc.clone(), 0, 0)
|
||||
{
|
||||
// Generate a thumbnail
|
||||
let path = services().globals.get_media_file(&key);
|
||||
let path: std::path::PathBuf;
|
||||
if cfg!(feature = "sha256_media") {
|
||||
path = services().globals.get_media_file_new(&key);
|
||||
} else {
|
||||
path = services().globals.get_media_file(&key);
|
||||
}
|
||||
let mut file = Vec::new();
|
||||
File::open(path).await?.read_to_end(&mut file).await?;
|
||||
|
||||
|
@ -204,7 +231,12 @@ impl Service {
|
|||
content_type.as_deref(),
|
||||
)?;
|
||||
|
||||
let path = services().globals.get_media_file(&thumbnail_key);
|
||||
let path: std::path::PathBuf;
|
||||
if cfg!(feature = "sha256_media") {
|
||||
path = services().globals.get_media_file_new(&key);
|
||||
} else {
|
||||
path = services().globals.get_media_file(&key);
|
||||
}
|
||||
let mut f = File::create(path).await?;
|
||||
f.write_all(&thumbnail_bytes).await?;
|
||||
|
||||
|
@ -226,3 +258,92 @@ impl Service {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use sha2::Digest;
|
||||
|
||||
use super::*;
|
||||
|
||||
struct MockedKVDatabase;
|
||||
|
||||
impl Data for MockedKVDatabase {
|
||||
fn create_file_metadata(
|
||||
&self,
|
||||
mxc: String,
|
||||
width: u32,
|
||||
height: u32,
|
||||
content_disposition: Option<&str>,
|
||||
content_type: Option<&str>,
|
||||
) -> Result<Vec<u8>> {
|
||||
// copied from src/database/key_value/media.rs
|
||||
let mut key = mxc.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(&width.to_be_bytes());
|
||||
key.extend_from_slice(&height.to_be_bytes());
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(
|
||||
content_disposition
|
||||
.as_ref()
|
||||
.map(|f| f.as_bytes())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(
|
||||
content_type
|
||||
.as_ref()
|
||||
.map(|c| c.as_bytes())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
fn search_file_metadata(
|
||||
&self,
|
||||
_mxc: String,
|
||||
_width: u32,
|
||||
_height: u32,
|
||||
) -> Result<(Option<String>, Option<String>, Vec<u8>)> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn long_file_names_works() {
|
||||
static DB: MockedKVDatabase = MockedKVDatabase;
|
||||
let media = Service { db: &DB };
|
||||
|
||||
let mxc = "mxc://example.com/ascERGshawAWawugaAcauga".to_owned();
|
||||
let width = 100;
|
||||
let height = 100;
|
||||
let content_disposition = "attachment; filename=\"this is a very long file name with spaces and special characters like äöüß and even emoji like 🦀.png\"";
|
||||
let content_type = "image/png";
|
||||
let key = media
|
||||
.db
|
||||
.create_file_metadata(
|
||||
mxc,
|
||||
width,
|
||||
height,
|
||||
Some(content_disposition),
|
||||
Some(content_type),
|
||||
)
|
||||
.unwrap();
|
||||
let mut r = PathBuf::new();
|
||||
r.push("/tmp");
|
||||
r.push("media");
|
||||
// r.push(base64::encode_config(key, base64::URL_SAFE_NO_PAD));
|
||||
// use the sha256 hash of the key as the file name instead of the key itself
|
||||
// this is because the base64 encoded key can be longer than 255 characters.
|
||||
r.push(general_purpose::URL_SAFE_NO_PAD.encode(sha2::Sha256::digest(&key)));
|
||||
// Check that the file path is not longer than 255 characters
|
||||
// (255 is the maximum length of a file path on most file systems)
|
||||
assert!(
|
||||
r.to_str().unwrap().len() <= 255,
|
||||
"File path is too long: {}",
|
||||
r.to_str().unwrap().len()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue