diff --git a/src/main.rs b/src/main.rs index 5bea989..44c2687 100644 --- a/src/main.rs +++ b/src/main.rs @@ -178,7 +178,7 @@ fn main() -> Result<(), Box> { &config["wiki-http-password"], &config["wiki-api-user"], &config["wiki-api-secret"], - is_dry_run(), + false, // is_dry_run(), // TODO: Remove this false in order for actually letting dry_run affecting if mediawiki is run &config["wiki-plenum-page"], ); trace_var_!(wiki); diff --git a/src/mediawiki.rs b/src/mediawiki.rs index d43971e..99092b1 100644 --- a/src/mediawiki.rs +++ b/src/mediawiki.rs @@ -5,6 +5,7 @@ use chrono::{Datelike, NaiveDate, Utc}; use colored::Colorize; use reqwest::blocking::Client; use serde::Deserialize; +use serde_json::{json, Value}; use crate::{trace_var, verboseln}; use crate::config_spec::{CfgField, CfgGroup}; @@ -97,30 +98,57 @@ impl Mediawiki { client: Client::builder().cookie_store(true).build().unwrap(), } } - pub fn get_login_token(&self) -> Result<(), Box> { - let url = - format!("{}/api.php?", self.server_url); - let params: Box<[(&str, &str)]> = Box::from( [ - ("format", "json"), + pub fn login (&self) -> Result<(), Box> { + let url = format!("{}/api.php?", self.server_url); + // retrieve login token first + let params_0: Box<[(&str, &str)]> = Box::from([ + ("action", "query"), ("meta", "tokens"), ("type", "login"), - ("action", "query") + ("format", "json") ]); - let resp = self.make_request(url, params, ValidRequestTypes::Get)?; - let response_deserialized: QueryResponseLogin = serde_json::from_str(&resp)?; - self.login_token.set(response_deserialized.query.tokens.logintoken)?; - Ok(()) - } - pub fn login (&self) -> Result> { - let url = format!("{}/api.php?", self.server_url); - let params: Box<[(&str, &str)]> = Box::from([ - ("lgname", self.api_user.as_str()), - ("lgpassword", self.api_secret.as_str()), - ("lgtoken", self.login_token.get().unwrap()), - ("action", "login") + verboseln!("Login params: {:?}", params_0); + let resp_0: String = self.make_request(url.clone(), params_0, ValidRequestTypes::Get)?; + verboseln!("Raw response login_0: {}", resp_0.yellow()); + let resp_0_deserialized: serde_json::Value = serde_json::from_str(&resp_0)?; + verboseln!("login0 deserialized"); + + let login_token = resp_0_deserialized + .pointer("/query/tokens/logintoken") + .and_then(|v| v.as_str()) + .map(|token| token.replace("+\\", "")) + .ok_or("Login token not found")?; + + self.login_token.set(login_token)?; + + verboseln!("login0 finished"); + let login_token: String = self.login_token.clone().into_inner().unwrap(); + verboseln!("using {login_token} as login"); + let params_1: Box<[(&str, &str)]> = Box::from([ + ("action", "login"), + ("lgname", &self.api_user), + ("lgpassword", &self.api_secret), + ("lgtoken", &login_token), + ("format", "json") ]); - let resp: Result> = self.make_request(url, params, ValidRequestTypes::Post); - Ok(resp?) + verboseln!("Login params: {:?}", params_1); + let resp_1: String = self.client + .post(&url) + // .basic_auth(&self.http_user, Some(&self.http_password)) // TODO: ZU TESTZWECKEN ENTFERNT + .form(¶ms_1) + .send()? + .text()?; + verboseln!("Raw response login_1: {}", resp_1.yellow()); + let resp_1_deserialized: serde_json::Value = serde_json::from_str(&resp_1)?; + if let Some(result) = resp_1_deserialized.get("login").and_then(|l| l.get("result")) { + if result.as_str() == Some("Success") { + Ok(()) + } else { + Err(format!("Login failed. Response: {}", resp_1_deserialized).into()) + } + } else { + Err(format!("Unexpected login response: {}", resp_1_deserialized).into()) + } } pub fn get_csrf_token(&self) -> Result<(), Box> { let url = @@ -128,12 +156,18 @@ impl Mediawiki { let params: Box<[(&str, &str)]> = Box::from([ ("format", "json"), ("meta", "tokens"), - ("formatversion", "2"), ("action", "query") ]); let resp: String = self.make_request(url, params, ValidRequestTypes::Get)?; + verboseln!("Raw response csrf: {}", resp); let response_deserialized: QueryResponseCsrf = serde_json::from_str(&resp)?; - self.csrf_token.set(response_deserialized.query.tokens.csrftoken)?; + let token = response_deserialized.query.tokens.csrftoken; + verboseln!("Parsed token: '{}'", token); + if token == "+\\" { + return Err("Failed to parse CSRF token. Response was only '+\\'. Please check your Bot API credentials".into()); + } + self.csrf_token.set(token)?; + verboseln!("CSRF token acquired: {}", self.csrf_token.get().unwrap()); Ok(()) } @@ -144,7 +178,7 @@ impl Mediawiki { self .client .get(url) - //.basic_auth(&self.http_user, Some(&self.http_password)) ZU TESTZWECKEN ENTFERNT + //.basic_auth(&self.http_user, Some(&self.http_password)) // TODO: ZU TESTZWECKEN ENTFERNT .query(¶ms) .send() } @@ -154,8 +188,8 @@ impl Mediawiki { self .client .post(url) - //.basic_auth(&self.http_user, Some(&self.http_password)) ZU TESTZWECKEN ENTFERNT - .json(¶ms_map) + //.basic_auth(&self.http_user, Some(&self.http_password)) // TODO: ZU TESTZWECKEN ENTFERNT + .query(¶ms_map) .send() } } @@ -313,7 +347,6 @@ impl Mediawiki { ); // Ensure login token and CSRF token are set - self.get_login_token()?; let _login_result = self.login()?; self.get_csrf_token()?; @@ -382,7 +415,6 @@ impl Mediawiki { } } } - } /// This function runs at the end of do_protocol() and is responsible for @@ -394,9 +426,7 @@ pub fn pad_ins_wiki(old_pad_content: String, wiki: &Mediawiki, plenum_date: &Nai let date = plenum_date; wiki.test_wiki_write()?; // Login to Wiki and get required tokens for logging in and writing - wiki.get_login_token()?; - verboseln!("Login token acquired."); - + verboseln!("logging in..."); let login_result = wiki.login()?; verboseln!("Login done."); trace_var!(login_result); @@ -463,7 +493,6 @@ struct TokensLogin { #[derive(Deserialize)] struct QueryResponseCsrf { #[allow(dead_code)] - batchcomplete: bool, query: crate::mediawiki::QueryTokensCsrf, }