Compare commits
No commits in common. "5f4be9809a5f9a3e55d62a61450a554927aed327" and "9871fc3774b6d55806d5074b7f8ba995e2161909" have entirely different histories.
5f4be9809a
...
9871fc3774
7 changed files with 10 additions and 237 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -1196,7 +1196,6 @@ dependencies = [
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
"sodiumoxide",
|
"sodiumoxide",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tempfile",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
@ -1595,15 +1594,6 @@ version = "0.6.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "remove_dir_all"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
|
@ -2149,20 +2139,6 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tempfile"
|
|
||||||
version = "3.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"rand",
|
|
||||||
"redox_syscall",
|
|
||||||
"remove_dir_all",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
|
|
@ -48,6 +48,3 @@ url = { version = "2", features = [ "serde" ] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen = "5"
|
vergen = "5"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tempfile = "3"
|
|
87
src/cache/compat.rs
vendored
87
src/cache/compat.rs
vendored
|
@ -1,87 +0,0 @@
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use chrono::{DateTime, FixedOffset};
|
|
||||||
use serde::{
|
|
||||||
de::{Unexpected, Visitor},
|
|
||||||
Deserialize, Serialize,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::ImageContentType;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
|
||||||
pub(crate) struct LegacyImageMetadata {
|
|
||||||
pub(crate) content_type: Option<LegacyImageContentType>,
|
|
||||||
pub(crate) size: Option<u32>,
|
|
||||||
pub(crate) last_modified: Option<LegacyDateTime>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize)]
|
|
||||||
pub(crate) struct LegacyDateTime(pub DateTime<FixedOffset>);
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for LegacyDateTime {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct LegacyDateTimeVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for LegacyDateTimeVisitor {
|
|
||||||
type Value = LegacyDateTime;
|
|
||||||
|
|
||||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(f, "a valid image type")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
DateTime::parse_from_rfc2822(v)
|
|
||||||
.map(LegacyDateTime)
|
|
||||||
.map_err(|_| E::invalid_value(Unexpected::Str(v), &"a valid image type"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_str(LegacyDateTimeVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub(crate) struct LegacyImageContentType(pub ImageContentType);
|
|
||||||
|
|
||||||
impl Serialize for LegacyImageContentType {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(self.0.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for LegacyImageContentType {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct LegacyImageContentTypeVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for LegacyImageContentTypeVisitor {
|
|
||||||
type Value = LegacyImageContentType;
|
|
||||||
|
|
||||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(f, "a valid image type")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
ImageContentType::from_str(v)
|
|
||||||
.map(LegacyImageContentType)
|
|
||||||
.map_err(|_| E::invalid_value(Unexpected::Str(v), &"a valid image type"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_str(LegacyImageContentTypeVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
2
src/cache/disk.rs
vendored
2
src/cache/disk.rs
vendored
|
@ -197,7 +197,7 @@ impl Cache for DiskCache {
|
||||||
|
|
||||||
tokio::spawn(async move { channel.send(DbMessage::Get(path_0)).await });
|
tokio::spawn(async move { channel.send(DbMessage::Get(path_0)).await });
|
||||||
|
|
||||||
super::fs::read_file_from_path(&path).await.map(|res| {
|
super::fs::read_file(&path).await.map(|res| {
|
||||||
let (inner, maybe_header, metadata) = res?;
|
let (inner, maybe_header, metadata) = res?;
|
||||||
CacheStream::new(inner, maybe_header)
|
CacheStream::new(inner, maybe_header)
|
||||||
.map(|stream| (stream, metadata))
|
.map(|stream| (stream, metadata))
|
||||||
|
|
110
src/cache/fs.rs
vendored
110
src/cache/fs.rs
vendored
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::io::{Seek, SeekFrom};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
@ -34,7 +33,6 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||||
|
|
||||||
use super::compat::LegacyImageMetadata;
|
|
||||||
use super::{CacheKey, ImageMetadata, InnerStream, ENCRYPTION_KEY};
|
use super::{CacheKey, ImageMetadata, InnerStream, ENCRYPTION_KEY};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -46,30 +44,14 @@ pub enum OnDiskMetadata {
|
||||||
/// Attempts to lookup the file on disk, returning a byte stream if it exists.
|
/// Attempts to lookup the file on disk, returning a byte stream if it exists.
|
||||||
/// Note that this could return two types of streams, depending on if the file
|
/// Note that this could return two types of streams, depending on if the file
|
||||||
/// is in progress of being written to.
|
/// is in progress of being written to.
|
||||||
#[inline]
|
pub(super) async fn read_file(
|
||||||
pub(super) async fn read_file_from_path(
|
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Option<Result<(InnerStream, Option<Header>, ImageMetadata), std::io::Error>> {
|
) -> Option<Result<(InnerStream, Option<Header>, ImageMetadata), std::io::Error>> {
|
||||||
read_file(std::fs::File::open(path).ok()?).await
|
let file = std::fs::File::open(path).ok()?;
|
||||||
}
|
let file_0 = file.try_clone().unwrap();
|
||||||
|
|
||||||
async fn read_file(
|
|
||||||
file: std::fs::File,
|
|
||||||
) -> Option<Result<(InnerStream, Option<Header>, ImageMetadata), std::io::Error>> {
|
|
||||||
let mut file_0 = file.try_clone().unwrap();
|
|
||||||
let file_1 = file.try_clone().unwrap();
|
|
||||||
|
|
||||||
// Try reading decrypted header first...
|
// Try reading decrypted header first...
|
||||||
let mut deserializer = serde_json::Deserializer::from_reader(file);
|
let mut deserializer = serde_json::Deserializer::from_reader(file);
|
||||||
let mut maybe_metadata = ImageMetadata::deserialize(&mut deserializer);
|
let maybe_metadata = ImageMetadata::deserialize(&mut deserializer);
|
||||||
|
|
||||||
// Failed to parse normally, see if we have a legacy file format
|
|
||||||
if maybe_metadata.is_err() {
|
|
||||||
file_0.seek(SeekFrom::Start(2)).ok()?;
|
|
||||||
let mut deserializer = serde_json::Deserializer::from_reader(file_0);
|
|
||||||
maybe_metadata =
|
|
||||||
LegacyImageMetadata::deserialize(&mut deserializer).map(LegacyImageMetadata::into);
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed_metadata;
|
let parsed_metadata;
|
||||||
let mut maybe_header = None;
|
let mut maybe_header = None;
|
||||||
|
@ -83,11 +65,11 @@ async fn read_file(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
reader = Some(Box::pin(File::from_std(file_1)));
|
reader = Some(Box::pin(File::from_std(file_0)));
|
||||||
parsed_metadata = Some(metadata);
|
parsed_metadata = Some(metadata);
|
||||||
debug!("Found not encrypted file");
|
debug!("Found not encrypted file");
|
||||||
} else {
|
} else {
|
||||||
let mut file = File::from_std(file_1);
|
let mut file = File::from_std(file_0);
|
||||||
let file_0 = file.try_clone().await.unwrap();
|
let file_0 = file.try_clone().await.unwrap();
|
||||||
|
|
||||||
// image is encrypted or corrupt
|
// image is encrypted or corrupt
|
||||||
|
@ -361,7 +343,7 @@ impl AsyncWrite for EncryptedDiskWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents some upstream error.
|
/// Represents some upstream error.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug)]
|
||||||
pub struct UpstreamError;
|
pub struct UpstreamError;
|
||||||
|
|
||||||
impl Error for UpstreamError {}
|
impl Error for UpstreamError {}
|
||||||
|
@ -378,81 +360,3 @@ impl From<UpstreamError> for actix_web::Error {
|
||||||
PayloadError::Incomplete(None).into()
|
PayloadError::Incomplete(None).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod read_file {
|
|
||||||
use crate::cache::{ImageContentType, ImageMetadata};
|
|
||||||
|
|
||||||
use super::read_file;
|
|
||||||
use bytes::Bytes;
|
|
||||||
use chrono::DateTime;
|
|
||||||
use futures::StreamExt;
|
|
||||||
use std::io::{Seek, SeekFrom, Write};
|
|
||||||
use tempfile::tempfile;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn can_read() {
|
|
||||||
let mut temp_file = tempfile().unwrap();
|
|
||||||
temp_file
|
|
||||||
.write_all(
|
|
||||||
br#"{"content_type":0,"content_length":708370,"last_modified":"2021-04-13T04:37:41+00:00"}abc"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
temp_file.seek(SeekFrom::Start(0)).unwrap();
|
|
||||||
|
|
||||||
let (inner_stream, maybe_header, metadata) = read_file(temp_file).await.unwrap().unwrap();
|
|
||||||
|
|
||||||
let foo: Vec<_> = inner_stream.collect().await;
|
|
||||||
assert_eq!(foo, vec![Ok(Bytes::from("abc"))]);
|
|
||||||
assert!(maybe_header.is_none());
|
|
||||||
assert_eq!(
|
|
||||||
metadata,
|
|
||||||
ImageMetadata {
|
|
||||||
content_length: Some(708370),
|
|
||||||
content_type: Some(ImageContentType::Png),
|
|
||||||
last_modified: Some(
|
|
||||||
DateTime::parse_from_rfc3339("2021-04-13T04:37:41+00:00").unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod read_file_compat {
|
|
||||||
use crate::cache::{ImageContentType, ImageMetadata};
|
|
||||||
|
|
||||||
use super::read_file;
|
|
||||||
use bytes::Bytes;
|
|
||||||
use chrono::DateTime;
|
|
||||||
use futures::StreamExt;
|
|
||||||
use std::io::{Seek, SeekFrom, Write};
|
|
||||||
use tempfile::tempfile;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn can_read_legacy() {
|
|
||||||
let mut temp_file = tempfile().unwrap();
|
|
||||||
temp_file
|
|
||||||
.write_all(
|
|
||||||
b"\x00\x5b{\"content_type\":\"image/jpeg\",\"last_modified\":\"Sat, 10 Apr 2021 10:55:22 GMT\",\"size\":117888}abc",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
temp_file.seek(SeekFrom::Start(0)).unwrap();
|
|
||||||
|
|
||||||
let (inner_stream, maybe_header, metadata) = read_file(temp_file).await.unwrap().unwrap();
|
|
||||||
|
|
||||||
let foo: Vec<_> = inner_stream.collect().await;
|
|
||||||
assert_eq!(foo, vec![Ok(Bytes::from("abc"))]);
|
|
||||||
assert!(maybe_header.is_none());
|
|
||||||
assert_eq!(
|
|
||||||
metadata,
|
|
||||||
ImageMetadata {
|
|
||||||
content_length: Some(117888),
|
|
||||||
content_type: Some(ImageContentType::Jpeg),
|
|
||||||
last_modified: Some(
|
|
||||||
DateTime::parse_from_rfc2822("Sat, 10 Apr 2021 10:55:22 GMT").unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
17
src/cache/mod.rs
vendored
17
src/cache/mod.rs
vendored
|
@ -23,11 +23,8 @@ pub use disk::DiskCache;
|
||||||
pub use fs::UpstreamError;
|
pub use fs::UpstreamError;
|
||||||
pub use mem::MemoryCache;
|
pub use mem::MemoryCache;
|
||||||
|
|
||||||
use self::compat::LegacyImageMetadata;
|
|
||||||
|
|
||||||
pub static ENCRYPTION_KEY: OnceCell<Key> = OnceCell::new();
|
pub static ENCRYPTION_KEY: OnceCell<Key> = OnceCell::new();
|
||||||
|
|
||||||
mod compat;
|
|
||||||
mod disk;
|
mod disk;
|
||||||
mod fs;
|
mod fs;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
|
@ -62,7 +59,7 @@ impl From<&CacheKey> for PathBuf {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CachedImage(pub Bytes);
|
pub struct CachedImage(pub Bytes);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct ImageMetadata {
|
pub struct ImageMetadata {
|
||||||
pub content_type: Option<ImageContentType>,
|
pub content_type: Option<ImageContentType>,
|
||||||
pub content_length: Option<u32>,
|
pub content_length: Option<u32>,
|
||||||
|
@ -70,7 +67,7 @@ pub struct ImageMetadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirmed by Ply to be these types: https://link.eddie.sh/ZXfk0
|
// Confirmed by Ply to be these types: https://link.eddie.sh/ZXfk0
|
||||||
#[derive(Copy, Clone, Serialize_repr, Deserialize_repr, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Serialize_repr, Deserialize_repr)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum ImageContentType {
|
pub enum ImageContentType {
|
||||||
Png = 0,
|
Png = 0,
|
||||||
|
@ -105,16 +102,6 @@ impl AsRef<str> for ImageContentType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LegacyImageMetadata> for ImageMetadata {
|
|
||||||
fn from(legacy: LegacyImageMetadata) -> Self {
|
|
||||||
Self {
|
|
||||||
content_type: legacy.content_type.map(|v| v.0),
|
|
||||||
content_length: legacy.size,
|
|
||||||
last_modified: legacy.last_modified.map(|v| v.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::pub_enum_variant_names)]
|
#[allow(clippy::pub_enum_variant_names)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ImageRequestError {
|
pub enum ImageRequestError {
|
||||||
|
|
|
@ -251,10 +251,6 @@ fn print_preamble_and_warnings(args: &Config) -> Result<(), Box<dyn Error>> {
|
||||||
". If not, see <https://www.gnu.org/licenses/>.\n"
|
". If not, see <https://www.gnu.org/licenses/>.\n"
|
||||||
));
|
));
|
||||||
|
|
||||||
if args.ephemeral_disk_encryption {
|
|
||||||
error!("Encrypted files are _very_ broken; caveat emptor!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if !args.unstable_options.is_empty() {
|
if !args.unstable_options.is_empty() {
|
||||||
warn!("Unstable options are enabled. These options should not be used in production!");
|
warn!("Unstable options are enabled. These options should not be used in production!");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue