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
#[macro_use] extern crate failure;
extern crate openssl;
extern crate rmp_serde as rmps;
#[macro_use] extern crate serde_derive;
pub mod common;
pub mod listener;
pub mod state;
pub use listener::*;
pub use state::*;
use common::Packet;
use failure::Error;
use openssl::ssl::{SSL_VERIFY_PEER, SslConnectorBuilder, SslMethod, SslStream};
use openssl::x509::X509StoreContextRef;
use std::any::Any;
use std::net::{TcpStream, ToSocketAddrs};
pub struct Session {
stream: SslStream<TcpStream>
}
impl Drop for Session {
fn drop(&mut self) {
let _ = self.send(&Packet::Close);
}
}
impl Session {
pub fn new<S: Into<String>, T: ToSocketAddrs>(addr: T, hash: S) -> Result<Session, Error> {
let hash = hash.into();
Self::new_with_verify_callback(addr, move |_, cert| {
if let Some(cert) = cert.current_cert() {
if let Ok(pkey) = cert.public_key() {
if let Ok(pem) = pkey.public_key_to_pem() {
let digest = openssl::sha::sha256(&pem);
let mut digest_string = String::with_capacity(digest.len());
for byte in &digest {
digest_string.push_str(&format!("{:02X}", byte));
}
use std::ascii::AsciiExt;
return hash.trim().eq_ignore_ascii_case(&digest_string);
}
}
}
false
})
}
pub fn new_with_verify_callback<T, F>(addr: T, callback: F)
-> Result<Session, Error>
where
T: ToSocketAddrs,
F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send
{
let mut config = SslConnectorBuilder::new(SslMethod::tls())?;
config.set_verify_callback(SSL_VERIFY_PEER, callback);
let connector = config.build();
let stream = TcpStream::connect(addr)?;
let stream =
connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream)?;
Ok(Session {
stream: stream
})
}
pub fn inner_stream(&mut self) -> &mut SslStream<TcpStream> {
&mut self.stream
}
pub fn set_nonblocking(&mut self, value: bool) -> Result<(), std::io::Error> {
self.stream.get_ref().set_nonblocking(value)
}
pub fn login_with_password<S: Into<String>>(&mut self, bot: bool, name: S, password: S) -> Result<(), Error> {
self.send(&Packet::Login(common::Login {
bot: bot,
name: name.into(),
password: Some(password.into()),
token: None
}))
}
pub fn login_with_token<S: Into<String>>(&mut self, bot: bool, name: S, token: S) -> Result<(), Error> {
self.send(&Packet::Login(common::Login {
bot: bot,
name: name.into(),
password: None,
token: Some(token.into())
}))
}
pub fn send(&mut self, packet: &Packet) -> Result<(), Error> {
Ok(common::write(&mut self.stream, packet)?)
}
pub fn read(&mut self) -> Result<Packet, Error> {
Ok(common::read(&mut self.stream)?)
}
}
pub fn get_mode(channel: &common::Channel, user: &common::User) -> u8 {
if user.bot {
user.modes.get(&channel.id).cloned().unwrap_or(channel.default_mode_bot)
} else {
user.modes.get(&channel.id).cloned().unwrap_or(channel.default_mode_user)
}
}