An unofficial collection of APIs used in FreeJam games and mods
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

164 Zeilen
5.1KB

  1. use serde::{Deserialize, Serialize};
  2. use ureq::{Agent, Error};
  3. use serde_json::{to_string, from_slice};
  4. use crate::robocraft::ITokenProvider;
  5. /// Token provider for an existing Robocraft account.
  6. ///
  7. /// Steam accounts are not supported.
  8. pub struct AuthenticatedTokenProvider {
  9. /// The account's username
  10. pub username: String,
  11. /// The account's password
  12. pub password: String,
  13. /// Ureq HTTP client
  14. client: Agent,
  15. }
  16. impl AuthenticatedTokenProvider {
  17. pub fn with_email(email: &str, password: &str) -> Result<Self, Error> {
  18. let client = Agent::new();
  19. let payload = AuthenticationEmailPayload {
  20. email_address: email.to_string(),
  21. password: password.to_string(),
  22. };
  23. let response = client.post("https://account.freejamgames.com/api/authenticate/email/web")
  24. .set("Content-Type", "application/json")
  25. .send_string(&to_string(&payload).unwrap())?;
  26. let json_res = response.into_json::<AuthenticationResponseInfo>()?;
  27. Ok(Self {
  28. username: json_res.decode_jwt_data().display_name,
  29. password: password.to_string(),
  30. client,
  31. })
  32. }
  33. pub fn with_username(username: &str, password: &str) -> Result<Self, Error> {
  34. let new_obj = Self {
  35. username: username.to_string(),
  36. password: password.to_string(),
  37. client: Agent::new(),
  38. };
  39. new_obj.do_auth()?;
  40. Ok(new_obj)
  41. }
  42. fn do_auth(&self) -> Result<AuthenticationResponseInfo, Error> {
  43. let payload = AuthenticationUsernamePayload {
  44. username: self.username.clone(),
  45. password: self.password.clone(),
  46. };
  47. let response = self.client.post("https://account.freejamgames.com/api/authenticate/displayname/web")
  48. .set("Content-Type", "application/json")
  49. .send_string(&to_string(&payload).unwrap())?;
  50. let json_res = response.into_json::<AuthenticationResponseInfo>()?;
  51. Ok(json_res)
  52. }
  53. pub fn get_account_info(&self) -> Result<AccountInfo, Error> {
  54. let json_res = self.do_auth()?;
  55. Ok(json_res.decode_jwt_data())
  56. }
  57. }
  58. impl ITokenProvider for AuthenticatedTokenProvider {
  59. fn token(&self) -> Result<String, ()> {
  60. let json_res = self.do_auth().map_err(|_|())?;
  61. Ok(json_res.token)
  62. }
  63. }
  64. #[derive(Deserialize, Serialize, Clone)]
  65. pub(crate) struct AuthenticationEmailPayload {
  66. #[serde(rename = "EmailAddress")]
  67. pub email_address: String,
  68. #[serde(rename = "Password")]
  69. pub password: String,
  70. }
  71. #[derive(Deserialize, Serialize, Clone)]
  72. pub(crate) struct AuthenticationUsernamePayload {
  73. #[serde(rename = "DisplayName")]
  74. pub username: String,
  75. #[serde(rename = "Password")]
  76. pub password: String,
  77. }
  78. #[derive(Deserialize, Serialize, Clone, Debug)]
  79. pub(crate) struct AuthenticationResponseInfo {
  80. #[serde(rename = "Token")]
  81. pub token: String,
  82. #[serde(rename = "RefreshToken")]
  83. pub refresh_token: String,
  84. #[serde(rename = "RefreshTokenExpiry")]
  85. pub refresh_token_expiry: String,
  86. }
  87. impl AuthenticationResponseInfo {
  88. pub fn decode_jwt_data(&self) -> AccountInfo {
  89. // Refer to https://jwt.io/
  90. // header is before dot, signature is after dot.
  91. // data is sandwiched in the middle, and it's all we care about
  92. let data = self.token.split(".").collect::<Vec<&str>>()[1];
  93. let data_vec = base64::decode(data).unwrap();
  94. from_slice::<AccountInfo>(&data_vec).unwrap()
  95. }
  96. }
  97. /// Robocraft account information.
  98. #[derive(Deserialize, Serialize, Clone)]
  99. pub struct AccountInfo {
  100. /// User's public ID
  101. #[serde(rename = "PublicId")]
  102. pub public_id: String,
  103. /// Account display name
  104. #[serde(rename = "DisplayName")]
  105. pub display_name: String,
  106. /// Account GUID, or display name for older accounts
  107. #[serde(rename = "RobocraftName")]
  108. pub robocraft_name: String,
  109. /// ??? is confirmed?
  110. #[serde(rename = "Confirmed")]
  111. pub confirmed: bool,
  112. /// Freejam support code
  113. #[serde(rename = "SupportCode")]
  114. pub support_code: String,
  115. /// User's email address
  116. #[serde(rename = "EmailAddress")]
  117. pub email_address: String,
  118. /// Email address is verified?
  119. #[serde(rename = "EmailVerified")]
  120. pub email_verified: bool,
  121. /// Account creation date
  122. #[serde(rename = "CreatedDate")]
  123. pub created_date: String,
  124. /// Owned products (?)
  125. #[serde(rename = "Products")]
  126. pub products: Vec<String>,
  127. /// Account flags
  128. #[serde(rename = "Flags")]
  129. pub flags: Vec<String>,
  130. /// Account has a password?
  131. #[serde(rename = "HasPassword")]
  132. pub has_password: bool,
  133. /// Mailing lists that the account is signed up for
  134. #[serde(rename = "MailingLists")]
  135. pub mailing_lists: Vec<String>,
  136. /// Is Steam account? (always false)
  137. #[serde(rename = "HasSteam")]
  138. pub has_steam: bool,
  139. /// iss (?)
  140. #[serde(rename = "iss")]
  141. pub iss: String,
  142. /// sub (?)
  143. #[serde(rename = "sub")]
  144. pub sub: String,
  145. /// Token created at (unix time) (?)
  146. #[serde(rename = "iat")]
  147. pub iat: u64,
  148. /// Token expiry (unix time) (?)
  149. #[serde(rename = "exp")]
  150. pub exp: u64,
  151. }