Update login, add nasu
This commit is contained in:
parent
685b47daff
commit
18bc76e2ec
3 changed files with 1068 additions and 616 deletions
1485
Cargo.lock
generated
1485
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
12
Cargo.toml
12
Cargo.toml
|
|
@ -4,13 +4,15 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
passterm = "2.0.3"
|
||||
rand = "0.8.5"
|
||||
reqwest = { version = "0.12.8", features = ["blocking", "cookies", "json"] }
|
||||
argp = "0.4.1"
|
||||
futures-util = "0.3.34"
|
||||
passterm = "2.1.0"
|
||||
rand = "0.10.3"
|
||||
reqwest = { version = "0.13.5", default-features = false, features = ["blocking", "charset", "cookies", "form", "json", "native-tls", "system-proxy"] }
|
||||
reqwest-websocket = { version = "0.6.0", features = ["json"] }
|
||||
#serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
#sled = "0.34.7"
|
||||
#smallvec = "1.13.2"
|
||||
tokio = { version = "1", features = [] }
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
#typed-sled = "0.2.3"
|
||||
|
|
|
|||
197
src/main.rs
197
src/main.rs
|
|
@ -1,37 +1,68 @@
|
|||
use clap::Parser;
|
||||
use rand::Rng;
|
||||
use futures_util::{SinkExt, TryStreamExt};
|
||||
use rand::RngExt;
|
||||
use reqwest::{
|
||||
header::{HeaderMap, HeaderValue},
|
||||
Method,
|
||||
};
|
||||
use reqwest_websocket::{Message, Upgrade};
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
const WS: &'static str = "wss://leekwars.com/ws";
|
||||
const API: &'static str = "https://leekwars.com/api/";
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "leekwarsbot")]
|
||||
#[command(bin_name = "leekwarsbot")]
|
||||
struct Cli {
|
||||
#[clap(short, long)]
|
||||
username: String,
|
||||
/// Number of seconds to wait between each fight
|
||||
#[clap(short, long, default_value_t = 10)]
|
||||
delay: u64,
|
||||
/// Number of fights to start
|
||||
#[clap(short, long, default_value_t = 1)]
|
||||
fights: usize,
|
||||
const WS_GARDEN_BOSS_CREATE_SQUAD: u32 = 66;
|
||||
const WS_GARDEN_BOSS_JOIN_SQUAD: u32 = 67;
|
||||
const WS_GARDEN_BOSS_SQUAD: u32 = 76;
|
||||
const WS_GARDEN_BOSS_SQUAD_JOINED: u32 = 74;
|
||||
const WS_GARDEN_BOSS_ATTACK: u32 = 71;
|
||||
const WS_GARDEN_BOSS_LISTEN: u32 = 72;
|
||||
|
||||
enum FightType {
|
||||
Farmer,
|
||||
Nasu,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
impl argp::FromArgValue for FightType {
|
||||
fn from_arg_value(value: &std::ffi::OsStr) -> Result<Self, String> {
|
||||
match value.to_str().unwrap() {
|
||||
"farmer" => Ok(FightType::Farmer),
|
||||
"nasu" => Ok(FightType::Nasu),
|
||||
_ => Err("fight type must be one of farmer|nasu".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// LeekWars bot
|
||||
#[derive(argp::FromArgs)]
|
||||
struct Cli {
|
||||
/// Username
|
||||
#[argp(positional)]
|
||||
username: String,
|
||||
/// Number of seconds to wait between each fight
|
||||
#[argp(option, short = 'd', default = "10")]
|
||||
delay: u64,
|
||||
/// Number of fights to start
|
||||
#[argp(option, short = 'n', default = "1")]
|
||||
fights: usize,
|
||||
/// Fight type
|
||||
#[argp(option, short = 't', default = "FightType::Farmer")]
|
||||
fight_type: FightType,
|
||||
/// Leek id
|
||||
#[argp(option, short = 'l')]
|
||||
leek: Option<u32>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cli: Cli = argp::parse_args_or_exit(argp::DEFAULT);
|
||||
|
||||
let delay = std::time::Duration::from_secs(cli.delay);
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = rand::rng();
|
||||
|
||||
let password = passterm::prompt_password_tty(Some("Password: ")).unwrap();
|
||||
|
||||
let client = reqwest::blocking::Client::builder()
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(30))
|
||||
.user_agent("RustyLeekwarsBot")
|
||||
.build()
|
||||
|
|
@ -45,20 +76,21 @@ fn main() {
|
|||
.post(format!("{}{}", API, "farmer/login-token"))
|
||||
.form(&form)
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
//dbg!(resp.status());
|
||||
//dbg!(resp.headers());
|
||||
|
||||
let phpsessid = resp
|
||||
let hostsess = resp
|
||||
.cookies()
|
||||
.find_map(|cookie| {
|
||||
if cookie.name() == "PHPSESSID" && cookie.value() != "deleted" {
|
||||
if cookie.name() == "__Host-sess" && cookie.value() != "deleted" {
|
||||
Some(cookie.value().to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.expect("No PHPSESSID from the API!");
|
||||
.expect("No __Host-sess from the API!");
|
||||
let token = resp
|
||||
.cookies()
|
||||
.find_map(|cookie| {
|
||||
|
|
@ -73,13 +105,15 @@ fn main() {
|
|||
let mut headers = HeaderMap::new();
|
||||
headers.insert(
|
||||
reqwest::header::AUTHORIZATION,
|
||||
HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(),
|
||||
HeaderValue::from_str("Bearer $").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::COOKIE,
|
||||
HeaderValue::from_str(&format!("token={}; PHPSESSID={}", token, phpsessid)).unwrap(),
|
||||
HeaderValue::from_str(&format!("token={}; __Host-sess={}", token, hostsess)).unwrap(),
|
||||
);
|
||||
|
||||
match cli.fight_type {
|
||||
FightType::Farmer => {
|
||||
for _ in 0..cli.fights {
|
||||
let resp: serde_json::Value = client
|
||||
.request(
|
||||
|
|
@ -88,12 +122,14 @@ fn main() {
|
|||
)
|
||||
.headers(headers.clone())
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json()
|
||||
.await
|
||||
.unwrap();
|
||||
//dbg!(&resp);
|
||||
|
||||
let opponent = &resp["opponents"].as_array().unwrap()[rng.gen_range(0..5)];
|
||||
let opponent = &resp["opponents"].as_array().unwrap()[rng.random_range(0..5)];
|
||||
let opponent_name = opponent["name"].as_str().unwrap();
|
||||
let opponent_id = opponent["id"].as_u64().unwrap();
|
||||
|
||||
|
|
@ -110,10 +146,123 @@ fn main() {
|
|||
.headers(headers.clone())
|
||||
.json(&map)
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json()
|
||||
.await
|
||||
.unwrap();
|
||||
//dbg!(resp);
|
||||
std::thread::sleep(delay);
|
||||
}
|
||||
}
|
||||
FightType::Nasu => {
|
||||
headers.insert(
|
||||
reqwest::header::SEC_WEBSOCKET_PROTOCOL,
|
||||
HeaderValue::from_str("leek-wars, $").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::SEC_WEBSOCKET_EXTENSIONS,
|
||||
HeaderValue::from_str("permessage-deflate").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::SEC_WEBSOCKET_KEY,
|
||||
HeaderValue::from_str("mKwpFRJwZHKyJDTUdyhRIA==").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::SEC_WEBSOCKET_VERSION,
|
||||
HeaderValue::from_str("13").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::HeaderName::from_static("sec-fetch-dest"),
|
||||
HeaderValue::from_str("empty").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::HeaderName::from_static("sec-fetch-site"),
|
||||
HeaderValue::from_str("same-origin").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::HeaderName::from_static("sec-fetch-mode"),
|
||||
HeaderValue::from_str("websocket").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::CACHE_CONTROL,
|
||||
HeaderValue::from_str("no-cache").unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
reqwest::header::ORIGIN,
|
||||
HeaderValue::from_str("https://leekwars.com").unwrap(),
|
||||
);
|
||||
|
||||
let ws_resp = client
|
||||
.get(WS)
|
||||
.headers(headers.clone())
|
||||
.upgrade()
|
||||
.protocols(["leek-wars"])
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
let mut ws = ws_resp.into_websocket().await.unwrap();
|
||||
let enter_msg = Message::text_from_json(&[
|
||||
serde_json::Value::Number(serde_json::Number::from(WS_GARDEN_BOSS_CREATE_SQUAD)),
|
||||
serde_json::Value::Number(serde_json::Number::from(1)),
|
||||
serde_json::Value::Bool(true),
|
||||
serde_json::Value::Array(vec![serde_json::Value::Number(
|
||||
serde_json::Number::from(cli.leek.unwrap()),
|
||||
)]),
|
||||
])
|
||||
.unwrap();
|
||||
let attack_msg = Message::text_from_json(&[serde_json::Value::Number(
|
||||
serde_json::Number::from(WS_GARDEN_BOSS_ATTACK),
|
||||
)])
|
||||
.unwrap();
|
||||
for i in 0..cli.fights {
|
||||
if i > 0 {
|
||||
std::thread::sleep(delay);
|
||||
}
|
||||
ws.flush().await.unwrap();
|
||||
ws.send(enter_msg.clone()).await.unwrap();
|
||||
let mut boss_id = None;
|
||||
//let mut master_id = None;
|
||||
while let Some(msg) = ws.try_next().await.unwrap() {
|
||||
match dbg!(&msg) {
|
||||
Message::Ping(b) => {
|
||||
ws.send(Message::Pong(b.clone())).await.unwrap();
|
||||
}
|
||||
Message::Text(_) | Message::Binary(_) => {
|
||||
let msg: serde_json::Value = msg.json().unwrap();
|
||||
if !msg.is_array() {
|
||||
continue;
|
||||
}
|
||||
let msg = msg.as_array().unwrap();
|
||||
if msg[0]
|
||||
== serde_json::Value::Number(serde_json::Number::from(
|
||||
WS_GARDEN_BOSS_SQUAD,
|
||||
)) {
|
||||
boss_id = Some(msg[1].as_object().unwrap()["id"].clone());
|
||||
//master_id = Some(msg[1].as_object().unwrap()["master"].clone());
|
||||
} else if msg[0]
|
||||
== serde_json::Value::Number(serde_json::Number::from(
|
||||
WS_GARDEN_BOSS_SQUAD_JOINED,
|
||||
))
|
||||
&& boss_id.is_some()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let join_msg = Message::text_from_json(&[
|
||||
serde_json::Value::Number(serde_json::Number::from(WS_GARDEN_BOSS_JOIN_SQUAD)),
|
||||
boss_id.unwrap(),
|
||||
serde_json::Value::Array(vec![serde_json::Value::Number(
|
||||
serde_json::Number::from(cli.leek.unwrap()),
|
||||
)]),
|
||||
])
|
||||
.unwrap();
|
||||
ws.send(join_msg).await.unwrap();
|
||||
ws.send(attack_msg.clone()).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue