1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use std::fmt::{self, Display};
use std::sync::Arc;
use std::error::{Error as ErrorTrait};
use base64::encode;
use ::{ExecFuture, Cmd, EhloData, Io};
use ::error::MissingCapabilities;
use super::validate_auth_capability;
#[derive(Debug, Clone)]
pub struct Plain {
authorization_identity: String,
authentication_identity: String,
password: String
}
impl Plain {
pub fn from_username<I1, I2>(user: I1, password: I2) -> Result<Self, NullCodePointError>
where I1: Into<String> + AsRef<str>, I2: Into<String> + AsRef<str>
{
validate_no_null_cps(&user)?;
validate_no_null_cps(&password)?;
let user = user.into();
Ok(Plain {
authentication_identity: user.clone(),
authorization_identity: user,
password: password.into()
})
}
pub fn new<I1,I2,I3>(
authorization_identity: I1,
authentication_identity: I2,
password: I3
) -> Result<Self, NullCodePointError>
where I1: Into<String> + AsRef<str>,
I2: Into<String> + AsRef<str>,
I3: Into<String> + AsRef<str>
{
validate_no_null_cps(&authorization_identity)?;
validate_no_null_cps(&authentication_identity)?;
validate_no_null_cps(&password)?;
Ok(Plain {
authentication_identity: authentication_identity.into(),
authorization_identity: authorization_identity.into(),
password: password.into()
})
}
pub fn authorization_identity(&self) -> &str {
&self.authorization_identity
}
pub fn authentication_identity(&self) -> &str {
&self.authentication_identity
}
fn exec_ref(&self, io: Io) -> ExecFuture {
let auth_str = encode(&format!("{}\0{}\0{}",
&self.authorization_identity,
&self.authentication_identity,
&self.password));
io.exec_simple_cmd(&["AUTH PLAIN ", auth_str.as_str()])
}
}
impl Cmd for Plain {
fn check_cmd_availability(&self, caps: Option<&EhloData>)
-> Result<(), MissingCapabilities>
{
validate_auth_capability(caps, "PLAIN")
}
fn exec(self, con: Io) -> ExecFuture {
self.exec_ref(con)
}
}
impl Cmd for Arc<Plain> {
fn check_cmd_availability(&self, caps: Option<&EhloData>)
-> Result<(), MissingCapabilities>
{
let me: &Plain = &*self;
me.check_cmd_availability(caps)
}
fn exec(self, con: Io) -> ExecFuture {
self.exec_ref(con)
}
}
fn validate_no_null_cps<R>(inp: R) -> Result<(), NullCodePointError>
where R: AsRef<str>
{
for bch in inp.as_ref().bytes() {
if bch == b'\0' {
return Err(NullCodePointError)
}
}
Ok(())
}
#[derive(Copy, Clone, Debug)]
pub struct NullCodePointError;
impl Display for NullCodePointError {
fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
fter.write_str(self.description())
}
}
impl ErrorTrait for NullCodePointError {
fn description(&self) -> &str {
"input (username/password) contained null byte"
}
fn cause(&self) -> Option<&ErrorTrait> {
None
}
}