mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 01:16:31 +03:00
Fix long filenames containing dots (#3098)
This commit is contained in:
@@ -18,6 +18,8 @@
|
|||||||
- keep track of securejoin joiner status in database to survive restarts #2920
|
- keep track of securejoin joiner status in database to survive restarts #2920
|
||||||
- remove never used `SentboxMove` option #3111
|
- remove never used `SentboxMove` option #3111
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix a bug where sometimes the file extension of a long filename containing a dot was cropped #3098
|
||||||
|
|
||||||
## 1.76.0
|
## 1.76.0
|
||||||
|
|
||||||
|
|||||||
19
src/blob.rs
19
src/blob.rs
@@ -345,13 +345,30 @@ impl<'a> BlobObject<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let clean = sanitize_filename::sanitize_with_options(name, opts);
|
let clean = sanitize_filename::sanitize_with_options(name, opts);
|
||||||
|
// Let's take the tricky filename
|
||||||
|
// "file.with_lots_of_characters_behind_point_and_double_ending.tar.gz" as an example.
|
||||||
|
// Split it into "file" and "with_lots_of_characters_behind_point_and_double_ending.tar.gz":
|
||||||
let mut iter = clean.splitn(2, '.');
|
let mut iter = clean.splitn(2, '.');
|
||||||
|
|
||||||
let stem: String = iter.next().unwrap_or_default().chars().take(64).collect();
|
let stem: String = iter.next().unwrap_or_default().chars().take(64).collect();
|
||||||
let ext: String = iter.next().unwrap_or_default().chars().take(32).collect();
|
// stem == "file"
|
||||||
|
|
||||||
|
let ext_chars = iter.next().unwrap_or_default().chars();
|
||||||
|
let ext: String = ext_chars
|
||||||
|
.rev()
|
||||||
|
.take(32)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.collect();
|
||||||
|
// ext == "d_point_and_double_ending.tar.gz"
|
||||||
|
|
||||||
if ext.is_empty() {
|
if ext.is_empty() {
|
||||||
(stem, "".to_string())
|
(stem, "".to_string())
|
||||||
} else {
|
} else {
|
||||||
(stem, format!(".{}", ext).to_lowercase())
|
(stem, format!(".{}", ext).to_lowercase())
|
||||||
|
// Return ("file", ".d_point_and_double_ending.tar.gz")
|
||||||
|
// which is not perfect but acceptable.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2333,6 +2333,9 @@ async fn add_or_lookup_contact_by_addr(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
use async_std::fs::{self, File};
|
||||||
|
use async_std::io::WriteExt;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::chat::get_chat_contacts;
|
use crate::chat::get_chat_contacts;
|
||||||
@@ -2340,7 +2343,7 @@ mod tests {
|
|||||||
use crate::chatlist::Chatlist;
|
use crate::chatlist::Chatlist;
|
||||||
use crate::constants::{DC_CONTACT_ID_INFO, DC_GCL_NO_SPECIALS};
|
use crate::constants::{DC_CONTACT_ID_INFO, DC_GCL_NO_SPECIALS};
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::test_utils::{get_chat_msg, TestContext};
|
use crate::test_utils::{get_chat_msg, TestContext, TestContextManager};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hex_hash() {
|
fn test_hex_hash() {
|
||||||
@@ -4968,4 +4971,59 @@ Reply from different address
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_long_filenames() -> Result<()> {
|
||||||
|
let mut tcm = TestContextManager::new().await;
|
||||||
|
let alice = tcm.alice().await;
|
||||||
|
let bob = tcm.bob().await;
|
||||||
|
|
||||||
|
for filename_sent in &[
|
||||||
|
"foo.bar very long file name test baz.tar.gz",
|
||||||
|
"foobarabababababababbababababverylongfilenametestbaz.tar.gz",
|
||||||
|
"fooo...tar.gz",
|
||||||
|
"foo. .tar.gz",
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.tar.gz",
|
||||||
|
"a.tar.gz",
|
||||||
|
"a.a..a.a.a.a.tar.gz",
|
||||||
|
] {
|
||||||
|
let attachment = alice.blobdir.join(filename_sent);
|
||||||
|
let content = format!("File content of {}", filename_sent);
|
||||||
|
File::create(&attachment)
|
||||||
|
.await?
|
||||||
|
.write_all(content.as_bytes())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut msg_alice = Message::new(Viewtype::File);
|
||||||
|
msg_alice.set_file(attachment.to_str().unwrap(), None);
|
||||||
|
let alice_chat = alice.create_chat(&bob).await;
|
||||||
|
let sent = alice.send_msg(alice_chat.id, &mut msg_alice).await;
|
||||||
|
println!("{}", sent.payload());
|
||||||
|
|
||||||
|
bob.recv_msg(&sent).await;
|
||||||
|
let msg_bob = bob.get_last_msg().await;
|
||||||
|
|
||||||
|
async fn check_message(msg: &Message, t: &TestContext, content: &str) {
|
||||||
|
assert_eq!(msg.get_viewtype(), Viewtype::File);
|
||||||
|
let resulting_filename = msg.get_filename().unwrap();
|
||||||
|
let path = msg.get_file(t).unwrap();
|
||||||
|
assert!(
|
||||||
|
resulting_filename.ends_with(".tar.gz"),
|
||||||
|
"{:?} doesn't end with .tar.gz, path: {:?}",
|
||||||
|
resulting_filename,
|
||||||
|
path
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
path.to_str().unwrap().ends_with(".tar.gz"),
|
||||||
|
"path {:?} doesn't end with .tar.gz",
|
||||||
|
path
|
||||||
|
);
|
||||||
|
assert_eq!(fs::read_to_string(path).await.unwrap(), content);
|
||||||
|
}
|
||||||
|
check_message(&msg_alice, &alice, &content).await;
|
||||||
|
check_message(&msg_bob, &bob, &content).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user