]> git.lizzy.rs Git - mt_client.git/blob - src/main.rs
Initial commit
[mt_client.git] / src / main.rs
1 use mt_net::{MtReceiver, MtSender, RemoteSrv, ToCltPkt, ToSrvPkt};
2 use rand::RngCore;
3 use sha2::Sha256;
4 use srp::{client::SrpClient, groups::G_2048};
5 use std::time::Duration;
6 use tokio::sync::oneshot;
7
8 async fn handle(tx: MtSender<RemoteSrv>, rx: &mut MtReceiver<RemoteSrv>) {
9     let mut username = "hydra".to_string();
10     let password = "password";
11
12     let (init_tx, mut init_rx) = oneshot::channel();
13
14     {
15         let tx = tx.clone();
16         let pkt = ToSrvPkt::Init {
17             serialize_version: 29,
18             min_proto_version: 40,
19             max_proto_version: 40,
20             player_name: username.clone(),
21             send_full_item_meta: false,
22         };
23
24         tokio::spawn(async move {
25             let mut interval = tokio::time::interval(Duration::from_millis(100));
26             while tokio::select! {
27                 _ = &mut init_rx => false,
28                 _ = interval.tick() => true,
29             } {
30                 tx.send(&pkt).await.unwrap()
31             }
32         });
33     }
34
35     let mut init_tx = Some(init_tx);
36     let mut auth = None;
37
38     while let Some(res) = rx.recv().await {
39         match res {
40             Ok(pkt) => {
41                 use ToCltPkt::*;
42
43                 match pkt {
44                     Hello {
45                         auth_methods,
46                         username: name,
47                         ..
48                     } => {
49                         use mt_net::AuthMethod;
50
51                         if let Some(chan) = init_tx.take() {
52                             chan.send(()).unwrap();
53
54                             let client = SrpClient::<Sha256>::new(&G_2048);
55
56                             let mut rand_bytes = vec![0; 32];
57                             rand::thread_rng().fill_bytes(&mut rand_bytes);
58
59                             username = name;
60
61                             if auth_methods.contains(AuthMethod::FirstSrp) {
62                                 let verifier = client.compute_verifier(
63                                     username.to_lowercase().as_bytes(),
64                                     password.as_bytes(),
65                                     &rand_bytes,
66                                 );
67
68                                 tx.send(&ToSrvPkt::FirstSrp {
69                                     salt: rand_bytes,
70                                     verifier,
71                                     empty_passwd: password.is_empty(),
72                                 })
73                                 .await
74                                 .unwrap();
75                             } else if auth_methods.contains(AuthMethod::Srp) {
76                                 let a = client.compute_public_ephemeral(&rand_bytes);
77                                 auth = Some((rand_bytes, client));
78
79                                 tx.send(&ToSrvPkt::SrpBytesA { a, no_sha1: true })
80                                     .await
81                                     .unwrap();
82                             } else {
83                                 panic!("unsupported auth methods: {auth_methods:?}");
84                             }
85                         }
86                     }
87                     SrpBytesSaltB { salt, b } => {
88                         if let Some((a, client)) = auth.take() {
89                             let m = client
90                                 .process_reply(
91                                     &a,
92                                     username.to_lowercase().as_bytes(),
93                                     password.as_bytes(),
94                                     &salt,
95                                     &b,
96                                 )
97                                 .unwrap()
98                                 .proof()
99                                 .into();
100
101                             tx.send(&ToSrvPkt::SrpBytesM { m }).await.unwrap();
102                         }
103                     }
104                     x => println!("{x:?}"),
105                 }
106             }
107             Err(err) => eprintln!("{err}"),
108         }
109     }
110 }
111
112 #[tokio::main]
113 async fn main() {
114     let (tx, mut rx) = mt_net::connect("localhost:30000").await.unwrap();
115
116     tokio::select! {
117         _ = tokio::signal::ctrl_c() => println!("canceled"),
118         _ = handle(tx, &mut rx) => {
119             println!("disconnected");
120         }
121     }
122
123     rx.close().await;
124 }