From 13e5644c8951cde86e2e6c5cc8068cc516a99dbf Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Mon, 21 Aug 2023 10:42:33 -0400 Subject: [PATCH] Fix creator payouts + scheduler (#686) --- src/auth/flows.rs | 63 +------- src/auth/minecraft/auth.rs | 160 -------------------- src/auth/minecraft/login.rs | 35 ----- src/auth/minecraft/mod.rs | 60 -------- src/auth/minecraft/refresh.rs | 72 --------- src/auth/minecraft/socket.rs | 40 ----- src/auth/minecraft/stages/access_token.rs | 65 -------- src/auth/minecraft/stages/bearer_token.rs | 27 ---- src/auth/minecraft/stages/login_redirect.rs | 8 - src/auth/minecraft/stages/mod.rs | 27 ---- src/auth/minecraft/stages/player_info.rs | 33 ---- src/auth/minecraft/stages/xbl_signin.rs | 55 ------- src/auth/minecraft/stages/xsts_token.rs | 57 ------- src/auth/mod.rs | 7 +- src/database/models/flow_item.rs | 3 - src/main.rs | 38 ++--- src/queue/payouts.rs | 9 +- src/validate/forge.rs | 2 +- 18 files changed, 29 insertions(+), 732 deletions(-) delete mode 100644 src/auth/minecraft/auth.rs delete mode 100644 src/auth/minecraft/login.rs delete mode 100644 src/auth/minecraft/mod.rs delete mode 100644 src/auth/minecraft/refresh.rs delete mode 100644 src/auth/minecraft/socket.rs delete mode 100644 src/auth/minecraft/stages/access_token.rs delete mode 100644 src/auth/minecraft/stages/bearer_token.rs delete mode 100644 src/auth/minecraft/stages/login_redirect.rs delete mode 100644 src/auth/minecraft/stages/mod.rs delete mode 100644 src/auth/minecraft/stages/player_info.rs delete mode 100644 src/auth/minecraft/stages/xbl_signin.rs delete mode 100644 src/auth/minecraft/stages/xsts_token.rs diff --git a/src/auth/flows.rs b/src/auth/flows.rs index fa32f38cc..4e6247f8b 100644 --- a/src/auth/flows.rs +++ b/src/auth/flows.rs @@ -50,9 +50,7 @@ pub fn config(cfg: &mut ServiceConfig) { .service(resend_verify_email) .service(set_email) .service(verify_email) - .service(subscribe_newsletter) - .service(login_from_minecraft) - .configure(super::minecraft::config), + .service(subscribe_newsletter), ); } @@ -1177,65 +1175,6 @@ pub async fn auth_callback( Ok(res?) } -#[derive(Deserialize)] -pub struct MinecraftLogin { - pub flow: String, -} - -#[post("login/minecraft")] -pub async fn login_from_minecraft( - req: HttpRequest, - client: Data, - file_host: Data>, - redis: Data, - login: web::Json, -) -> Result { - let flow = Flow::get(&login.flow, &redis).await?; - - // Extract cookie header from request - if let Some(Flow::MicrosoftLogin { - access_token: token, - }) = flow - { - Flow::remove(&login.flow, &redis).await?; - let provider = AuthProvider::Microsoft; - let oauth_user = provider.get_user(&token).await?; - let user_id_opt = provider.get_user_id(&oauth_user.id, &**client).await?; - - let mut transaction = client.begin().await?; - - let user_id = if let Some(user_id) = user_id_opt { - let user = crate::database::models::User::get_id(user_id, &**client, &redis) - .await? - .ok_or_else(|| AuthenticationError::InvalidCredentials)?; - - if user.totp_secret.is_some() { - let flow = Flow::Login2FA { user_id: user.id } - .insert(Duration::minutes(30), &redis) - .await?; - - return Ok(HttpResponse::Ok().json(serde_json::json!({ - "error": "2fa_required", - "flow": flow - }))); - } - - user_id - } else { - oauth_user - .create_account(provider, &mut transaction, &client, &file_host, &redis) - .await? - }; - - let session = issue_session(req, user_id, &mut transaction, &redis).await?; - Ok(HttpResponse::Ok().json(serde_json::json!({ - "code": session.session - }))) - } else { - Err(AuthenticationError::InvalidCredentials) - } -} - #[derive(Deserialize)] pub struct DeleteAuthProvider { pub provider: AuthProvider, diff --git a/src/auth/minecraft/auth.rs b/src/auth/minecraft/auth.rs deleted file mode 100644 index 9b67fdead..000000000 --- a/src/auth/minecraft/auth.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! Main authentication flow for Hydra -use crate::{auth::minecraft::stages, auth::templates, parse_var}; - -// use crate::db::RuntimeState; -use crate::database::models::flow_item::Flow; -use crate::queue::socket::ActiveSockets; -use actix_web::http::StatusCode; -use actix_web::{get, web, HttpResponse}; -use chrono::Duration; -use serde::Deserialize; -use serde_json::json; -use tokio::sync::RwLock; - -macro_rules! ws_conn_try { - ($ctx:literal $status:path, $res:expr => $ws_conn:expr) => { - match $res { - Ok(res) => res, - Err(err) => { - let error = format!("In {}: {err}", $ctx); - let render = super::Error::render_string(&error); - let _ = $ws_conn.text(render.clone()).await; - let _ = $ws_conn.close(None).await; - return Err(templates::ErrorPage { - code: $status, - message: render, - }); - } - } - }; -} - -#[derive(Deserialize)] -pub struct Query { - pub code: String, - pub state: String, -} - -#[get("callback")] -pub async fn route( - db: web::Data>, - info: web::Query, - redis: web::Data, -) -> Result { - let public_url = parse_var::("SELF_ADDR").unwrap_or(format!( - "http://{}", - parse_var::("BIND_ADDR").unwrap() - )); - let client_id = parse_var::("MICROSOFT_CLIENT_ID").unwrap(); - let client_secret = parse_var::("MICROSOFT_CLIENT_SECRET").unwrap(); - - let code = &info.code; - - let mut ws_conn = { - let db = db.read().await; - - let mut x = db - .auth_sockets - .get_mut(&info.state) - .ok_or_else(|| templates::ErrorPage { - code: StatusCode::BAD_REQUEST, - message: "Invalid state sent, you probably need to get a new websocket".to_string(), - })?; - - x.value_mut().clone() - }; - - ws_conn_try!( - "Removing login flow" StatusCode::INTERNAL_SERVER_ERROR, - Flow::remove(code, &redis).await - => ws_conn - ); - - let access_token = ws_conn_try!( - "OAuth token exchange" StatusCode::INTERNAL_SERVER_ERROR, - stages::access_token::fetch_token( - public_url, - code, - &client_id, - &client_secret, - ).await - => ws_conn - ); - - let stages::xbl_signin::XBLLogin { - token: xbl_token, - uhs, - } = ws_conn_try!( - "XBox Live token exchange" StatusCode::INTERNAL_SERVER_ERROR, - stages::xbl_signin::login_xbl(&access_token.access_token).await - => ws_conn - ); - - let xsts_response = ws_conn_try!( - "XSTS token exchange" StatusCode::INTERNAL_SERVER_ERROR, - stages::xsts_token::fetch_token(&xbl_token).await - => ws_conn - ); - - match xsts_response { - stages::xsts_token::XSTSResponse::Unauthorized(err) => { - let _ = ws_conn - .text(super::Error::render_string(&format!( - "Error getting XBox Live token: {err}" - ))) - .await; - let _ = ws_conn.close(None).await; - - Err(templates::ErrorPage { - code: StatusCode::FORBIDDEN, - message: err, - }) - } - stages::xsts_token::XSTSResponse::Success { token: xsts_token } => { - let bearer_token = &ws_conn_try!( - "Bearer token flow" StatusCode::INTERNAL_SERVER_ERROR, - stages::bearer_token::fetch_bearer(&xsts_token, &uhs) - .await - => ws_conn - ); - - let player_info = &ws_conn_try!( - "No Minecraft account for profile. Make sure you own the game and have set a username through the official Minecraft launcher." StatusCode::BAD_REQUEST, - stages::player_info::fetch_info(bearer_token) - .await - => ws_conn - ); - - let flow = &ws_conn_try!( - "Error creating microsoft login request flow." StatusCode::INTERNAL_SERVER_ERROR, - Flow::MicrosoftLogin { - access_token: access_token.access_token.clone(), - } - .insert(Duration::hours(1), &redis) - .await - => ws_conn - ); - - ws_conn - .text( - json!({ - "token": bearer_token, - "refresh_token": &access_token.refresh_token, - "expires_after": 86400, - "flow": flow, - }).to_string() - ) - .await.map_err(|_| templates::ErrorPage { - code: StatusCode::BAD_REQUEST, - message: "Failed to send login details to launcher. Try restarting the login process!".to_string(), - })?; - let _ = ws_conn.close(None).await; - - Ok(templates::Success { - name: &player_info.name, - icon: &format!("https://mc-heads.net/avatar/{}/128", &player_info.id), - } - .render()) - } - } -} diff --git a/src/auth/minecraft/login.rs b/src/auth/minecraft/login.rs deleted file mode 100644 index d61ea14e4..000000000 --- a/src/auth/minecraft/login.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Login route for Hydra, redirects to the Microsoft login page before going to the redirect route -use crate::{auth::minecraft::stages::login_redirect, auth::templates, parse_var}; -use actix_web::http::StatusCode; -use actix_web::{get, web, HttpResponse}; -use serde::{Deserialize, Serialize}; - -#[derive(Deserialize)] -pub struct Query { - pub id: Option, -} - -#[derive(Serialize)] -pub struct AuthorizationInit { - pub url: String, -} - -#[get("init")] -pub async fn route(info: web::Query) -> Result { - let conn_id = info.0.id.ok_or_else(|| templates::ErrorPage { - code: StatusCode::BAD_REQUEST, - message: "No socket ID provided (open a web socket at the / route for one)".to_string(), - })?; - - let public_url = parse_var::("SELF_ADDR").unwrap_or(format!( - "http://{}", - parse_var::("BIND_ADDR").unwrap() - )); - let client_id = parse_var::("MICROSOFT_CLIENT_ID").unwrap(); - - let url = login_redirect::get_url(&public_url, &conn_id, &client_id); - - Ok(HttpResponse::TemporaryRedirect() - .append_header(("Location", &*url)) - .json(AuthorizationInit { url })) -} diff --git a/src/auth/minecraft/mod.rs b/src/auth/minecraft/mod.rs deleted file mode 100644 index 98d11c998..000000000 --- a/src/auth/minecraft/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -mod auth; -mod login; -mod refresh; -mod socket; -mod stages; - -use actix_web::http::StatusCode; -use actix_web::web::{scope, ServiceConfig}; -use actix_web::HttpResponse; -use serde_json::json; -use std::fmt::{Display, Formatter}; - -/// Error message -#[derive(Debug)] -pub struct Error { - pub code: StatusCode, - pub reason: String, -} - -impl Error { - pub fn render_string(reason: &str) -> String { - json!({ "error": reason }).to_string() - } -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - json!({ - "error": self.reason - }) - )?; - - Ok(()) - } -} - -impl actix_web::ResponseError for Error { - fn status_code(&self) -> StatusCode { - self.code - } - - fn error_response(&self) -> HttpResponse { - HttpResponse::build(self.code).json(json!({ - "error": self.reason - })) - } -} - -pub fn config(cfg: &mut ServiceConfig) { - cfg.service( - scope("minecraft") - .service(auth::route) - .service(login::route) - .service(refresh::route) - .service(socket::route), - ); -} diff --git a/src/auth/minecraft/refresh.rs b/src/auth/minecraft/refresh.rs deleted file mode 100644 index 6b269f94e..000000000 --- a/src/auth/minecraft/refresh.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! Refresh token route -use super::stages; -use crate::parse_var; -use actix_web::http::StatusCode; -use actix_web::{post, web, HttpResponse}; -use serde::Deserialize; -use serde_json::json; - -#[derive(Deserialize)] -pub struct Body { - refresh_token: String, -} - -#[post("refresh")] -pub async fn route(body: web::Json) -> Result { - let public_url = parse_var::("SELF_ADDR").unwrap_or(format!( - "http://{}", - parse_var::("BIND_ADDR").unwrap() - )); - let client_id = parse_var::("MICROSOFT_CLIENT_ID").unwrap(); - let client_secret = parse_var::("MICROSOFT_CLIENT_SECRET").unwrap(); - - let access_token = stages::access_token::refresh_token( - &public_url, - &body.refresh_token, - &client_id, - &client_secret, - ) - .await - .map_err(|_| super::Error { - code: StatusCode::INTERNAL_SERVER_ERROR, - reason: "Error with OAuth token exchange".to_string(), - })?; - - let stages::xbl_signin::XBLLogin { - token: xbl_token, - uhs, - } = stages::xbl_signin::login_xbl(&access_token.access_token) - .await - .map_err(|_| super::Error { - code: StatusCode::INTERNAL_SERVER_ERROR, - reason: "Error with XBox Live token exchange".to_string(), - })?; - - let xsts_response = stages::xsts_token::fetch_token(&xbl_token) - .await - .map_err(|_| super::Error { - code: StatusCode::INTERNAL_SERVER_ERROR, - reason: "Error with XSTS token exchange".to_string(), - })?; - - match xsts_response { - stages::xsts_token::XSTSResponse::Unauthorized(err) => Err(super::Error { - code: StatusCode::UNAUTHORIZED, - reason: format!("Error getting XBox Live token: {err}"), - }), - stages::xsts_token::XSTSResponse::Success { token: xsts_token } => { - let bearer_token = stages::bearer_token::fetch_bearer(&xsts_token, &uhs) - .await - .map_err(|_| super::Error { - code: StatusCode::INTERNAL_SERVER_ERROR, - reason: "Error with Bearer token flow".to_string(), - })?; - - Ok(HttpResponse::Ok().json(&json!({ - "token": bearer_token, - "refresh_token": &access_token.refresh_token, - "expires_after": 86400 - }))) - } - } -} diff --git a/src/auth/minecraft/socket.rs b/src/auth/minecraft/socket.rs deleted file mode 100644 index 2fd209b8a..000000000 --- a/src/auth/minecraft/socket.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::database::models::flow_item::Flow; -use crate::queue::socket::ActiveSockets; -use actix_web::web::Payload; -use actix_web::{get, web, HttpRequest, HttpResponse}; -use actix_ws::{Closed, Session}; -use chrono::Duration; -use tokio::sync::RwLock; - -#[get("ws")] -pub async fn route( - req: HttpRequest, - body: Payload, - db: web::Data>, - redis: web::Data, -) -> Result { - let (res, session, _msg_stream) = actix_ws::handle(&req, body)?; - let _ = sock(session, db, redis).await; - - Ok(res) -} - -async fn sock( - mut ws_stream: Session, - db: web::Data>, - redis: web::Data, -) -> Result<(), Closed> { - if let Ok(state) = Flow::MinecraftAuth - .insert(Duration::minutes(30), &redis) - .await - { - ws_stream - .text(serde_json::json!({ "login_code": state }).to_string()) - .await?; - - let db = db.write().await; - db.auth_sockets.insert(state, ws_stream); - } - - Ok(()) -} diff --git a/src/auth/minecraft/stages/access_token.rs b/src/auth/minecraft/stages/access_token.rs deleted file mode 100644 index 59989b67f..000000000 --- a/src/auth/minecraft/stages/access_token.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Get access token from code -use serde::Deserialize; -use std::collections::HashMap; - -const OAUTH_TOKEN_URL: &str = "https://login.live.com/oauth20_token.srf"; - -#[derive(Deserialize)] -pub struct Tokens { - pub access_token: String, - pub refresh_token: String, -} - -pub async fn fetch_token( - public_uri: String, - code: &str, - client_id: &str, - client_secret: &str, -) -> Result { - let redirect_uri = format!("{}/v2/auth/minecraft/callback", public_uri); - - let mut params = HashMap::new(); - params.insert("client_id", client_id); - params.insert("client_secret", client_secret); - params.insert("code", code); - params.insert("grant_type", "authorization_code"); - params.insert("redirect_uri", redirect_uri.as_str()); - - let client = reqwest::Client::new(); - let result = client - .post(OAUTH_TOKEN_URL) - .form(¶ms) - .send() - .await? - .json::() - .await?; - - Ok(result) -} - -pub async fn refresh_token( - public_uri: &str, - refresh_token: &str, - client_id: &str, - client_secret: &str, -) -> Result { - let redirect_uri = format!("{}/v2/auth/minecraft/callback", public_uri); - - let mut params = HashMap::new(); - params.insert("client_id", client_id); - params.insert("client_secret", client_secret); - params.insert("refresh_token", refresh_token); - params.insert("grant_type", "refresh_token"); - params.insert("redirect_uri", &redirect_uri); - - let client = reqwest::Client::new(); - let result = client - .post(OAUTH_TOKEN_URL) - .form(¶ms) - .send() - .await? - .json::() - .await?; - - Ok(result) -} diff --git a/src/auth/minecraft/stages/bearer_token.rs b/src/auth/minecraft/stages/bearer_token.rs deleted file mode 100644 index d6e04c3da..000000000 --- a/src/auth/minecraft/stages/bearer_token.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Minecraft bearer token -use crate::auth::AuthenticationError; -use serde_json::json; - -const MCSERVICES_AUTH_URL: &str = "https://api.minecraftservices.com/launcher/login"; - -pub async fn fetch_bearer(token: &str, uhs: &str) -> Result { - let client = reqwest::Client::new(); - let body = client - .post(MCSERVICES_AUTH_URL) - .json(&json!({ - "xtoken": format!("XBL3.0 x={};{}", uhs, token), - "platform": "PC_LAUNCHER" - })) - .send() - .await? - .text() - .await?; - - serde_json::from_str::(&body)? - .get("access_token") - .and_then(serde_json::Value::as_str) - .map(String::from) - .ok_or(AuthenticationError::Custom(format!( - "Response didn't contain valid bearer token. body: {body}" - ))) -} diff --git a/src/auth/minecraft/stages/login_redirect.rs b/src/auth/minecraft/stages/login_redirect.rs deleted file mode 100644 index 357a4dd07..000000000 --- a/src/auth/minecraft/stages/login_redirect.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Login redirect step -pub fn get_url(public_uri: &str, conn_id: &str, client_id: &str) -> String { - format!( - "https://login.live.com/oauth20_authorize.srf?client_id={client_id}&response_type=code&redirect_uri={}&scope={}&state={conn_id}&prompt=select_account&cobrandid=8058f65d-ce06-4c30-9559-473c9275a65d", - urlencoding::encode(&format!("{}/v2/auth/minecraft/callback", public_uri)), - urlencoding::encode("XboxLive.signin offline_access") - ) -} diff --git a/src/auth/minecraft/stages/mod.rs b/src/auth/minecraft/stages/mod.rs deleted file mode 100644 index 6753b24c1..000000000 --- a/src/auth/minecraft/stages/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! MSA authentication stages - -use lazy_static::lazy_static; - -pub mod access_token; -pub mod bearer_token; -pub mod login_redirect; -pub mod player_info; -pub mod xbl_signin; -pub mod xsts_token; - -lazy_static! { - static ref REQWEST_CLIENT: reqwest::Client = { - let mut headers = reqwest::header::HeaderMap::new(); - let header = reqwest::header::HeaderValue::from_str(&format!( - "modrinth/labrinth/{} (support@modrinth.com)", - env!("CARGO_PKG_VERSION") - )) - .unwrap(); - headers.insert(reqwest::header::USER_AGENT, header); - reqwest::Client::builder() - .tcp_keepalive(Some(std::time::Duration::from_secs(10))) - .default_headers(headers) - .build() - .expect("Reqwest Client Building Failed") - }; -} diff --git a/src/auth/minecraft/stages/player_info.rs b/src/auth/minecraft/stages/player_info.rs deleted file mode 100644 index 8cc81f093..000000000 --- a/src/auth/minecraft/stages/player_info.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Fetch player info for display -use serde::Deserialize; - -const PROFILE_URL: &str = "https://api.minecraftservices.com/minecraft/profile"; - -#[derive(Deserialize)] -pub struct PlayerInfo { - pub id: String, - pub name: String, -} - -impl Default for PlayerInfo { - fn default() -> Self { - Self { - id: "606e2ff0ed7748429d6ce1d3321c7838".to_string(), - name: String::from("???"), - } - } -} - -pub async fn fetch_info(token: &str) -> Result { - let client = reqwest::Client::new(); - let resp = client - .get(PROFILE_URL) - .header(reqwest::header::AUTHORIZATION, format!("Bearer {token}")) - .send() - .await? - .error_for_status()? - .json() - .await?; - - Ok(resp) -} diff --git a/src/auth/minecraft/stages/xbl_signin.rs b/src/auth/minecraft/stages/xbl_signin.rs deleted file mode 100644 index e84b340a7..000000000 --- a/src/auth/minecraft/stages/xbl_signin.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Signin for XBox Live - -use crate::auth::AuthenticationError; -use serde_json::json; - -const XBL_AUTH_URL: &str = "https://user.auth.xboxlive.com/user/authenticate"; - -// Deserialization -pub struct XBLLogin { - pub token: String, - pub uhs: String, -} - -// Impl -pub async fn login_xbl(token: &str) -> Result { - let client = reqwest::Client::new(); - let body = client - .post(XBL_AUTH_URL) - .header(reqwest::header::ACCEPT, "application/json") - .header("x-xbl-contract-version", "1") - .json(&json!({ - "Properties": { - "AuthMethod": "RPS", - "SiteName": "user.auth.xboxlive.com", - "RpsTicket": format!("d={token}") - }, - "RelyingParty": "http://auth.xboxlive.com", - "TokenType": "JWT" - })) - .send() - .await? - .text() - .await?; - - let json = serde_json::from_str::(&body)?; - let token = Some(&json) - .and_then(|it| it.get("Token")?.as_str().map(String::from)) - .ok_or(AuthenticationError::Custom( - "XBL response didn't contain valid token".to_string(), - ))?; - let uhs = Some(&json) - .and_then(|it| { - it.get("DisplayClaims")? - .get("xui")? - .get(0)? - .get("uhs")? - .as_str() - .map(String::from) - }) - .ok_or(AuthenticationError::Custom( - "XBL response didn't contain valid user hash".to_string(), - ))?; - - Ok(XBLLogin { token, uhs }) -} diff --git a/src/auth/minecraft/stages/xsts_token.rs b/src/auth/minecraft/stages/xsts_token.rs deleted file mode 100644 index 0b92f091a..000000000 --- a/src/auth/minecraft/stages/xsts_token.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::auth::AuthenticationError; -use serde_json::json; - -const XSTS_AUTH_URL: &str = "https://xsts.auth.xboxlive.com/xsts/authorize"; - -pub enum XSTSResponse { - Unauthorized(String), - Success { token: String }, -} - -pub async fn fetch_token(token: &str) -> Result { - let client = reqwest::Client::new(); - let resp = client - .post(XSTS_AUTH_URL) - .header(reqwest::header::ACCEPT, "application/json") - .json(&json!({ - "Properties": { - "SandboxId": "RETAIL", - "UserTokens": [ - token - ] - }, - "RelyingParty": "rp://api.minecraftservices.com/", - "TokenType": "JWT" - })) - .send() - .await?; - let status = resp.status(); - - let body = resp.text().await?; - let json = serde_json::from_str::(&body)?; - - if status.is_success() { - Ok(json - .get("Token") - .and_then(|x| x.as_str().map(String::from)) - .map(|it| XSTSResponse::Success { token: it }) - .unwrap_or(XSTSResponse::Unauthorized( - "XSTS response didn't contain valid token!".to_string(), - ))) - } else { - Ok(XSTSResponse::Unauthorized( - #[allow(clippy::unreadable_literal)] - match json.get("XErr").and_then(|x| x.as_i64()) { - Some(2148916238) => { - String::from("This Microsoft account is underage and is not linked to a family.") - }, - Some(2148916235) => { - String::from("XBOX Live/Minecraft is not available in your country.") - }, - Some(2148916233) => String::from("This account does not have a valid XBOX Live profile. Please buy Minecraft and try again!"), - Some(2148916236) | Some(2148916237) => String::from("This account needs adult verification on Xbox page."), - _ => String::from("Unknown error code"), - }, - )) - } -} diff --git a/src/auth/mod.rs b/src/auth/mod.rs index 0fb59a4cb..a05068835 100644 --- a/src/auth/mod.rs +++ b/src/auth/mod.rs @@ -1,7 +1,6 @@ pub mod checks; pub mod email; pub mod flows; -pub mod minecraft; pub mod pats; pub mod session; mod templates; @@ -48,9 +47,7 @@ pub enum AuthenticationError { #[error("Invalid state sent, you probably need to get a new websocket")] SocketError, #[error("Invalid callback URL specified")] - Url, - #[error("{0}")] - Custom(String), + Url } impl actix_web::ResponseError for AuthenticationError { @@ -69,7 +66,6 @@ impl actix_web::ResponseError for AuthenticationError { AuthenticationError::Url => StatusCode::BAD_REQUEST, AuthenticationError::FileHosting(..) => StatusCode::INTERNAL_SERVER_ERROR, AuthenticationError::DuplicateUser => StatusCode::BAD_REQUEST, - AuthenticationError::Custom(..) => StatusCode::BAD_REQUEST, AuthenticationError::SocketError => StatusCode::BAD_REQUEST, } } @@ -90,7 +86,6 @@ impl actix_web::ResponseError for AuthenticationError { AuthenticationError::Url => "url_error", AuthenticationError::FileHosting(..) => "file_hosting", AuthenticationError::DuplicateUser => "duplicate_user", - AuthenticationError::Custom(..) => "custom", AuthenticationError::SocketError => "socket", }, description: &self.to_string(), diff --git a/src/database/models/flow_item.rs b/src/database/models/flow_item.rs index 8883957c8..f55fa9b03 100644 --- a/src/database/models/flow_item.rs +++ b/src/database/models/flow_item.rs @@ -34,9 +34,6 @@ pub enum Flow { confirm_email: String, }, MinecraftAuth, - MicrosoftLogin { - access_token: String, - }, } impl Flow { diff --git a/src/main.rs b/src/main.rs index eb49a5d64..34d71f38d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -335,25 +335,25 @@ async fn main() -> std::io::Result<()> { }); } - // { - // let pool_ref = pool.clone(); - // let redis_ref = redis_pool.clone(); - // let client_ref = clickhouse.clone(); - // scheduler.run(std::time::Duration::from_secs(60 * 60 * 6), move || { - // let pool_ref = pool_ref.clone(); - // let redis_ref = redis_ref.clone(); - // let client_ref = client_ref.clone(); - // - // async move { - // info!("Done running payouts"); - // let result = process_payout(&pool_ref, &redis_ref, &client_ref).await; - // if let Err(e) = result { - // warn!("Payouts run failed: {:?}", e); - // } - // info!("Done running payouts"); - // } - // }); - // } + { + let pool_ref = pool.clone(); + let redis_ref = redis_pool.clone(); + let client_ref = clickhouse.clone(); + scheduler.run(std::time::Duration::from_secs(60 * 60 * 6), move || { + let pool_ref = pool_ref.clone(); + let redis_ref = redis_ref.clone(); + let client_ref = client_ref.clone(); + + async move { + info!("Done running payouts"); + let result = process_payout(&pool_ref, &redis_ref, &client_ref).await; + if let Err(e) = result { + warn!("Payouts run failed: {:?}", e); + } + info!("Done running payouts"); + } + }); + } let ip_salt = Pepper { pepper: models::ids::Base62Id(models::ids::random_base62(11)).to_string(), diff --git a/src/queue/payouts.rs b/src/queue/payouts.rs index 988f3165f..2a78447ac 100644 --- a/src/queue/payouts.rs +++ b/src/queue/payouts.rs @@ -2,7 +2,7 @@ use crate::models::projects::MonetizationStatus; use crate::routes::ApiError; use crate::util::env::parse_var; use base64::Engine; -use chrono::{DateTime, Datelike, Duration, Utc, Weekday}; +use chrono::{DateTime, Datelike, Duration, Utc, Weekday, NaiveDateTime, NaiveDate, NaiveTime}; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -287,7 +287,12 @@ pub async fn process_payout( .into_iter() .map(|x| (x.project_id, x.page_views)) .collect::>(); - views_values.extend(downloads_values); + + for (key, value) in downloads_values.iter() { + let counter = views_values.entry(*key).or_insert(0); + *counter += *value; + } + let multipliers: PayoutMultipliers = PayoutMultipliers { sum: downloads_sum + views_sum, values: views_values, diff --git a/src/validate/forge.rs b/src/validate/forge.rs index 9740156c0..6a4907da2 100644 --- a/src/validate/forge.rs +++ b/src/validate/forge.rs @@ -28,7 +28,7 @@ impl super::Validator for ForgeValidator { fn validate( &self, - archive: &mut ZipArchive>, + _archive: &mut ZipArchive>, ) -> Result { // if archive.by_name("META-INF/mods.toml").is_err() { // return Ok(ValidationResult::Warning(