diff --git a/res/agreement/DEFAULT.xml b/res/agreement/DEFAULT.xml index 68055bb..c80b4cc 100644 --- a/res/agreement/DEFAULT.xml +++ b/res/agreement/DEFAULT.xml @@ -1 +1 @@ -USenEnglish2014-09-29T20:07:35NINTENDO-NETWORK-EULA0300USenEspañol2014-09-29T20:07:35NINTENDO-NETWORK-EULA0300 \ No newline at end of file +USenEnglish2014-09-29T20:07:35NINTENDO-NETWORK-EULA0300USenEspañol2014-09-29T20:07:35NINTENDO-NETWORK-EULA0300 diff --git a/res/agreement/EVIL.xml b/res/agreement/EVIL.xml new file mode 100644 index 0000000..e69de29 diff --git a/src/nnid/agreements.rs b/src/nnid/agreements.rs index 16e9700..e1ca61f 100644 --- a/src/nnid/agreements.rs +++ b/src/nnid/agreements.rs @@ -1,12 +1,38 @@ use std::{env, io}; +use std::collections::HashSet; +use gxhash::HashMap; +use once_cell::sync::Lazy; use rocket::fs::NamedFile; -use rocket::get; +use rocket::{get, Request}; +use rocket::http::Status; +use rocket::request::{FromRequest, Outcome}; use rocket::response::content::RawXml; use tokio::fs::try_exists; +use tokio::sync::RwLock; +use tonic::async_trait; use crate::dsresponse::Ds; +pub static EVIL_AGREEMENT_THING: Lazy>> = Lazy::new(|| Default::default()); + +pub struct CFIP(pub String); + +#[async_trait] +impl<'r> FromRequest<'r> for CFIP{ + type Error = (); + + async fn from_request(request: &'r Request<'_>) -> Outcome { + match request.headers().get("CF-Connecting-IP").next(){ + Some(v) => Outcome::Success(Self(v.to_owned())), + None => Outcome::Error((Status::ImATeapot, ())) + } + } +} + + #[get("/v1/api/content/agreements/Nintendo-Network-EULA//@latest")] -pub async fn get_agreement(lang: &str) -> io::Result>>{ +pub async fn get_agreement(lang: &str, ip: CFIP) -> io::Result>>{ + + let base_path = { // if this crashes then something is wrong with the server setup so crashing here is fine imo let mut path = env::current_dir().unwrap(); @@ -17,27 +43,38 @@ pub async fn get_agreement(lang: &str) -> io::Result>>{ path }; - let requested_file_path = { - let mut path = base_path.clone(); + if EVIL_AGREEMENT_THING.read().await.contains(&ip.0) { + let requested_file_path = { + let mut path = base_path.clone(); - path.push(format!("{}.xml", lang)); - - path - }; - - - - if try_exists(&requested_file_path).await.is_ok_and(|v| v == true){ - Ok(Ds(RawXml(NamedFile::open(&requested_file_path).await?))) - } else { - let fallback_path = { - let mut path = base_path; - - path.push("DEFAULT.xml"); + path.push(format!("{}.xml", lang)); path }; - Ok(Ds(RawXml(NamedFile::open(&fallback_path).await?))) + + if try_exists(&requested_file_path).await.is_ok_and(|v| v == true) { + Ok(Ds(RawXml(NamedFile::open(&requested_file_path).await?))) + } else { + let fallback_path = { + let mut path = base_path; + + path.push("DEFAULT.xml"); + + path + }; + + Ok(Ds(RawXml(NamedFile::open(&fallback_path).await?))) + } + } else { + let path = { + let mut path = base_path; + + path.push("EVIL.xml"); + + path + }; + + Ok(Ds(RawXml(NamedFile::open(&path).await?))) } } \ No newline at end of file diff --git a/src/nnid/oauth/generate_token.rs b/src/nnid/oauth/generate_token.rs index 9f12bbd..2baf374 100644 --- a/src/nnid/oauth/generate_token.rs +++ b/src/nnid/oauth/generate_token.rs @@ -3,6 +3,7 @@ use rocket::form::Form; use serde::{Serialize}; use crate::account::account::User; use crate::error::{Error, Errors}; +use crate::nnid::agreements::{CFIP, EVIL_AGREEMENT_THING}; use crate::nnid::oauth::generate_token::token_type::{AUTH_REFRESH_TOKEN, AUTH_TOKEN}; use crate::nnid::oauth::TokenData; use crate::Pool; @@ -26,12 +27,21 @@ const ACCOUNT_ID_OR_PASSWORD_ERRORS: Errors = Errors{ const ACCOUNT_BANNED_ERRORS: Errors = Errors{ error: &[ Error{ - code: "0123", + code: "0122", message: "Device has been banned by game server" } ] }; + +const REREAD_EULA_EXTRABANNED_ERRORS: Errors = Errors{ + error: &[ + Error{ + code: "0109", + message: "REREAD THE EULA LOL" + } + ] +}; #[derive(FromForm)] pub struct TokenRequestData<'a>{ grant_type: &'a str, @@ -90,7 +100,7 @@ pub struct TokenRequestReturnData{ } #[post("/v1/api/oauth20/access_token/generate", data="")] -pub async fn generate_token(pool: &State, data: Form>) -> Result, Option>>{ +pub async fn generate_token(pool: &State, data: Form>, ip: CFIP) -> Result, Option>>{ let pool = pool.inner(); let user = User::get_by_username(data.user_id, pool).await @@ -101,6 +111,14 @@ pub async fn generate_token(pool: &State, data: Form> } if user.account_level < 0{ + if user.account_level == -2 { + return Err(Some(REREAD_EULA_EXTRABANNED_ERRORS)); + } + if user.account_level == -3{ + EVIL_AGREEMENT_THING.write().await.insert(ip.0); + + return Err(Some(REREAD_EULA_EXTRABANNED_ERRORS)); + } return Err(Some(ACCOUNT_BANNED_ERRORS)); }