Skip to content

Commit 8025a91

Browse files
committed
Initial pass of adding integration tests.
This version just does the bare minimum and logs in and out again.
1 parent a615f36 commit 8025a91

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

Cargo.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,14 @@ uuid = { version = "^1.8", features = ["serde", "v4"] }
1515
reqwest = { version = "^0.12", features = ["json", "cookies", "multipart"] }
1616

1717
[dev-dependencies]
18-
tokio = { version = '1', features = ['macros', 'rt-multi-thread'] }
18+
tokio = { version = '1', features = ['macros', 'rt-multi-thread'] }
19+
totp_rfc6238 = "0.6.1"
20+
anyhow = "1"
21+
thiserror = "1"
22+
dotenv = "0.15"
23+
base32 = "0.5.1"
24+
25+
[[test]]
26+
name = "integration"
27+
path = "integration/main.rs"
28+
harness = false

integration/main.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use base32::Alphabet;
2+
use vrchatapi::models::{EitherUserOrTwoFactor, TwoFactorAuthCode};
3+
4+
#[derive(Debug, thiserror::Error)]
5+
enum Error{
6+
#[error("Dotenv failed to initialize: {0}")]
7+
DotenvInitError(dotenv::Error),
8+
#[error("No Username provided or error decoding username: {0}")]
9+
NoUsername(dotenv::Error),
10+
#[error("No Password provided or error decoding password: {0}")]
11+
NoPassword(dotenv::Error),
12+
#[error("No Totp Secret provided or error decoding totp secret: {0}")]
13+
NoTotpSecret(dotenv::Error),
14+
#[error("We were unable to login with the provided credentials.")]
15+
UnableToLogin,
16+
#[error("No totp 2fa variant available.")]
17+
NoTotp2FAAvailable,
18+
#[error("Failed to get the current user: {0}")]
19+
GetCurrentUser(#[from] vrchatapi::apis::Error<vrchatapi::apis::authentication_api::GetCurrentUserError>),
20+
#[error("Failed to verify with 2fa: {0}")]
21+
Verify2FA(#[from] vrchatapi::apis::Error<vrchatapi::apis::authentication_api::Verify2FaError>),
22+
#[error("Failed to logout: {0}")]
23+
Logout(#[from] vrchatapi::apis::Error<vrchatapi::apis::authentication_api::LogoutError>),
24+
#[error("Failed to decode Totp from base32")]
25+
TOTPBase32,
26+
}
27+
28+
const VERSION: &str = env!("CARGO_PKG_VERSION");
29+
#[tokio::main]
30+
async fn main() {
31+
println!("Hello");
32+
match test().await {
33+
Ok(()) => {}
34+
Err(e) => eprint!("{e}")
35+
}
36+
}
37+
async fn test() -> Result<(), anyhow::Error>{
38+
dotenv::dotenv().map_err(|e|Error::DotenvInitError(e))?;
39+
let username = dotenv::var("USERNAME").map_err(|e|Error::NoUsername(e))?;
40+
let password = dotenv::var("PASSWORD").map_err(|e|Error::NoPassword(e))?;
41+
let totp_secret = dotenv::var("TOTP_SECRET").map_err(|e|Error::NoTotpSecret(e))?;
42+
let totp_secret = base32::decode(Alphabet::Rfc4648Lower {padding: false}, totp_secret.as_str()).ok_or(Error::TOTPBase32)?;
43+
let generator = totp_rfc6238::TotpGenerator::new()
44+
.build();
45+
46+
let mut client = vrchatapi::apis::configuration::Configuration::default();
47+
client.user_agent = Some(format!("vrchatapi-rust@{VERSION} https://github.com/vrchatapi/vrchatapi-rust/issues/new"));
48+
client.basic_auth = Some((username.clone(), Some(password)));
49+
let u = match vrchatapi::apis::authentication_api::get_current_user(&client).await.map_err(|e|Error::GetCurrentUser(e))? {
50+
EitherUserOrTwoFactor::CurrentUser(u) => u,
51+
EitherUserOrTwoFactor::RequiresTwoFactorAuth(r2fa) => {
52+
if !r2fa.requires_two_factor_auth.contains(&"totp".to_string()) {
53+
let _ = logout(&client).await; //Ignore logout error. This is just here, to hopefully avoid session spam.
54+
return Err(Error::NoTotp2FAAvailable)?;
55+
}
56+
57+
let code = generator.get_code(totp_secret.as_slice());
58+
println!("Generated code: {code}");
59+
if !vrchatapi::apis::authentication_api::verify2_fa(&client, TwoFactorAuthCode::new(code)).await.map_err(|e|Error::Verify2FA(e))?.verified {
60+
let _ = logout(&client).await; //Ignore logout error. This is just here, to hopefully avoid session spam.
61+
return Err(Error::UnableToLogin)?;
62+
}
63+
64+
match vrchatapi::apis::authentication_api::get_current_user(&client).await.map_err(|e|Error::GetCurrentUser(e))? {
65+
EitherUserOrTwoFactor::CurrentUser(u) => u,
66+
EitherUserOrTwoFactor::RequiresTwoFactorAuth(_) => return Err(Error::UnableToLogin)?,
67+
}
68+
}
69+
};
70+
println!("Logged in as: {} (Login Name was {username}", u.username.as_ref().map(String::as_str).unwrap_or("Unknown User"));
71+
72+
logout(&client).await?;
73+
Ok(())
74+
}
75+
76+
async fn logout(client: &vrchatapi::apis::configuration::Configuration) -> Result<(), anyhow::Error> {
77+
vrchatapi::apis::authentication_api::logout(&client).await.map_err(|e|Error::Logout(e))?;
78+
Ok(())
79+
}

0 commit comments

Comments
 (0)