diff --git a/src/auth.rs b/src/auth.rs index 697eff3..31b8206 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -24,10 +24,18 @@ use crate::login::ArcLoginProvider; /// S: DONE /// C: VERSION 1 2 /// C: CPID 1 +/// /// C: AUTH 2 PLAIN service=smtp /// S: CONT 2 /// C: CONT 2 base64stringFollowingRFC4616== /// S: OK 2 user=alice@example.tld +/// +/// C: AUTH 42 LOGIN service=smtp +/// S: CONT 42 VXNlcm5hbWU6 +/// C: CONT 42 b64User +/// S: CONT 42 UGFzc3dvcmQ6 +/// C: CONT 42 b64Pass +/// S: FAIL 42 user=alice /// ``` /// /// ## RFC References @@ -698,6 +706,44 @@ fn lf_enc(out: &mut BytesMut) { out.put(&[0x0A][..]) } +impl Encode for Mechanism { + fn encode(&self, out: &mut BytesMut) -> Result<()> { + match self { + Self::Plain => out.put(&b"PLAIN"[..]), + Self::Login => out.put(&b"LOGIN"[..]), + } + Ok(()) + } +} + +impl Encode for MechanismParameters { + fn encode(&self, out: &mut BytesMut) -> Result<()> { + match self { + Self::Anonymous => out.put(&b"anonymous"[..]), + Self::PlainText => out.put(&b"plaintext"[..]), + Self::Dictionary => out.put(&b"dictionary"[..]), + Self::Active => out.put(&b"active"[..]), + Self::ForwardSecrecy => out.put(&b"forward-secrecy"[..]), + Self::MutualAuth => out.put(&b"mutual-auth"[..]), + Self::Private => out.put(&b"private"[..]), + } + Ok(()) + } +} + + +impl Encode for FailCode { + fn encode(&self, out: &mut BytesMut) -> Result<()> { + match self { + Self::TempFail => out.put(&b"temp_fail"[..]), + Self::AuthzFail => out.put(&b"authz_fail"[..]), + Self::UserDisabled => out.put(&b"user_disabled"[..]), + Self::PassExpired => out.put(&b"pass_expired"[..]), + }; + Ok(()) + } +} + impl Encode for ServerCommand { fn encode(&self, out: &mut BytesMut) -> Result<()> { match self { @@ -709,14 +755,85 @@ impl Encode for ServerCommand { out.put(minor.to_string().as_bytes()); lf_enc(out); }, - Self::Spid(v) => unimplemented!(), - Self::Cuid(v) => unimplemented!(), - Self::Mech { kind, parameters } => unimplemented!(), - Self::Cookie(v) => unimplemented!(), - Self::Done => unimplemented!(), - Self::Cont { id, data } => unimplemented!(), - Self::Ok { id, user_id, extra_parameters } => unimplemented!(), - Self::Fail {id, user_id, code, extra_parameters } => unimplemented!(), + Self::Spid(pid) => { + out.put(&b"SPID"[..]); + tab_enc(out); + out.put(pid.to_string().as_bytes()); + lf_enc(out); + }, + Self::Cuid(pid) => { + out.put(&b"CUID"[..]); + tab_enc(out); + out.put(pid.to_string().as_bytes()); + lf_enc(out); + }, + Self::Cookie(cval) => { + out.put(&b"COOKIE"[..]); + tab_enc(out); + out.put(hex::encode(cval).as_bytes()); + lf_enc(out); + + }, + Self::Mech { kind, parameters } => { + out.put(&b"MECH"[..]); + tab_enc(out); + kind.encode(out)?; + for p in parameters.iter() { + tab_enc(out); + p.encode(out)?; + } + lf_enc(out); + }, + Self::Done => { + out.put(&b"DONE"[..]); + lf_enc(out); + }, + Self::Cont { id, data } => { + out.put(&b"CONT"[..]); + tab_enc(out); + out.put(id.to_string().as_bytes()); + if let Some(rdata) = data { + tab_enc(out); + let b64 = base64::engine::general_purpose::STANDARD.encode(rdata); + out.put(b64.as_bytes()); + } + lf_enc(out); + }, + Self::Ok { id, user_id, extra_parameters } => { + out.put(&b"OK"[..]); + tab_enc(out); + out.put(id.to_string().as_bytes()); + if let Some(user) = user_id { + tab_enc(out); + out.put(&b"user="[..]); + out.put(user.as_bytes()); + } + for p in extra_parameters.iter() { + tab_enc(out); + out.put(&p[..]); + } + lf_enc(out); + }, + Self::Fail {id, user_id, code, extra_parameters } => { + out.put(&b"FAIL"[..]); + tab_enc(out); + out.put(id.to_string().as_bytes()); + if let Some(user) = user_id { + tab_enc(out); + out.put(&b"user="[..]); + out.put(user.as_bytes()); + } + if let Some(code_val) = code { + tab_enc(out); + out.put(&b"code="[..]); + code_val.encode(out)?; + } + for p in extra_parameters.iter() { + tab_enc(out); + out.put(&p[..]); + } + lf_enc(out); + }, } Ok(()) }