Skip to content

Instantly share code, notes, and snippets.

@Alloyed
Created August 1, 2019 00:47
Show Gist options
  • Save Alloyed/03b96626518fa280240643baaf6049cb to your computer and use it in GitHub Desktop.
Save Alloyed/03b96626518fa280240643baaf6049cb to your computer and use it in GitHub Desktop.
// itch api
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
struct ItchUser {
username: String,
display_name: String,
id: u32,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
enum ItchMeRaw {
User(ItchUser),
Errors(Vec<String>),
}
type ItchMe = Result<ItchUser, Vec<String>>;
impl From<ItchMeRaw> for ItchMe {
fn from(json: ItchMeRaw) -> ItchMe {
match json {
ItchMeRaw::Errors(messages) => Err(messages),
ItchMeRaw::User(user) => Ok(user),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
struct ItchDownloadKey {
id: u32,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
enum ItchDownloadKeysRaw {
DownloadKey(ItchDownloadKey),
Errors(Vec<String>),
}
type ItchDownloadKeys = Result<ItchDownloadKey, Vec<String>>;
impl From<ItchDownloadKeysRaw> for ItchDownloadKeys {
fn from(json: ItchDownloadKeysRaw) -> ItchDownloadKeys {
match json {
ItchDownloadKeysRaw::Errors(messages) => Err(messages),
ItchDownloadKeysRaw::DownloadKey(key) => Ok(key),
}
}
}
// end itch api
#[derive(PartialEq, Eq, Hash, Clone)]
pub enum AccountKey {
NoAuth(String),
Itch(u32),
}
pub enum Account {
NoAuth {
display_name: String,
},
Itch {
display_name: String,
account_name: String,
user_id: u32,
},
}
impl Account {
pub fn create_and_verify(
player: PlayerKey,
auth: &api::AuthData,
) -> Box<dyn Future<Item = Account, Error = api::AuthError>> {
match auth {
api::AuthData::NoAuth { display_name } => {
let auth_required = cfg::get_value(|c| c.auth.required);
if auth_required {
Box::new(future::err(api::AuthError::InvalidService))
} else {
Box::new(future::ok(Account::NoAuth {
display_name: display_name.clone(),
}))
}
}
api::AuthData::Itch { auth_token } => {
let auth_future = {
let cli = HTTP_CLIENT.lock().unwrap();
cli.get("https://itch.io/api/1/jwt/me")
.bearer_auth(auth_token)
.send()
.map_err(|e| {
warn!("querying itch.io failed: {}", e);
api::AuthError::ServiceFailed
})
.and_then(|mut response| {
response.json::<ItchMe>().map_err(|e| {
warn!("itch.io returned not-serializable output: {}", e);
api::AuthError::InternalError
})
})
.and_then(move |me: ItchMe| {
me.map_err(|e| {
debug!("getting userid for player {:?} failed: {:?}", player, e);
api::AuthError::BadCredentials
})
})
};
let (api_key, maybe_game_id) =
cfg::get_value(|c| (c.auth.itch_api_key.clone(), c.auth.itch_game_id));
match maybe_game_id {
// No game id, having a valid auth is enough
None => Box::new(auth_future.map(|me| Account::Itch {
display_name: me.display_name,
account_name: me.username,
user_id: me.id,
})),
// Yes game id, fetch and check against the user's keys for this game
Some(game_id) => Box::new(auth_future.and_then(move |me| {
let itch_id = me.id;
let cli = HTTP_CLIENT.lock().unwrap();
cli.get(&format!(
"https://itch.io/api/1/key/game/{}/download_keys",
game_id
))
.bearer_auth(api_key)
.query(&[("user_id", me.id)])
.send()
.map_err(|e| {
warn!("querying itch.io failed: {}", e);
api::AuthError::ServiceFailed
})
.and_then(|mut response| {
response.json::<ItchDownloadKeys>().map_err(|e| {
warn!("itch returned not-serializable output: {}", e);
api::AuthError::InternalError
})
})
.and_then(move |keys: ItchDownloadKeys| {
keys.map_err(move |e| {
debug!(
"querying download keys for itch user {} failed: {:?}",
itch_id, e
);
api::AuthError::BadCredentials
})
})
.map(|_keys| Account::Itch {
display_name: me.display_name,
account_name: me.username,
user_id: me.id,
})
})),
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment