sqlx_core_oldapi/postgres/message/
password.rs1use std::fmt::Write;
2
3use md5::{Digest, Md5};
4
5use crate::io::{BufMutExt, Encode};
6use crate::postgres::io::PgBufMutExt;
7
8#[derive(Debug)]
9pub enum Password<'a> {
10 Cleartext(&'a str),
11
12 Md5 {
13 password: &'a str,
14 username: &'a str,
15 salt: [u8; 4],
16 },
17}
18
19impl Password<'_> {
20 #[inline]
21 fn len(&self) -> usize {
22 match self {
23 Password::Cleartext(s) => s.len() + 5,
24 Password::Md5 { .. } => 35 + 5,
25 }
26 }
27}
28
29impl Encode<'_> for Password<'_> {
30 fn encode_with(&self, buf: &mut Vec<u8>, _: ()) {
31 buf.reserve(1 + 4 + self.len());
32 buf.push(b'p');
33
34 buf.put_length_prefixed(|buf| {
35 match self {
36 Password::Cleartext(password) => {
37 buf.put_str_nul(password);
38 }
39
40 Password::Md5 {
41 username,
42 password,
43 salt,
44 } => {
45 let mut hasher = Md5::new();
51
52 hasher.update(password);
53 hasher.update(username);
54
55 let mut output = String::with_capacity(35);
56
57 let _ = write!(output, "{:x}", hasher.finalize_reset());
58
59 hasher.update(&output);
60 hasher.update(salt);
61
62 output.clear();
63
64 let _ = write!(output, "md5{:x}", hasher.finalize());
65
66 buf.put_str_nul(&output);
67 }
68 }
69 });
70 }
71}
72
73#[test]
74fn test_encode_clear_password() {
75 const EXPECTED: &[u8] = b"p\0\0\0\rpassword\0";
76
77 let mut buf = Vec::new();
78 let m = Password::Cleartext("password");
79
80 m.encode(&mut buf);
81
82 assert_eq!(buf, EXPECTED);
83}
84
85#[test]
86fn test_encode_md5_password() {
87 const EXPECTED: &[u8] = b"p\0\0\0(md53e2c9d99d49b201ef867a36f3f9ed62c\0";
88
89 let mut buf = Vec::new();
90 let m = Password::Md5 {
91 password: "password",
92 username: "root",
93 salt: [147, 24, 57, 152],
94 };
95
96 m.encode(&mut buf);
97
98 assert_eq!(buf, EXPECTED);
99}
100
101#[cfg(all(test, not(debug_assertions)))]
102#[bench]
103fn bench_encode_clear_password(b: &mut test::Bencher) {
104 use test::black_box;
105
106 let mut buf = Vec::with_capacity(128);
107
108 b.iter(|| {
109 buf.clear();
110
111 black_box(Password::Cleartext("password")).encode(&mut buf);
112 });
113}
114
115#[cfg(all(test, not(debug_assertions)))]
116#[bench]
117fn bench_encode_md5_password(b: &mut test::Bencher) {
118 use test::black_box;
119
120 let mut buf = Vec::with_capacity(128);
121
122 b.iter(|| {
123 buf.clear();
124
125 black_box(Password::Md5 {
126 password: "password",
127 username: "root",
128 salt: [147, 24, 57, 152],
129 })
130 .encode(&mut buf);
131 });
132}