use std::collections::BTreeMap;
use std::fmt;
use crate::routing::Route;
use crate::types::auth::AccessToken;
use crate::types::{Message, Timestamp};
use crate::Modio;
use crate::Result;
pub use crate::types::auth::{Link, Links, Terms};
#[derive(Clone, Eq, PartialEq)]
pub struct Credentials {
pub api_key: String,
pub token: Option<Token>,
}
#[derive(Clone, Eq, PartialEq)]
pub struct Token {
pub value: String,
pub expired_at: Option<Timestamp>,
}
impl fmt::Debug for Credentials {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.token.is_some() {
f.write_str("Credentials(apikey+token)")
} else {
f.write_str("Credentials(apikey)")
}
}
}
impl Credentials {
pub fn new<S: Into<String>>(api_key: S) -> Credentials {
Credentials {
api_key: api_key.into(),
token: None,
}
}
pub fn with_token<S: Into<String>, T: Into<String>>(api_key: S, token: T) -> Credentials {
Credentials {
api_key: api_key.into(),
token: Some(Token {
value: token.into(),
expired_at: None,
}),
}
}
}
impl From<&str> for Credentials {
fn from(api_key: &str) -> Credentials {
Credentials::new(api_key)
}
}
impl From<(&str, &str)> for Credentials {
fn from((api_key, token): (&str, &str)) -> Credentials {
Credentials::with_token(api_key, token)
}
}
impl From<String> for Credentials {
fn from(api_key: String) -> Credentials {
Credentials::new(api_key)
}
}
impl From<(String, String)> for Credentials {
fn from((api_key, token): (String, String)) -> Credentials {
Credentials::with_token(api_key, token)
}
}
#[derive(Clone)]
pub struct Auth {
modio: Modio,
}
impl Auth {
pub(crate) fn new(modio: Modio) -> Self {
Self { modio }
}
pub async fn terms(self) -> Result<Terms> {
self.modio.request(Route::Terms).send().await
}
pub async fn request_code(self, email: &str) -> Result<()> {
self.modio
.request(Route::OAuthEmailRequest)
.form(&[("email", email)])
.send::<Message>()
.await?;
Ok(())
}
pub async fn security_code(self, code: &str) -> Result<Credentials> {
let t = self
.modio
.request(Route::OAuthEmailExchange)
.form(&[("security_code", code)])
.send::<AccessToken>()
.await?;
let token = Token {
value: t.value,
expired_at: t.expired_at,
};
Ok(Credentials {
api_key: self.modio.inner.credentials.api_key.clone(),
token: Some(token),
})
}
pub async fn external<T>(self, auth_options: T) -> Result<Credentials>
where
T: Into<AuthOptions>,
{
let AuthOptions { route, params } = auth_options.into();
let t = self
.modio
.request(route)
.form(¶ms)
.send::<AccessToken>()
.await?;
let token = Token {
value: t.value,
expired_at: t.expired_at,
};
Ok(Credentials {
api_key: self.modio.inner.credentials.api_key.clone(),
token: Some(token),
})
}
pub async fn logout(self) -> Result<()> {
self.modio
.request(Route::OAuthLogout)
.send::<Message>()
.await?;
Ok(())
}
}
pub struct AuthOptions {
route: Route,
params: BTreeMap<&'static str, String>,
}
impl From<OculusOptions> for AuthOptions {
fn from(options: OculusOptions) -> AuthOptions {
AuthOptions {
route: Route::ExternalAuthMeta,
params: options.params,
}
}
}
impl From<SteamOptions> for AuthOptions {
fn from(options: SteamOptions) -> AuthOptions {
AuthOptions {
route: Route::ExternalAuthSteam,
params: options.params,
}
}
}
impl From<SwitchOptions> for AuthOptions {
fn from(options: SwitchOptions) -> AuthOptions {
AuthOptions {
route: Route::ExternalAuthSwitch,
params: options.params,
}
}
}
impl From<XboxOptions> for AuthOptions {
fn from(options: XboxOptions) -> AuthOptions {
AuthOptions {
route: Route::ExternalAuthXbox,
params: options.params,
}
}
}
impl From<DiscordOptions> for AuthOptions {
fn from(options: DiscordOptions) -> AuthOptions {
AuthOptions {
route: Route::ExternalAuthDiscord,
params: options.params,
}
}
}
impl From<GoogleOptions> for AuthOptions {
fn from(options: GoogleOptions) -> AuthOptions {
AuthOptions {
route: Route::ExternalAuthGoogle,
params: options.params,
}
}
}
pub struct GalaxyOptions {
params: BTreeMap<&'static str, String>,
}
impl GalaxyOptions {
pub fn new<T>(ticket: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("appdata", ticket.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct ItchioOptions {
params: BTreeMap<&'static str, String>,
}
impl ItchioOptions {
pub fn new<T>(token: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("itchio_token", token.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct OculusOptions {
params: BTreeMap<&'static str, String>,
}
impl OculusOptions {
pub fn new_for_quest<T>(nonce: T, user_id: u64, auth_token: T) -> Self
where
T: Into<String>,
{
OculusOptions::new("quest".to_owned(), nonce.into(), user_id, auth_token.into())
}
pub fn new_for_rift<T>(nonce: T, user_id: u64, auth_token: T) -> Self
where
T: Into<String>,
{
OculusOptions::new("rift".to_owned(), nonce.into(), user_id, auth_token.into())
}
fn new(device: String, nonce: String, user_id: u64, auth_token: String) -> Self {
let mut params = BTreeMap::new();
params.insert("device", device);
params.insert("nonce", nonce);
params.insert("user_id", user_id.to_string());
params.insert("auth_token", auth_token);
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct SteamOptions {
params: BTreeMap<&'static str, String>,
}
impl SteamOptions {
pub fn new<T>(ticket: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("appdata", ticket.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct SwitchOptions {
params: BTreeMap<&'static str, String>,
}
impl SwitchOptions {
pub fn new<T>(id_token: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("id_token", id_token.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct XboxOptions {
params: BTreeMap<&'static str, String>,
}
impl XboxOptions {
pub fn new<T>(token: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("xbox_token", token.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct DiscordOptions {
params: BTreeMap<&'static str, String>,
}
impl DiscordOptions {
pub fn new<T>(token: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("discord_token", token.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}
pub struct GoogleOptions {
params: BTreeMap<&'static str, String>,
}
impl GoogleOptions {
pub fn new<T>(token: T) -> Self
where
T: Into<String>,
{
let mut params = BTreeMap::new();
params.insert("id_token", token.into());
Self { params }
}
option!(email >> "email");
option!(
expired_at u64 >> "date_expires"
);
option!(terms_agreed bool >> "terms_agreed");
}