Add RC account info
This commit is contained in:
parent
ce31f89fb9
commit
77ef47dce4
6 changed files with 205 additions and 4 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "libfj"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "An unofficial collection of APIs used in FreeJam games and mods"
|
||||
|
@ -35,8 +35,10 @@ genmesh = {version = "^0.6", optional = true}
|
|||
tokio = { version = "1.4.0", features = ["macros"]}
|
||||
|
||||
[features]
|
||||
all = ["simple", "robocraft", "cardlife", "techblox", "convert"]
|
||||
default = ["all"]
|
||||
simple = ["ureq"]
|
||||
robocraft = ["reqwest"]
|
||||
robocraft = ["reqwest", "ureq"]
|
||||
cardlife = ["reqwest"]
|
||||
techblox = ["chrono", "highhash", "half", "libfj_parsable_macro_derive"]
|
||||
convert = ["obj", "genmesh"]
|
||||
|
|
163
src/robocraft/account.rs
Normal file
163
src/robocraft/account.rs
Normal file
|
@ -0,0 +1,163 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use ureq::{Agent, Error};
|
||||
use serde_json::{to_string, from_slice};
|
||||
|
||||
use crate::robocraft::ITokenProvider;
|
||||
|
||||
/// Token provider for an existing Robocraft account.
|
||||
///
|
||||
/// Steam accounts are not supported.
|
||||
pub struct AuthenticatedTokenProvider {
|
||||
/// The account's username
|
||||
pub username: String,
|
||||
/// The account's password
|
||||
pub password: String,
|
||||
/// Ureq HTTP client
|
||||
client: Agent,
|
||||
}
|
||||
|
||||
impl AuthenticatedTokenProvider {
|
||||
pub fn with_email(email: &str, password: &str) -> Result<Self, Error> {
|
||||
let client = Agent::new();
|
||||
let payload = AuthenticationEmailPayload {
|
||||
email_address: email.to_string(),
|
||||
password: password.to_string(),
|
||||
};
|
||||
let response = client.post("https://account.freejamgames.com/api/authenticate/email/web")
|
||||
.set("Content-Type", "application/json")
|
||||
.send_string(&to_string(&payload).unwrap())?;
|
||||
let json_res = response.into_json::<AuthenticationResponseInfo>()?;
|
||||
Ok(Self {
|
||||
username: json_res.decode_jwt_data().display_name,
|
||||
password: password.to_string(),
|
||||
client,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_username(username: &str, password: &str) -> Result<Self, Error> {
|
||||
let new_obj = Self {
|
||||
username: username.to_string(),
|
||||
password: password.to_string(),
|
||||
client: Agent::new(),
|
||||
};
|
||||
new_obj.do_auth()?;
|
||||
Ok(new_obj)
|
||||
}
|
||||
|
||||
fn do_auth(&self) -> Result<AuthenticationResponseInfo, Error> {
|
||||
let payload = AuthenticationUsernamePayload {
|
||||
username: self.username.clone(),
|
||||
password: self.password.clone(),
|
||||
};
|
||||
let response = self.client.post("https://account.freejamgames.com/api/authenticate/displayname/web")
|
||||
.set("Content-Type", "application/json")
|
||||
.send_string(&to_string(&payload).unwrap())?;
|
||||
let json_res = response.into_json::<AuthenticationResponseInfo>()?;
|
||||
Ok(json_res)
|
||||
}
|
||||
|
||||
pub fn get_account_info(&self) -> Result<AccountInfo, Error> {
|
||||
let json_res = self.do_auth()?;
|
||||
Ok(json_res.decode_jwt_data())
|
||||
}
|
||||
}
|
||||
|
||||
impl ITokenProvider for AuthenticatedTokenProvider {
|
||||
fn token(&self) -> Result<String, ()> {
|
||||
let json_res = self.do_auth().map_err(|_|())?;
|
||||
Ok(json_res.token)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub(crate) struct AuthenticationEmailPayload {
|
||||
#[serde(rename = "EmailAddress")]
|
||||
pub email_address: String,
|
||||
#[serde(rename = "Password")]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub(crate) struct AuthenticationUsernamePayload {
|
||||
#[serde(rename = "DisplayName")]
|
||||
pub username: String,
|
||||
#[serde(rename = "Password")]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub(crate) struct AuthenticationResponseInfo {
|
||||
#[serde(rename = "Token")]
|
||||
pub token: String,
|
||||
#[serde(rename = "RefreshToken")]
|
||||
pub refresh_token: String,
|
||||
#[serde(rename = "RefreshTokenExpiry")]
|
||||
pub refresh_token_expiry: String,
|
||||
}
|
||||
|
||||
impl AuthenticationResponseInfo {
|
||||
pub fn decode_jwt_data(&self) -> AccountInfo {
|
||||
// Refer to https://jwt.io/
|
||||
// header is before dot, signature is after dot.
|
||||
// data is sandwiched in the middle, and it's all we care about
|
||||
let data = self.token.split(".").collect::<Vec<&str>>()[1];
|
||||
let data_vec = base64::decode(data).unwrap();
|
||||
from_slice::<AccountInfo>(&data_vec).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Robocraft account information.
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct AccountInfo {
|
||||
/// User's public ID
|
||||
#[serde(rename = "PublicId")]
|
||||
pub public_id: String,
|
||||
/// Account display name
|
||||
#[serde(rename = "DisplayName")]
|
||||
pub display_name: String,
|
||||
/// Account GUID, or display name for older accounts
|
||||
#[serde(rename = "RobocraftName")]
|
||||
pub robocraft_name: String,
|
||||
/// ??? is confirmed?
|
||||
#[serde(rename = "Confirmed")]
|
||||
pub confirmed: bool,
|
||||
/// Freejam support code
|
||||
#[serde(rename = "SupportCode")]
|
||||
pub support_code: String,
|
||||
/// User's email address
|
||||
#[serde(rename = "EmailAddress")]
|
||||
pub email_address: String,
|
||||
/// Email address is verified?
|
||||
#[serde(rename = "EmailVerified")]
|
||||
pub email_verified: bool,
|
||||
/// Account creation date
|
||||
#[serde(rename = "CreatedDate")]
|
||||
pub created_date: String,
|
||||
/// Owned products (?)
|
||||
#[serde(rename = "Products")]
|
||||
pub products: Vec<String>,
|
||||
/// Account flags
|
||||
#[serde(rename = "Flags")]
|
||||
pub flags: Vec<String>,
|
||||
/// Account has a password?
|
||||
#[serde(rename = "HasPassword")]
|
||||
pub has_password: bool,
|
||||
/// Mailing lists that the account is signed up for
|
||||
#[serde(rename = "MailingLists")]
|
||||
pub mailing_lists: Vec<String>,
|
||||
/// Is Steam account? (always false)
|
||||
#[serde(rename = "HasSteam")]
|
||||
pub has_steam: bool,
|
||||
/// iss (?)
|
||||
#[serde(rename = "iss")]
|
||||
pub iss: String,
|
||||
/// sub (?)
|
||||
#[serde(rename = "sub")]
|
||||
pub sub: String,
|
||||
/// Token created at (unix time) (?)
|
||||
#[serde(rename = "iat")]
|
||||
pub iat: u64,
|
||||
/// Token expiry (unix time) (?)
|
||||
#[serde(rename = "exp")]
|
||||
pub exp: u64,
|
||||
}
|
|
@ -16,5 +16,8 @@ pub use self::cubes::{Cube, Cubes};
|
|||
mod auth;
|
||||
pub use self::auth::{ITokenProvider, DefaultTokenProvider};
|
||||
|
||||
mod account;
|
||||
pub use self::account::{AuthenticatedTokenProvider, AccountInfo};
|
||||
|
||||
/// Token defined in a javascript file from Freejam which never expires
|
||||
pub const DEFAULT_TOKEN: &str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJQdWJsaWNJZCI6IjEyMyIsIkRpc3BsYXlOYW1lIjoiVGVzdCIsIlJvYm9jcmFmdE5hbWUiOiJGYWtlQ1JGVXNlciIsIkZsYWdzIjpbXSwiaXNzIjoiRnJlZWphbSIsInN1YiI6IldlYiIsImlhdCI6MTU0NTIyMzczMiwiZXhwIjoyNTQ1MjIzNzkyfQ.ralLmxdMK9rVKPZxGng8luRIdbTflJ4YMJcd25dKlqg";
|
||||
|
|
3
test.sh
3
test.sh
|
@ -1,5 +1,6 @@
|
|||
#!/bin/bash
|
||||
RUST_BACKTRACE=1 cargo test --all-features -- --nocapture
|
||||
# RUST_BACKTRACE=1 cargo test --all-features -- --nocapture
|
||||
# RUST_BACKTRACE=1 cargo test --release --all-features -- --nocapture
|
||||
# RUST_BACKTRACE=1 cargo test --features techblox -- --nocapture
|
||||
RUST_BACKTRACE=1 cargo test --features robocraft -- --nocapture
|
||||
exit $?
|
||||
|
|
32
tests/robocraft_auth.rs
Normal file
32
tests/robocraft_auth.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
#[cfg(feature = "robocraft")]
|
||||
use libfj::robocraft;
|
||||
#[cfg(feature = "robocraft")]
|
||||
use libfj::robocraft::ITokenProvider;
|
||||
|
||||
#[cfg(feature = "robocraft")]
|
||||
#[test]
|
||||
fn robocraft_auth_login() -> Result<(), ()> {
|
||||
let token_maybe = robocraft::AuthenticatedTokenProvider::with_email("melon.spoik@gmail.com", "P4$$w0rd");
|
||||
assert!(token_maybe.is_ok());
|
||||
let token_maybe = robocraft::AuthenticatedTokenProvider::with_username("FJAPIC00L", "P4$$w0rd");
|
||||
assert!(token_maybe.is_ok());
|
||||
let token_p = token_maybe.unwrap();
|
||||
let raw_token_maybe = token_p.token();
|
||||
assert!(raw_token_maybe.is_ok());
|
||||
println!("Token: {}", raw_token_maybe.unwrap());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "robocraft")]
|
||||
#[test]
|
||||
fn robocraft_account() -> Result<(), ()> {
|
||||
let token_maybe = robocraft::AuthenticatedTokenProvider::with_username("FJAPIC00L", "P4$$w0rd");
|
||||
assert!(token_maybe.is_ok());
|
||||
let token_provider = token_maybe.unwrap();
|
||||
let account_maybe = token_provider.get_account_info();
|
||||
assert!(account_maybe.is_ok());
|
||||
let account = account_maybe.unwrap();
|
||||
assert_eq!(account.display_name, "FJAPIC00L");
|
||||
assert_eq!(account.created_date, "2019-01-18T14:48:09");
|
||||
Ok(())
|
||||
}
|
|
@ -78,7 +78,7 @@ async fn robocraft_factory_custom_query() -> Result<(), ()> {
|
|||
#[tokio::test]
|
||||
async fn robocraft_factory_player_query() -> Result<(), ()> {
|
||||
let result = builder()
|
||||
.text("MilanZhi".to_string()) // there is a featured robot by this user, so this should never fail
|
||||
.text("Spacecam".to_string()) // there is a featured robot by this user, so this should never fail
|
||||
.text_search_type(robocraft::FactoryTextSearchType::Player)
|
||||
.items_per_page(10)
|
||||
.send().await;
|
||||
|
|
Loading…
Add table
Reference in a new issue