sqlx_mysql/protocol/connect/
auth_switch.rsuse bytes::{Buf, Bytes};
use crate::error::Error;
use crate::io::ProtocolEncode;
use crate::io::{BufExt, ProtocolDecode};
use crate::protocol::auth::AuthPlugin;
use crate::protocol::Capabilities;
#[derive(Debug)]
pub struct AuthSwitchRequest {
pub plugin: AuthPlugin,
pub data: Bytes,
}
impl ProtocolDecode<'_, bool> for AuthSwitchRequest {
fn decode_with(mut buf: Bytes, enable_cleartext_plugin: bool) -> Result<Self, Error> {
let header = buf.get_u8();
if header != 0xfe {
return Err(err_protocol!(
"expected 0xfe (AUTH_SWITCH) but found 0x{:x}",
header
));
}
let plugin = buf.get_str_nul()?.parse()?;
if matches!(plugin, AuthPlugin::MySqlClearPassword) && !enable_cleartext_plugin {
return Err(err_protocol!("mysql_cleartext_plugin disabled"));
}
if matches!(plugin, AuthPlugin::MySqlClearPassword) && buf.is_empty() {
return Ok(Self {
plugin,
data: Bytes::new(),
});
}
if buf.len() != 21 {
return Err(err_protocol!(
"expected 21 bytes but found {} bytes",
buf.len()
));
}
let data = buf.get_bytes(20);
buf.advance(1); Ok(Self { plugin, data })
}
}
#[derive(Debug)]
pub struct AuthSwitchResponse(pub Vec<u8>);
impl ProtocolEncode<'_, Capabilities> for AuthSwitchResponse {
fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), Error> {
buf.extend_from_slice(&self.0);
Ok(())
}
}
#[test]
fn test_decode_auth_switch_packet_data() {
const AUTH_SWITCH_NO_DATA: &[u8] = b"\xfecaching_sha2_password\x00abcdefghijabcdefghij\x00";
let p = AuthSwitchRequest::decode_with(AUTH_SWITCH_NO_DATA.into(), true).unwrap();
assert!(matches!(p.plugin, AuthPlugin::CachingSha2Password));
assert_eq!(p.data, &b"abcdefghijabcdefghij"[..]);
}
#[test]
fn test_decode_auth_switch_cleartext_disabled() {
const AUTH_SWITCH_CLEARTEXT: &[u8] = b"\xfemysql_clear_password\x00abcdefghijabcdefghij\x00";
let e = AuthSwitchRequest::decode_with(AUTH_SWITCH_CLEARTEXT.into(), false).unwrap_err();
let e_str = e.to_string();
let expected = "encountered unexpected or invalid data: mysql_cleartext_plugin disabled";
assert!(
e_str.starts_with(expected),
"expected error string to start with {expected:?}, got {e_str:?}"
);
}
#[test]
fn test_decode_auth_switch_packet_no_data() {
const AUTH_SWITCH_NO_DATA: &[u8] = b"\xfemysql_clear_password\x00";
let p = AuthSwitchRequest::decode_with(AUTH_SWITCH_NO_DATA.into(), true).unwrap();
assert!(matches!(p.plugin, AuthPlugin::MySqlClearPassword));
assert_eq!(p.data, Bytes::new());
}