diff --git a/README.md b/README.md index cfef674..a0edabc 100644 --- a/README.md +++ b/README.md @@ -3,31 +3,46 @@ Purple Cello interface for the Mojang API in rust ## Implemented endpoints -- [ ] ~~API Status (Removed)~~ -- [x] Username to UUID -- [ ] Usernames to UUIDs -- [ ] ~~UUID to Name History (Removed)~~ -- [x] UUID to Profile and Skin/Cape -- [ ] Blocked Servers -- [ ] Statistics -- [ ] Profile Information -- [ ] Player Attributes -- [ ] Player Blocklist -- [ ] Player Certificates -- [ ] Profile Name Change Information -- [ ] Check Product Voucher -- [ ] Name Availability -- [ ] Change Name -- [ ] Change Skin -- [ ] Upload Skin -- [ ] Reset Skin -- [ ] Hide Cape -- [ ] Show Cape -- [ ] Verify Security Location -- [ ] Get Security Questions -- [ ] Send Security Answers -- [ ] Get Account Migration Information -- [ ] Account Migration OTP -- [ ] Verify Account Migration OTP -- [ ] Submit Migration Token -- [ ] Connect Xbox Live +### Accounts +- [x] [Username to UUID](https://wiki.vg/Mojang_API#Username_to_UUID) +- [ ] [Usernames to UUIDs](https://wiki.vg/Mojang_API#Usernames_to_UUIDs) +- [ ] [~~UUID to Name History~~](https://wiki.vg/Mojang_API#UUID_to_Name_History_.28Removed.29) +- [x] [UUID to Profile and Skin/Cape](https://wiki.vg/Mojang_API#UUID_to_Profile_and_Skin.2FCape) +- [ ] [Profile Information](https://wiki.vg/Mojang_API#Profile_Information) +- [ ] [Player Attributes](https://wiki.vg/Mojang_API#Player_Attributes) +- [ ] [Player Blocklist](https://wiki.vg/Mojang_API#Player_Blocklist) +- [ ] [Player Certificates](https://wiki.vg/Mojang_API#Player_Certificates) +- [ ] [Profile Name Change Information](https://wiki.vg/Mojang_API#Profile_Name_Change_Information) +- [ ] [Name Availability](https://wiki.vg/Mojang_API#Name_Availability) +- [ ] [Change Name](https://wiki.vg/Mojang_API#Change_Name) +- [ ] [Change Skin](https://wiki.vg/Mojang_API#Change_Skin) +- [ ] [Upload Skin](https://wiki.vg/Mojang_API#Upload_Skin) +- [ ] [Reset Skin](https://wiki.vg/Mojang_API#Reset_Skin) +- [ ] [Hide Cape](https://wiki.vg/Mojang_API#Hide_Cape) +- [ ] [Show Cape](https://wiki.vg/Mojang_API#Show_Cape) + +### Mojang +- [ ] [~~API Status~~](https://wiki.vg/Mojang_API#API_Status_.28Removed.29) +- [ ] [~~Statistics~~](https://wiki.vg/Mojang_API#Statistics) +- [ ] [Blocked Servers](https://wiki.vg/Mojang_API#Blocked_Servers) +- [ ] [Check Product Voucher](https://wiki.vg/Mojang_API#Check_Product_Voucher) +- [ ] [Verify Security Location](https://wiki.vg/Mojang_API#Verify_Security_Location) +- [ ] [Get Security Questions](https://wiki.vg/Mojang_API#Get_Security_Questions) +- [ ] [Send Security Answers](https://wiki.vg/Mojang_API#Send_Security_Answers) + +### Account Migration +- [ ] [Get Account Migration Information](https://wiki.vg/Mojang_API#Get_Account_Migration_Information) +- [ ] [Account Migration OTP](https://wiki.vg/Mojang_API#Account_Migration_OTP) +- [ ] [Verify Account Migration OTP](https://wiki.vg/Mojang_API#Verify_Account_Migration_OTP) +- [ ] [Submit Migration Token](https://wiki.vg/Mojang_API#Submit_Migration_Token) +- [ ] [Connect Xbox Live](https://wiki.vg/Mojang_API#Connect_Xbox_Live) + +### Multiplayer Authentication +- [ ] [Client Authentication](https://wiki.vg/Protocol_Encryption#Client) +- [ ] [Server Authentication](https://wiki.vg/Protocol_Encryption#Server) + +### Game Files +- [ ] [Game Versions](https://wiki.vg/Game_files#Game) +- [ ] [Libraries](https://wiki.vg/Game_files#Libraries) +- [ ] [Assets](https://wiki.vg/Game_files#Assets) +- [ ] [Java Version](https://wiki.vg/Game_files#Java_version) diff --git a/src/accounts.rs b/src/accounts.rs new file mode 100644 index 0000000..dd36ba2 --- /dev/null +++ b/src/accounts.rs @@ -0,0 +1,171 @@ +// Yeahbut January 2024 + +#![allow(non_snake_case)] + +use reqwest; +use serde::{Serialize, Deserialize}; +use base64::{Engine as _, engine::general_purpose}; + +#[derive(Serialize, Deserialize)] +pub struct UsernameToUuid { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub legacy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub demo: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub errorMessage: Option, +} + +pub async fn username_to_uuid(username: &str) + -> Result> +{ + let url = format!( + "https://api.mojang.com/users/profiles/minecraft/{}", + username + ); + + let resp = reqwest::get(url) + .await? + .json::() + .await?; + + Ok(resp) +} + +#[derive(Serialize, Deserialize)] +pub struct ProfileTextureMetadata { + pub model: String, +} + +#[derive(Serialize, Deserialize)] +pub struct ProfileTexture { + pub url: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct ProfileTextures { + #[serde(skip_serializing_if = "Option::is_none")] + pub SKIN: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub CAPE: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct ProfileValue { + pub timestamp: i64, + pub profileId: String, + pub profileName: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub signatureRequired: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub textures: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct ProfileProperty { + pub name: String, + pub value: ProfileValue, + #[serde(skip_serializing_if = "Option::is_none")] + pub signature: Option, +} + +#[derive(Serialize, Deserialize)] +struct ProfilePropertyPrivate { + pub name: String, + pub value: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub signature: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct UUIDToProfile { + pub id: String, + pub name: String, + pub properties: Vec, + pub profileActions: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub legacy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub demo: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub errorMessage: Option, +} + + +#[derive(Serialize, Deserialize)] +struct UUIDToProfilePrivate { + pub id: String, + pub name: String, + pub properties: Vec, + pub profileActions: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub legacy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub demo: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub errorMessage: Option, +} + +fn get_profile_value(properties: Vec) + -> Result, Box> +{ + let mut output: Vec = Vec::new(); + + for property in properties { + output.push(ProfileProperty { + name: property.name, + value: serde_json::from_slice( + &general_purpose::STANDARD_NO_PAD.decode(property.value)? + )?, + signature: property.signature, + }) + } + + Ok(output) +} + +pub async fn uuid_to_profile(uuid: &str) + -> Result> +{ + let url = format!( + "https://sessionserver.mojang.com/session/minecraft/profile/{}", + uuid + ); + + let resp = reqwest::get(url) + .await? + .json::() + .await?; + + let output = UUIDToProfile { + id: resp.id, + name: resp.name, + properties: get_profile_value(resp.properties)?, + profileActions: resp.profileActions, + legacy: resp.legacy, + demo: resp.demo, + path: resp.path, + error: resp.error, + errorMessage: resp.errorMessage, + }; + + Ok(output) +} diff --git a/src/lib.rs b/src/lib.rs index 2a0374f..5756482 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,170 +1,3 @@ // Yeahbut January 2024 -use reqwest; -use serde::{Serialize, Deserialize}; -use base64::{Engine as _, engine::general_purpose}; - -#[derive(Serialize, Deserialize)] -pub struct UsernameToUuid { - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub legacy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub demo: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub path: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub errorMessage: Option, -} - -pub async fn username_to_uuid(username: &str) - -> Result> -{ - let url = format!( - "https://api.mojang.com/users/profiles/minecraft/{}", - username - ); - - let resp = reqwest::get(url) - .await? - .json::() - .await?; - - Ok(resp) -} - -#[derive(Serialize, Deserialize)] -pub struct ProfileTextureMetadata { - pub model: String, -} - -#[derive(Serialize, Deserialize)] -pub struct ProfileTexture { - pub url: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub metadata: Option, -} - -#[derive(Serialize, Deserialize)] -pub struct ProfileTextures { - #[serde(skip_serializing_if = "Option::is_none")] - pub SKIN: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub CAPE: Option, -} - -#[derive(Serialize, Deserialize)] -pub struct ProfileValue { - pub timestamp: i64, - pub profileId: String, - pub profileName: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub signatureRequired: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub textures: Option, -} - -#[derive(Serialize, Deserialize)] -pub struct ProfileProperty { - pub name: String, - pub value: ProfileValue, - #[serde(skip_serializing_if = "Option::is_none")] - pub signature: Option, -} - -#[derive(Serialize, Deserialize)] -struct ProfilePropertyPrivate { - pub name: String, - pub value: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub signature: Option, -} - -#[derive(Serialize, Deserialize)] -pub struct UUIDToProfile { - pub id: String, - pub name: String, - pub properties: Vec, - pub profileActions: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub legacy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub demo: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub path: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub errorMessage: Option, -} - - -#[derive(Serialize, Deserialize)] -struct UUIDToProfilePrivate { - pub id: String, - pub name: String, - pub properties: Vec, - pub profileActions: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub legacy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub demo: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub path: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub errorMessage: Option, -} - -fn get_profile_value(properties: Vec) - -> Result, Box> -{ - let mut output: Vec = Vec::new(); - - for property in properties { - output.push(ProfileProperty { - name: property.name, - value: serde_json::from_slice( - &general_purpose::STANDARD_NO_PAD.decode(property.value)? - )?, - signature: property.signature, - }) - } - - Ok(output) -} - -pub async fn uuid_to_profile(uuid: &str) - -> Result> -{ - let url = format!( - "https://sessionserver.mojang.com/session/minecraft/profile/{}", - uuid - ); - - let resp = reqwest::get(url) - .await? - .json::() - .await?; - - let output = UUIDToProfile { - id: resp.id, - name: resp.name, - properties: get_profile_value(resp.properties)?, - profileActions: resp.profileActions, - legacy: resp.legacy, - demo: resp.demo, - path: resp.path, - error: resp.error, - errorMessage: resp.errorMessage, - }; - - Ok(output) -} - +pub mod accounts;