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
|
use mt_net::{MtReceiver, MtSender, RemoteSrv, ToCltPkt, ToSrvPkt};
use rand::RngCore;
use sha2::Sha256;
use srp::{client::SrpClient, groups::G_2048};
use std::time::Duration;
use tokio::sync::oneshot;
async fn handle(tx: MtSender<RemoteSrv>, rx: &mut MtReceiver<RemoteSrv>) {
let mut username = "hydra".to_string();
let password = "password";
let (init_tx, mut init_rx) = oneshot::channel();
{
let tx = tx.clone();
let pkt = ToSrvPkt::Init {
serialize_version: 29,
min_proto_version: 40,
max_proto_version: 40,
player_name: username.clone(),
send_full_item_meta: false,
};
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_millis(100));
while tokio::select! {
_ = &mut init_rx => false,
_ = interval.tick() => true,
} {
tx.send(&pkt).await.unwrap()
}
});
}
let mut init_tx = Some(init_tx);
let mut auth = None;
while let Some(res) = rx.recv().await {
match res {
Ok(pkt) => {
use ToCltPkt::*;
match pkt {
Hello {
auth_methods,
username: name,
..
} => {
use mt_net::AuthMethod;
if let Some(chan) = init_tx.take() {
chan.send(()).unwrap();
let client = SrpClient::<Sha256>::new(&G_2048);
let mut rand_bytes = vec![0; 32];
rand::thread_rng().fill_bytes(&mut rand_bytes);
username = name;
if auth_methods.contains(AuthMethod::FirstSrp) {
let verifier = client.compute_verifier(
username.to_lowercase().as_bytes(),
password.as_bytes(),
&rand_bytes,
);
tx.send(&ToSrvPkt::FirstSrp {
salt: rand_bytes,
verifier,
empty_passwd: password.is_empty(),
})
.await
.unwrap();
} else if auth_methods.contains(AuthMethod::Srp) {
let a = client.compute_public_ephemeral(&rand_bytes);
auth = Some((rand_bytes, client));
tx.send(&ToSrvPkt::SrpBytesA { a, no_sha1: true })
.await
.unwrap();
} else {
panic!("unsupported auth methods: {auth_methods:?}");
}
}
}
SrpBytesSaltB { salt, b } => {
if let Some((a, client)) = auth.take() {
let m = client
.process_reply(
&a,
username.to_lowercase().as_bytes(),
password.as_bytes(),
&salt,
&b,
)
.unwrap()
.proof()
.into();
tx.send(&ToSrvPkt::SrpBytesM { m }).await.unwrap();
}
}
x => println!("{x:?}"),
}
}
Err(err) => eprintln!("{err}"),
}
}
}
#[tokio::main]
async fn main() {
let (tx, mut rx) = mt_net::connect("localhost:30000").await.unwrap();
tokio::select! {
_ = tokio::signal::ctrl_c() => println!("canceled"),
_ = handle(tx, &mut rx) => {
println!("disconnected");
}
}
rx.close().await;
}
|