fuck gmail + also fix some time stuff found by afl
This commit is contained in:
parent
f35ec53938
commit
77f0184276
8 changed files with 66 additions and 17 deletions
7
Justfile
7
Justfile
|
@ -13,6 +13,13 @@ test:
|
|||
watch:
|
||||
cargo watch -c
|
||||
|
||||
afl-imap:
|
||||
#!/bin/bash
|
||||
cd imap/imap-parsing-fuzz-target
|
||||
pwd
|
||||
cargo afl build
|
||||
cargo afl fuzz -i in -o out target/debug/imap-parsing-fuzz-target
|
||||
|
||||
fuzz-imap:
|
||||
#!/bin/bash
|
||||
cd imap
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
afl:
|
||||
#!/bin/bash
|
||||
cd imap-parsing-fuzz-target
|
||||
pwd
|
||||
cargo afl build
|
||||
cargo afl fuzz -i in -o out target/debug/imap-parsing-fuzz-target
|
1
imap/imap-parsing-fuzz-target/Cargo.lock
generated
1
imap/imap-parsing-fuzz-target/Cargo.lock
generated
|
@ -558,6 +558,7 @@ dependencies = [
|
|||
"format-bytes",
|
||||
"log",
|
||||
"nom",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
1
imap/imap-parsing-fuzz-target/in/response-highestmodseq
Normal file
1
imap/imap-parsing-fuzz-target/in/response-highestmodseq
Normal file
|
@ -0,0 +1 @@
|
|||
* OK [HIGHESTMODSEQ 694968]
|
|
@ -105,7 +105,7 @@ impl<'a> Encoder<&'a TaggedCommand> for ImapCodec {
|
|||
let cmd_bytes = format_bytes!(b"{}", command);
|
||||
dst.extend_from_slice(cmd_bytes.as_slice());
|
||||
|
||||
debug!("C>>>S: {:?}", dst);
|
||||
// debug!("C>>>S: {:?}", dst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ pub enum ResponseCode {
|
|||
Capabilities(Vec<Capability>),
|
||||
HighestModSeq(u64), // RFC 4551, section 3.1.1
|
||||
Parse,
|
||||
PermanentFlags(Vec<Bytes>),
|
||||
PermanentFlags(Vec<Flag>),
|
||||
ReadOnly,
|
||||
ReadWrite,
|
||||
TryCreate,
|
||||
|
@ -319,6 +319,7 @@ pub enum Flag {
|
|||
Recent,
|
||||
Keyword(Atom),
|
||||
Extension(Atom),
|
||||
SpecialCreate,
|
||||
}
|
||||
|
||||
impl DisplayBytes for Flag {
|
||||
|
@ -332,6 +333,7 @@ impl DisplayBytes for Flag {
|
|||
Flag::Recent => write_bytes!(w, b"\\Recent"),
|
||||
Flag::Keyword(atom) => write_bytes!(w, b"{}", atom),
|
||||
Flag::Extension(atom) => write_bytes!(w, b"\\{}", atom),
|
||||
Flag::SpecialCreate => write_bytes!(w, b"\\*"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,9 +134,11 @@ rule!(pub date_time : Timestamp => delimited(DQUOTE,
|
|||
SP,
|
||||
zone,
|
||||
)), |(d, _, m, _, y, _, time, _, zone)| {
|
||||
eprintln!("{}-{}-{} {:?} {:?}", y, m, d, time, zone);
|
||||
zone.ymd(y, m, d)
|
||||
// eprintln!("{}-{}-{} {:?} {:?}", y, m, d, time, zone);
|
||||
zone.ymd_opt(y, m, d)
|
||||
.and_time(time)
|
||||
// TODO: what the hell
|
||||
.earliest()
|
||||
.map(Timestamp)
|
||||
.ok_or_else(|| anyhow!("invalid time"))
|
||||
}),
|
||||
|
@ -196,6 +198,11 @@ rule!(pub flag_keyword : Atom => atom);
|
|||
|
||||
rule!(pub flag_list : Vec<Flag> => paren!(sep_list!(?flag)));
|
||||
|
||||
rule!(pub flag_perm : Flag => alt((
|
||||
flag,
|
||||
map(pair(byte(b'\\'), byte(b'*')), |_| Flag::SpecialCreate),
|
||||
)));
|
||||
|
||||
pub(crate) fn is_list_wildcards(c: u8) -> bool { c == b'%' || c == b'*' }
|
||||
rule!(pub list_wildcards : u8 => satisfy(is_list_wildcards));
|
||||
|
||||
|
@ -332,14 +339,30 @@ rule!(pub resp_cond_state : Condition => map(
|
|||
pub(crate) fn is_resp_specials(c: u8) -> bool { c == b']' }
|
||||
rule!(pub resp_specials : u8 => satisfy(is_resp_specials));
|
||||
|
||||
rule!(pub resp_text : ResponseText => map(pair(
|
||||
opt(terminated(delimited(byte(b'['), resp_text_code, byte(b']')), SP)),
|
||||
text,
|
||||
), |(code, info)| ResponseText { code, info }));
|
||||
rule!(pub resp_text : ResponseText => alt((
|
||||
// FUCK YOU GMAIL
|
||||
map(delimited(byte(b'['), resp_text_code, byte(b']')),
|
||||
|code| ResponseText { code: Some(code), info: Bytes::from(b"") }),
|
||||
|
||||
map(pair(
|
||||
opt(terminated(delimited(byte(b'['), resp_text_code, byte(b']')), SP)),
|
||||
text,
|
||||
), |(code, info)| ResponseText { code, info }),
|
||||
)));
|
||||
|
||||
rule!(pub resp_text_code : ResponseCode => alt((
|
||||
map(tagi(b"ALERT"), |_| ResponseCode::Alert),
|
||||
map(capability_data, ResponseCode::Capabilities),
|
||||
map(tagi(b"PARSE"), |_| ResponseCode::Parse),
|
||||
map(preceded(pair(tagi(b"PERMANENTFLAGS"), SP), paren!(sep_list!(flag_perm))), ResponseCode::PermanentFlags),
|
||||
map(tagi(b"READ-ONLY"), |_| ResponseCode::ReadOnly),
|
||||
map(tagi(b"READ-WRITE"), |_| ResponseCode::ReadWrite),
|
||||
map(tagi(b"TRYCREATE"), |_| ResponseCode::TryCreate),
|
||||
map(preceded(pair(tagi(b"UIDNEXT"), SP), nz_number), ResponseCode::UidNext),
|
||||
map(preceded(pair(tagi(b"UIDVALIDITY"), SP), nz_number), ResponseCode::UidValidity),
|
||||
map(preceded(pair(tagi(b"UNSEEN"), SP), nz_number), ResponseCode::Unseen),
|
||||
map(pair(atom, opt(preceded(SP, map(take_while1(|c| is_text_char(c) && c != b']'), Bytes::from)))),
|
||||
|(a, b)| ResponseCode::Other(a, b)),
|
||||
)));
|
||||
|
||||
rule!(pub string : Bytes => alt((quoted, literal)));
|
||||
|
@ -352,7 +375,7 @@ rule!(pub text : Bytes => map(take_while1(is_text_char), Bytes::from));
|
|||
pub(crate) fn is_text_char(c: u8) -> bool { is_char(c) && !is_cr(c) && !is_lf(c) }
|
||||
rule!(pub TEXT_CHAR : u8 => satisfy(is_text_char));
|
||||
|
||||
rule!(pub time : NaiveTime => map(
|
||||
rule!(pub time : NaiveTime => map_res(
|
||||
tuple((
|
||||
map_res(count(DIGIT, 2), parse_num::<_, u32>),
|
||||
byte(b':'),
|
||||
|
@ -360,7 +383,7 @@ rule!(pub time : NaiveTime => map(
|
|||
byte(b':'),
|
||||
map_res(count(DIGIT, 2), parse_num::<_, u32>),
|
||||
)),
|
||||
|(h, _, m, _, s)| NaiveTime::from_hms(h, m, s)));
|
||||
|(h, _, m, _, s)| NaiveTime::from_hms_opt(h, m, s).ok_or_else(|| anyhow!("invalid time"))));
|
||||
|
||||
rule!(pub uniqueid : u32 => nz_number);
|
||||
|
||||
|
|
|
@ -20,7 +20,11 @@ fn test_literal() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn afl() { let _ = response(Bytes::from(b"* 4544444444 444 ")); }
|
||||
fn from_afl() {
|
||||
let _ = response(Bytes::from(b"* 4544444444 444 "));
|
||||
|
||||
let _ = response(Bytes::from(b"* 8045 FETCH (UID 8225 ENVELOPE (\"Sun, 21 Mar 2021 18:44:10 -0700\" \"SUBJECT\" ((\"SENDER\" NIL \"sender\" \"example.com\")) ((\"SENDER\" NIL \"sender\" \"example.com\")) ((\"norepjy\" NIL \"noreply\" \"example.com\")) ((\"NAME\" NIL \"user\" \"gmail.com\")) NIL NIL NIL \"<Hmple.com>\") FLAGS () INTERNALDATE \"22-Mar-2021 01:64:12 \x7f0000\" RFC822.SIZE 13503)".to_vec()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date() {
|
||||
|
@ -91,3 +95,20 @@ fn test_list() {
|
|||
&*mailbox == &b"Trash"[..]
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gmail_is_shit() {
|
||||
// FUCK YOU GMAIL!
|
||||
let res = response(Bytes::from(b"* OK [HIGHESTMODSEQ 694968]\r\n"))
|
||||
.unwrap()
|
||||
.1;
|
||||
eprintln!("{:?}", res);
|
||||
assert!(matches!(res,
|
||||
Response::Condition(Condition {
|
||||
status: Status::Ok,
|
||||
code: Some(ResponseCode::Other(c, Some(d))),
|
||||
info: e,
|
||||
})
|
||||
if c == Bytes::from(b"HIGHESTMODSEQ") && d == Bytes::from(b"694968") && e.is_empty()
|
||||
));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue