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
use crate::{
serde_str::{deserialize_from_str, serialize_to_str},
Destination,
};
use distant_net::SecretKey32;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use std::{
convert::{TryFrom, TryInto},
fmt, io,
str::FromStr,
};
use uriparse::{URIReference, URI};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DistantSingleKeyCredentials {
pub host: String,
pub port: u16,
pub key: SecretKey32,
pub username: Option<String>,
}
impl fmt::Display for DistantSingleKeyCredentials {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "distant://")?;
if let Some(username) = self.username.as_ref() {
write!(f, "{}", username)?;
}
write!(f, ":{}@{}:{}", self.key, self.host, self.port)
}
}
impl FromStr for DistantSingleKeyCredentials {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from_uri_ref(s, true)
}
}
impl Serialize for DistantSingleKeyCredentials {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_to_str(self, serializer)
}
}
impl<'de> Deserialize<'de> for DistantSingleKeyCredentials {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserialize_from_str(deserializer)
}
}
impl DistantSingleKeyCredentials {
pub fn try_to_destination(&self) -> io::Result<Destination> {
let uri = self.try_to_uri()?;
Destination::try_from(uri.as_uri_reference().to_borrowed())
.map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))
}
pub fn try_to_uri(&self) -> io::Result<URI<'static>> {
let uri_string = self.to_string();
URI::try_from(uri_string.as_str())
.map(URI::into_owned)
.map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))
}
pub fn try_from_uri_ref<'a, E>(
uri_ref: impl TryInto<URIReference<'a>, Error = E>,
require_scheme: bool,
) -> io::Result<Self>
where
E: std::error::Error + Send + Sync + 'static,
{
let uri_ref = uri_ref
.try_into()
.map_err(|x| io::Error::new(io::ErrorKind::Other, x))?;
if let Some(scheme) = uri_ref.scheme() {
if !scheme.as_str().eq_ignore_ascii_case("distant") {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Scheme is not distant",
));
}
} else if require_scheme {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Missing scheme",
));
}
Ok(Self {
host: uri_ref
.host()
.map(ToString::to_string)
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing host"))?,
port: uri_ref
.port()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing port"))?,
key: uri_ref
.password()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Missing password"))
.and_then(|x| {
x.parse()
.map_err(|x| io::Error::new(io::ErrorKind::InvalidInput, x))
})?,
username: uri_ref.username().map(ToString::to_string),
})
}
}