Compare commits
13 Commits
8717f31a1b
...
master
Author | SHA1 | Date | |
---|---|---|---|
f60d7f29bf
|
|||
b2f59a0990
|
|||
2134d34cbb
|
|||
db61e1b78d
|
|||
1c5565e0fb
|
|||
9a14cb6c90
|
|||
dcce732f5e
|
|||
d002af88a6
|
|||
435b05949e
|
|||
91b587f7db
|
|||
033f41b0ac
|
|||
16bb6a48a2
|
|||
516c2529e2
|
237
Cargo.lock
generated
237
Cargo.lock
generated
@@ -55,6 +55,12 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
|
||||
|
||||
[[package]]
|
||||
name = "argparse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f8ebf5827e4ac4fd5946560e6a99776ea73b596d80898f357007317a7141e47"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.7"
|
||||
@@ -387,6 +393,31 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot 0.12.1",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@@ -881,6 +912,31 @@ dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers-core"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
|
||||
dependencies = [
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
@@ -1065,6 +1121,25 @@ version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
|
||||
|
||||
[[package]]
|
||||
name = "is-docker"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-wsl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
|
||||
dependencies = [
|
||||
"is-docker",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@@ -1183,14 +1258,17 @@ dependencies = [
|
||||
"matrix-sdk-indexeddb",
|
||||
"matrix-sdk-sled",
|
||||
"mime",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"ruma",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"url",
|
||||
"warp",
|
||||
"wasm-timer",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -1359,6 +1437,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.6"
|
||||
@@ -1411,6 +1499,16 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "873240a4a404d44c8cd1bf394359245d466a5695771fea15a79cafbc5e5cf4d7"
|
||||
dependencies = [
|
||||
"is-wsl",
|
||||
"pathdiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.50"
|
||||
@@ -1466,6 +1564,16 @@ dependencies = [
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core 0.9.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
@@ -1504,6 +1612,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.11.0"
|
||||
@@ -2059,6 +2173,15 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
@@ -2070,15 +2193,18 @@ name = "scam-police"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argparse",
|
||||
"dirs",
|
||||
"matrix-sdk",
|
||||
"once_cell",
|
||||
"open",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"rpassword",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strfmt",
|
||||
"terminal-menu",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
@@ -2092,6 +2218,12 @@ dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@@ -2173,6 +2305,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.9"
|
||||
@@ -2197,6 +2340,36 @@ dependencies = [
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "1.6.4"
|
||||
@@ -2225,7 +2398,7 @@ dependencies = [
|
||||
"fxhash",
|
||||
"libc",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2317,6 +2490,16 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal-menu"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df4f5aa03b86607186c90883734a1c5751e18828f7c2f96f94a282ec1a1bd7e5"
|
||||
dependencies = [
|
||||
"crossterm",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
@@ -2390,6 +2573,17 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.7"
|
||||
@@ -2443,6 +2637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
@@ -2480,6 +2675,15 @@ version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
@@ -2603,6 +2807,35 @@ dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27e1a710288f0f91a98dd8a74f05b76a10768db245ce183edf64dc1afdc3016c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
"hyper",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"rustls-pemfile",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
@@ -2691,7 +2924,7 @@ checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.2",
|
||||
"pin-utils",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
|
@@ -8,14 +8,17 @@ authors = [ "@0xf8:projectsegfau.lt", "@jjj333:pain.agency" ]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.70"
|
||||
argparse = "0.2.2"
|
||||
dirs = "5.0.0"
|
||||
matrix-sdk = "0.6.2"
|
||||
matrix-sdk = { version = "0.6.2", features = [ "sso-login" ] }
|
||||
once_cell = "1.17.1"
|
||||
open = "4.0.2"
|
||||
rand = "0.8.5"
|
||||
reqwest = "0.11.16"
|
||||
rpassword = "7.2.0"
|
||||
serde = "1.0.160"
|
||||
serde_json = "1.0.95"
|
||||
strfmt = "0.2.4"
|
||||
terminal-menu = "2.0.5"
|
||||
tokio = { version = "1.27.0", features = ["macros", "rt-multi-thread"] }
|
||||
url = "2.3.1"
|
||||
|
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Scam Police
|
||||
A rust bot for Matrix designed to call out scams
|
||||
|
||||
# Build
|
||||
`cargo build --release`
|
||||
|
||||
# Run
|
||||
On first run, you will need to login. To do this, run `cargo run --release [MXID]` where MXID is the Matrix ID of the user the bot will run on. The only currently supported login flow is Password. (SSO planned)
|
@@ -7,6 +7,7 @@
|
||||
"nude",
|
||||
"18+",
|
||||
"private",
|
||||
"l.wl.co/", ".app.link/", "is.gd/",
|
||||
"pictures",
|
||||
"cheap"
|
||||
],
|
||||
@@ -30,9 +31,11 @@
|
||||
"profit",
|
||||
"my commission",
|
||||
"tg", "t.me",
|
||||
"l.wl.co/", ".app.link/", "is.gd/",
|
||||
"cash.app",
|
||||
"l.wl.co/", ".app.link/",
|
||||
"giveaway",
|
||||
"dividend",
|
||||
"whatsapp", "+1",
|
||||
"btc", "bitcoin"
|
||||
],
|
||||
"keywords": [
|
||||
@@ -52,7 +55,7 @@
|
||||
"double",
|
||||
"asking me how",
|
||||
"link below",
|
||||
"cash", "whatsapp",
|
||||
"cash",
|
||||
"telegram",
|
||||
"👇", "👆️"
|
||||
]
|
||||
|
@@ -122,7 +122,7 @@ impl Config {
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|a| (a.0.to_owned(), KeywordSection::load(a.1)))
|
||||
.map(|a| (a.0.to_owned(), KeywordSection::load(a.1).unwrap()))
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
|
@@ -1,33 +1,20 @@
|
||||
use serde_json::Value;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct KeywordSection {
|
||||
pub threshold: u64,
|
||||
#[serde(rename = "requiredKeywords")]
|
||||
pub required: Vec<String>,
|
||||
pub keywords: Vec<String>,
|
||||
}
|
||||
|
||||
impl KeywordSection {
|
||||
pub fn load(json: &Value) -> Self {
|
||||
let threshold: u64 = json["threshold"].as_u64().unwrap();
|
||||
let required: Vec<String> = json["requiredKeywords"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|a| a.as_str().unwrap().to_string())
|
||||
.collect();
|
||||
let keywords: Vec<String> = json["keywords"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|a| a.as_str().unwrap().to_string())
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
threshold,
|
||||
required,
|
||||
keywords,
|
||||
pub fn load(json: &Value) -> Option<Self> {
|
||||
match serde_json::from_value(json.to_owned()) {
|
||||
Ok(j) => Some(j),
|
||||
Err(e) => { eprintln!("{e}"); None }
|
||||
}
|
||||
}
|
||||
|
||||
|
33
src/main.rs
33
src/main.rs
@@ -8,7 +8,7 @@ use matrix_sdk::{
|
||||
},
|
||||
Error, LoopCtrl,
|
||||
};
|
||||
use std::{path::PathBuf, sync::Mutex};
|
||||
use std::{path::PathBuf, sync::Mutex, env};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
pub mod config;
|
||||
@@ -77,9 +77,8 @@ async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) -> any
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let judgement = judge::Judgement { text: text_content };
|
||||
|
||||
// Handle replies
|
||||
let mut is_reply = false;
|
||||
if let Some(relation) = orig_event.to_owned().content.relates_to {
|
||||
if let Some(event) = match relation {
|
||||
Relation::Reply { in_reply_to } => {
|
||||
@@ -97,6 +96,13 @@ async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) -> any
|
||||
} {
|
||||
let event = event.as_original().unwrap();
|
||||
let content = event.content.to_owned().body().to_lowercase();
|
||||
is_reply = true;
|
||||
|
||||
let reply_end = content.find("\n\n");
|
||||
let content = match reply_end {
|
||||
Some(r) => content.get(r+2..).unwrap().to_string(),
|
||||
None => content,
|
||||
};
|
||||
|
||||
if !debug
|
||||
&& event.sender
|
||||
@@ -135,6 +141,16 @@ async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) -> any
|
||||
}
|
||||
}
|
||||
|
||||
let judgement = if is_reply {
|
||||
let reply_end = text_content.find("\n\n");
|
||||
judge::Judgement { text: match reply_end {
|
||||
Some(r) => text_content.get(r+2..).unwrap().to_string(),
|
||||
None => text_content,
|
||||
}}
|
||||
} else {
|
||||
judge::Judgement { text: text_content }
|
||||
};
|
||||
|
||||
let judgement = judgement.judge(&config)?;
|
||||
match judgement.0 {
|
||||
judge::JudgementResult::Ok => return Ok(()),
|
||||
@@ -183,7 +199,16 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
let _stdin_thread = tokio::spawn(prompt::prompt(client.to_owned()));
|
||||
// TODO: Better solution for this
|
||||
let mut no_prompt: bool = false;
|
||||
match env::var("NO_PROMPT") {
|
||||
Ok(e) => { if e.to_lowercase().contains("yes") { no_prompt = true; } },
|
||||
Err(_e) => ()
|
||||
};
|
||||
if !no_prompt {
|
||||
tokio::spawn(prompt::prompt(client.to_owned()));
|
||||
}
|
||||
|
||||
client.add_event_handler(on_room_message);
|
||||
client
|
||||
.sync_with_result_callback(sync_settings, |sync_result| async move {
|
||||
|
148
src/matrix.rs
148
src/matrix.rs
@@ -1,5 +1,5 @@
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings, ruma::api::client::filter::FilterDefinition, Client, Session,
|
||||
config::SyncSettings, ruma::api::client::{filter::FilterDefinition, session::get_login_types::v3::{IdentityProvider, LoginType}}, Client, Session,
|
||||
};
|
||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||
use reqwest::Client as http;
|
||||
@@ -24,36 +24,137 @@ pub struct FullSession {
|
||||
sync_token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum LoginChoice {
|
||||
Password,
|
||||
Sso,
|
||||
SsoIdp(IdentityProvider),
|
||||
}
|
||||
|
||||
impl LoginChoice {
|
||||
pub async fn login(&self, client: &Client, user: String, hs: String) -> anyhow::Result<()> {
|
||||
match self {
|
||||
LoginChoice::Password => Self::login_password(client, user, hs).await,
|
||||
LoginChoice::Sso => Self::login_sso(client, None).await,
|
||||
LoginChoice::SsoIdp(idp) => Self::login_sso(client, Some(idp.to_owned())).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn login_password(client: &Client, user: String, _hs: String) -> anyhow::Result<()> {
|
||||
loop {
|
||||
let password = prompt_password("Password\n> ")?;
|
||||
|
||||
match client
|
||||
.login_username(&user, &password)
|
||||
.initial_device_display_name("scam-police")
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
println!("[*] Logged in as {user}");
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[!] Error logging in: {e}");
|
||||
println!("[!] Please try again\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn login_sso(client: &Client, idp: Option<IdentityProvider>) -> anyhow::Result<()> {
|
||||
let mut login_builder = client.login_sso(|url| async move {
|
||||
open::that_in_background(url);
|
||||
println!("[*] Waiting for SSO token...");
|
||||
Ok(())
|
||||
}).initial_device_display_name("scam-police");
|
||||
if let Some(idp) = idp.to_owned() {
|
||||
login_builder = login_builder.identity_provider_id(&idp.id);
|
||||
|
||||
login_builder.send().await?;
|
||||
} else {
|
||||
login_builder.send().await?;
|
||||
}
|
||||
|
||||
println!("[+] Got SSO token!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Matrix Login & Init
|
||||
//
|
||||
|
||||
pub async fn login(data_dir: &Path, session_file: &Path, mxid: String) -> anyhow::Result<Client> {
|
||||
println!("[*] No previous session, logging in with mxid...");
|
||||
println!("[*] Logging in as {mxid}...");
|
||||
|
||||
let (user, hs) = resolve_mxid(mxid).await?;
|
||||
let (client, client_session) = build_client(data_dir, hs).await?;
|
||||
let (client, client_session) = build_client(data_dir, hs.to_owned()).await?;
|
||||
|
||||
loop {
|
||||
let password = prompt_password("Password\n> ")?;
|
||||
|
||||
match client
|
||||
.login_username(&user, &password)
|
||||
.initial_device_display_name("scam-police")
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
println!("[*] Logged in as {user}");
|
||||
break;
|
||||
}
|
||||
Err(error) => {
|
||||
println!("[!] Error logging in: {error}");
|
||||
println!("[!] Please try again\n");
|
||||
}
|
||||
let mut login_choices = Vec::new();
|
||||
for login_type in client.get_login_types().await?.flows {
|
||||
match login_type {
|
||||
LoginType::Password(_) => {
|
||||
login_choices.push(LoginChoice::Password);
|
||||
},
|
||||
LoginType::Sso(sso) => {
|
||||
if sso.identity_providers.is_empty() {
|
||||
login_choices.push(LoginChoice::Sso);
|
||||
} else {
|
||||
login_choices.extend(sso.identity_providers.into_iter().map(LoginChoice::SsoIdp));
|
||||
}
|
||||
},
|
||||
// Ignore all other types
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
match login_choices.to_owned().len() {
|
||||
0 => anyhow::bail!("No supported login types"),
|
||||
1 => login_choices.to_owned().get(0).unwrap().login(&client, user, hs.to_owned()).await,
|
||||
_ => {
|
||||
use terminal_menu::*;
|
||||
|
||||
let mut menu_items = vec![label("----- Scam Police Login -----")];
|
||||
let choices: Vec<(LoginChoice, String)> = login_choices.into_iter().map(|a| (a.to_owned(), match a {
|
||||
LoginChoice::Password => format!("Password"),
|
||||
LoginChoice::Sso => format!("SSO"),
|
||||
LoginChoice::SsoIdp(idp) => format!("SSO via {}", idp.name),
|
||||
})).collect();
|
||||
|
||||
for choice in choices.to_owned() {
|
||||
menu_items.push(button(choice.1));
|
||||
}
|
||||
|
||||
menu_items.push(button("Abort login"));
|
||||
menu_items.push(label("-----------------------------"));
|
||||
|
||||
let menu = menu(menu_items);
|
||||
run(&menu);
|
||||
|
||||
let menu = mut_menu(&menu);
|
||||
let mut selected: Option<LoginChoice> = None;
|
||||
let name = menu.selected_item_name().to_string();
|
||||
if name == "Abort login" {
|
||||
selected = None;
|
||||
} else {
|
||||
for c in choices {
|
||||
if c.1 == name {
|
||||
selected = Some(c.0.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match selected {
|
||||
Some(s) => s.login(&client, user, hs.to_owned()).await,
|
||||
None => anyhow::bail!("Aborting login")
|
||||
}
|
||||
}
|
||||
}?;
|
||||
|
||||
let user_session = client
|
||||
.session()
|
||||
.expect("A logged-in client should have a session");
|
||||
@@ -66,6 +167,7 @@ pub async fn login(data_dir: &Path, session_file: &Path, mxid: String) -> anyhow
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
|
||||
pub async fn build_client(data_dir: &Path, hs: String) -> anyhow::Result<(Client, ClientSession)> {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
@@ -89,7 +191,7 @@ pub async fn build_client(data_dir: &Path, hs: String) -> anyhow::Result<(Client
|
||||
.await
|
||||
{
|
||||
Ok(client) => {
|
||||
println!("[*] Homeserver OK");
|
||||
println!("[+] Homeserver OK");
|
||||
return Ok((
|
||||
client,
|
||||
ClientSession {
|
||||
@@ -165,7 +267,7 @@ pub async fn sync<'a>(
|
||||
client: Client,
|
||||
initial_sync_token: Option<String>,
|
||||
) -> anyhow::Result<(Client, SyncSettings<'a>)> {
|
||||
println!("[*] Initial sync...");
|
||||
println!("[*] Running initial sync...");
|
||||
|
||||
let filter = FilterDefinition::empty();
|
||||
|
||||
@@ -192,7 +294,7 @@ pub async fn sync<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
println!("[*] The bot is ready!");
|
||||
println!("[*] Scam police is now running!");
|
||||
|
||||
Ok((client, sync_settings))
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ pub async fn prompt(client: Client) -> anyhow::Result<()> {
|
||||
if let Some(cmd) = args.get(0) {
|
||||
match cmd.as_ref() {
|
||||
"help" => {
|
||||
println!("help; stop; rooms; join room_id; leave room_id");
|
||||
println!("help; stop; logout; rooms; join room_id; leave room_id");
|
||||
},
|
||||
"stop" => {
|
||||
let should_stop = unsafe { crate::SHOULD_STOP.get_mut() };
|
||||
@@ -40,6 +40,19 @@ pub async fn prompt(client: Client) -> anyhow::Result<()> {
|
||||
eprintln!("Stopping...");
|
||||
}
|
||||
},
|
||||
"logout" => {
|
||||
match client.logout().await {
|
||||
Ok(_) => {
|
||||
println!("Logged out.");
|
||||
match std::fs::remove_dir_all(crate::DATA_DIR.to_owned()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => anyhow::bail!("Couldn't remove data dir: {e}"),
|
||||
}
|
||||
std::process::exit(0);
|
||||
},
|
||||
Err(e) => anyhow::bail!("Failed to logout: {e}")
|
||||
}
|
||||
},
|
||||
"rooms" => {
|
||||
let rooms = client.rooms();
|
||||
|
||||
|
Reference in New Issue
Block a user