An unofficial collection of APIs used in FreeJam games and mods
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.9KB

  1. use std::sync::RwLock;
  2. use serde::{Deserialize, Serialize};
  3. use ureq::{Agent, Error};
  4. use serde_json::to_string;
  5. use crate::robocraft::{ITokenProvider, account::AuthenticationResponseInfo, AccountInfo};
  6. /// Token provider for an existing Freejam account, authenticated through the web browser portal.
  7. ///
  8. /// Steam and Epic accounts are not supported.
  9. pub struct PortalTokenProvider {
  10. /// Login token
  11. token: RwLock<ProgressionLoginResponse>,
  12. /// User info token
  13. jwt: AuthenticationResponseInfo,
  14. /// Ureq HTTP client
  15. client: Agent,
  16. }
  17. impl PortalTokenProvider {
  18. pub fn portal() -> Result<Self, Error> {
  19. Self::target("Techblox".to_owned())
  20. }
  21. pub fn target(value: String) -> Result<Self, Error> {
  22. let client = Agent::new();
  23. let payload = PortalStartPayload {
  24. target: value,
  25. };
  26. let start_response = client.post("https://account.freejamgames.com/api/authenticate/portal/start")
  27. .set("Content-Type", "application/json")
  28. .send_string(&to_string(&payload).unwrap())?;
  29. let start_res = start_response.into_json::<PortalStartResponse>()?;
  30. println!("GO TO https://account.freejamgames.com/login?theme=rc2&redirect_url=portal?theme=rc2%26portalToken={}", start_res.token);
  31. let payload = PortalCheckPayload {
  32. token: start_res.token,
  33. };
  34. let mut check_response = client.post("https://account.freejamgames.com/api/authenticate/portal/check")
  35. .set("Content-Type", "application/json")
  36. .send_json(&payload)?;
  37. //.send_string(&to_string(&payload).unwrap())?;
  38. let mut auth_complete = check_response.status() == 200;
  39. while !auth_complete {
  40. check_response = client.post("https://account.freejamgames.com/api/authenticate/portal/check")
  41. .set("Content-Type", "application/json")
  42. .send_json(&payload)?;
  43. auth_complete = check_response.status() == 200;
  44. }
  45. let check_res = check_response.into_json::<AuthenticationResponseInfo>()?;
  46. // login with token we just got
  47. let payload = ProgressionLoginPayload {
  48. token: check_res.token.clone(),
  49. };
  50. let progress_response = client.post("https://progression.production.robocraft2.com/login/fj")
  51. .set("Content-Type", "application/json")
  52. .send_json(&payload)?;
  53. let progress_res = progress_response.into_json::<ProgressionLoginResponse>()?;
  54. Ok(Self {
  55. token: RwLock::new(progress_res),
  56. jwt: check_res,
  57. client: client,
  58. })
  59. }
  60. pub fn get_account_info(&self) -> Result<AccountInfo, Error> {
  61. Ok(self.jwt.decode_jwt_data())
  62. }
  63. }
  64. impl ITokenProvider for PortalTokenProvider {
  65. fn token(&self) -> Result<String, ()> {
  66. // TODO re-authenticate when expired
  67. if let Some(token) = self.token.read().map_err(|_| ())?.token.clone() {
  68. Ok(token)
  69. } else {
  70. Err(())
  71. }
  72. }
  73. }
  74. #[derive(Deserialize, Serialize, Clone)]
  75. pub(crate) struct PortalStartPayload {
  76. #[serde(rename = "Target")]
  77. pub target: String,
  78. }
  79. #[derive(Deserialize, Serialize, Clone)]
  80. pub(crate) struct PortalStartResponse {
  81. #[serde(rename = "Token")]
  82. pub token: String,
  83. }
  84. #[derive(Deserialize, Serialize, Clone)]
  85. pub(crate) struct PortalCheckPayload {
  86. #[serde(rename = "Token")]
  87. pub token: String,
  88. }
  89. #[derive(Deserialize, Serialize, Clone)]
  90. pub(crate) struct ProgressionLoginPayload {
  91. #[serde(rename = "token")]
  92. pub token: String,
  93. }
  94. #[derive(Deserialize, Serialize, Clone)]
  95. pub(crate) struct ProgressionLoginResponse {
  96. #[serde(rename = "success")]
  97. pub success: bool,
  98. #[serde(rename = "error")]
  99. pub error: Option<String>,
  100. #[serde(rename = "token")]
  101. pub token: Option<String>,
  102. #[serde(rename = "serverToken")]
  103. pub server_token: Option<String>,
  104. }