diff --git a/mason-postgres-protocol/Cargo.toml b/mason-postgres-protocol/Cargo.toml index f9b2798c..0dcc2cf1 100644 --- a/mason-postgres-protocol/Cargo.toml +++ b/mason-postgres-protocol/Cargo.toml @@ -12,6 +12,7 @@ bytes = "0.4.12" memchr = "2.2.0" md-5 = "0.8.0" itoa = "0.4.4" +hex = "0.3.2" [dev-dependencies] matches = "0.1.8" diff --git a/mason-postgres-protocol/src/lib.rs b/mason-postgres-protocol/src/lib.rs index af18285a..c52bb4ac 100644 --- a/mason-postgres-protocol/src/lib.rs +++ b/mason-postgres-protocol/src/lib.rs @@ -5,17 +5,17 @@ mod backend_key_data; mod decode; mod encode; mod message; +mod password_message; mod ready_for_query; mod response; mod startup_message; -mod password_message; pub use self::{ decode::Decode, encode::Encode, message::Message, + password_message::PasswordMessage, ready_for_query::{ReadyForQuery, TransactionStatus}, response::{Response, ResponseBuilder, Severity}, startup_message::StartupMessage, - password_message::PasswordMessage, }; diff --git a/mason-postgres-protocol/src/password_message.rs b/mason-postgres-protocol/src/password_message.rs index 60e4e90d..2d1b7c3d 100644 --- a/mason-postgres-protocol/src/password_message.rs +++ b/mason-postgres-protocol/src/password_message.rs @@ -1,20 +1,30 @@ +use crate::{Decode, Encode}; use bytes::Bytes; +use md5::{Digest, Md5}; use std::io; -use crate::{Encode, Decode}; pub struct PasswordMessage { password: Bytes, } impl PasswordMessage { - pub fn cleartext(s: impl AsRef) -> Self { - // TODO - unimplemented!() + /// Create a `PasswordMessage` with an unecrypted password. + pub fn cleartext(password: impl AsRef) -> Self { + Self { password: Bytes::from(password.as_ref()) } } - pub fn md5(s: impl AsRef) -> Self { - // TODO - unimplemented!() + /// Create a `PasswordMessage` by hasing the password, user, and salt together using MD5. + pub fn md5(password: impl AsRef, user: impl AsRef, salt: &[u8; 4]) -> Self { + let credentials = + hex::encode(Md5::new().chain(password.as_ref()).chain(user.as_ref()).result()); + + let salted = hex::encode(Md5::new().chain(credentials).chain(salt).result()); + + let mut password = Vec::with_capacity(3 + salted.len()); + password.copy_from_slice(b"md5"); + password.copy_from_slice(salted.as_bytes()); + + Self { password: Bytes::from(password) } } /// The password (encrypted, if requested). @@ -24,8 +34,10 @@ impl PasswordMessage { } impl Decode for PasswordMessage { - fn decode(src: Bytes) -> io::Result where - Self: Sized { + fn decode(src: Bytes) -> io::Result + where + Self: Sized, + { // There is only one field, the password, and it's not like we can // decrypt it if it was encrypted Ok(PasswordMessage { password: src }) @@ -39,7 +51,7 @@ impl Encode for PasswordMessage { fn encode(&self, buf: &mut Vec) -> io::Result<()> { buf.push(b'p'); - buf.copy_from_slice((self.password.len() + 4).to_be_bytes()); + buf.copy_from_slice(&(self.password.len() + 4).to_be_bytes()); buf.copy_from_slice(&self.password); Ok(()) diff --git a/mason-postgres-protocol/src/startup_message.rs b/mason-postgres-protocol/src/startup_message.rs index a0119466..92b2790d 100644 --- a/mason-postgres-protocol/src/startup_message.rs +++ b/mason-postgres-protocol/src/startup_message.rs @@ -1,6 +1,6 @@ +use crate::{Decode, Encode}; use bytes::Bytes; use std::io; -use crate::{Encode, Decode}; pub struct StartupMessage { version: u32,