test: add mikan client login test
This commit is contained in:
parent
a7f52fe0eb
commit
791b75b3af
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -3959,6 +3959,15 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b"
|
||||
|
||||
[[package]]
|
||||
name = "nanoid"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
@ -5152,6 +5161,7 @@ dependencies = [
|
||||
"maplit",
|
||||
"mockito",
|
||||
"moka",
|
||||
"nanoid",
|
||||
"once_cell",
|
||||
"opendal",
|
||||
"openidconnect",
|
||||
|
@ -115,6 +115,7 @@ reqwest_cookie_store = "0.8.0"
|
||||
downloader = { workspace = true }
|
||||
util = { workspace = true }
|
||||
fetch = { workspace = true }
|
||||
nanoid = "0.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "3"
|
||||
|
@ -16,7 +16,7 @@ impl CryptoService {
|
||||
Ok(Self { config })
|
||||
}
|
||||
|
||||
pub fn encrypt_data(&self, data: String) -> Result<String, CryptoError> {
|
||||
pub fn encrypt_string(&self, data: String) -> Result<String, CryptoError> {
|
||||
let key = rand::rng().random::<[u8; 32]>();
|
||||
let mut cocoon = Cocoon::new(&key);
|
||||
|
||||
@ -32,7 +32,7 @@ impl CryptoService {
|
||||
Ok(BASE64_URL_SAFE.encode(combined))
|
||||
}
|
||||
|
||||
pub fn decrypt_data(&self, data: &str) -> Result<String, CryptoError> {
|
||||
pub fn decrypt_string(&self, data: &str) -> Result<String, CryptoError> {
|
||||
let decoded = BASE64_URL_SAFE.decode(data)?;
|
||||
|
||||
let (key, remain) = decoded.split_at(32);
|
||||
@ -45,20 +45,17 @@ impl CryptoService {
|
||||
String::from_utf8(data).map_err(CryptoError::from)
|
||||
}
|
||||
|
||||
pub fn encrypt_credentials<T: Serialize>(
|
||||
&self,
|
||||
credentials: &T,
|
||||
) -> Result<String, CryptoError> {
|
||||
pub fn encrypt_serialize<T: Serialize>(&self, credentials: &T) -> Result<String, CryptoError> {
|
||||
let json = serde_json::to_string(credentials)?;
|
||||
|
||||
self.encrypt_data(json)
|
||||
self.encrypt_string(json)
|
||||
}
|
||||
|
||||
pub fn decrypt_credentials<T: for<'de> Deserialize<'de>>(
|
||||
pub fn decrypt_deserialize<T: for<'de> Deserialize<'de>>(
|
||||
&self,
|
||||
encrypted: &str,
|
||||
) -> Result<T, CryptoError> {
|
||||
let data = self.decrypt_data(encrypted)?;
|
||||
let data = self.decrypt_string(encrypted)?;
|
||||
|
||||
serde_json::from_str(&data).map_err(CryptoError::from)
|
||||
}
|
||||
|
@ -242,3 +242,92 @@ impl Deref for MikanClient {
|
||||
}
|
||||
|
||||
impl HttpClientTrait for MikanClient {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(unused_variables)]
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rstest::{fixture, rstest};
|
||||
use tracing::Level;
|
||||
|
||||
use super::*;
|
||||
use crate::test_utils::{
|
||||
app::UnitTestAppContext,
|
||||
crypto::build_testing_crypto_service,
|
||||
database::build_testing_database_service,
|
||||
mikan::{MikanMockServer, build_testing_mikan_client, build_testing_mikan_credential_form},
|
||||
tracing::try_init_testing_tracing,
|
||||
};
|
||||
|
||||
async fn create_testing_context(
|
||||
mikan_base_url: Url,
|
||||
) -> RecorderResult<Arc<dyn AppContextTrait>> {
|
||||
let mikan_client = build_testing_mikan_client(mikan_base_url.clone()).await?;
|
||||
let db_service = build_testing_database_service().await?;
|
||||
let crypto_service = build_testing_crypto_service().await?;
|
||||
let ctx = UnitTestAppContext::builder()
|
||||
.db(db_service)
|
||||
.crypto(crypto_service)
|
||||
.mikan(mikan_client)
|
||||
.build();
|
||||
|
||||
Ok(Arc::new(ctx))
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
fn before_each() {
|
||||
try_init_testing_tracing(Level::DEBUG);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_mikan_client_submit_credential_form(before_each: ()) -> RecorderResult<()> {
|
||||
let mut mikan_server = MikanMockServer::new().await?;
|
||||
|
||||
let app_ctx = create_testing_context(mikan_server.base_url().clone()).await?;
|
||||
|
||||
let _login_mock = mikan_server.mock_get_login_page();
|
||||
|
||||
let mikan_client = app_ctx.mikan();
|
||||
let crypto_service = app_ctx.crypto();
|
||||
|
||||
let credential_form = build_testing_mikan_credential_form();
|
||||
|
||||
let credential_model = mikan_client
|
||||
.submit_credential_form(app_ctx.clone(), 1, credential_form.clone())
|
||||
.await?;
|
||||
|
||||
let expected_username = &credential_form.username;
|
||||
let expected_password = &credential_form.password;
|
||||
|
||||
let found_username = crypto_service
|
||||
.decrypt_string(credential_model.username.as_deref().unwrap_or_default())?;
|
||||
let found_password = crypto_service
|
||||
.decrypt_string(credential_model.password.as_deref().unwrap_or_default())?;
|
||||
|
||||
assert_eq!(&found_username, expected_username);
|
||||
assert_eq!(&found_password, expected_password);
|
||||
|
||||
let has_login = mikan_client.has_login().await?;
|
||||
|
||||
assert!(!has_login);
|
||||
|
||||
assert_matches!(
|
||||
mikan_client.login().await,
|
||||
Err(RecorderError::Credential3rdError { .. })
|
||||
);
|
||||
|
||||
let mikan_client = mikan_client
|
||||
.fork_with_credential(app_ctx.clone(), credential_model.id)
|
||||
.await?;
|
||||
|
||||
mikan_client.login().await?;
|
||||
|
||||
let has_login = mikan_client.has_login().await?;
|
||||
|
||||
assert!(has_login);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -74,17 +74,17 @@ impl ActiveModel {
|
||||
let crypto = ctx.crypto();
|
||||
|
||||
if let ActiveValue::Set(Some(username)) = self.username {
|
||||
let username_enc = crypto.encrypt_credentials(&username)?;
|
||||
let username_enc = crypto.encrypt_string(username)?;
|
||||
self.username = ActiveValue::Set(Some(username_enc));
|
||||
}
|
||||
|
||||
if let ActiveValue::Set(Some(password)) = self.password {
|
||||
let password_enc = crypto.encrypt_credentials(&password)?;
|
||||
let password_enc = crypto.encrypt_string(password)?;
|
||||
self.password = ActiveValue::Set(Some(password_enc));
|
||||
}
|
||||
|
||||
if let ActiveValue::Set(Some(cookies)) = self.cookies {
|
||||
let cookies_enc = crypto.encrypt_credentials(&cookies)?;
|
||||
let cookies_enc = crypto.encrypt_string(cookies)?;
|
||||
self.cookies = ActiveValue::Set(Some(cookies_enc));
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ impl Model {
|
||||
source: None.into(),
|
||||
})?;
|
||||
|
||||
let username: String = crypto.decrypt_credentials(&username_enc)?;
|
||||
let username: String = crypto.decrypt_string(&username_enc)?;
|
||||
|
||||
let password_enc = self
|
||||
.password
|
||||
@ -124,10 +124,10 @@ impl Model {
|
||||
source: None.into(),
|
||||
})?;
|
||||
|
||||
let password: String = crypto.decrypt_credentials(&password_enc)?;
|
||||
let password: String = crypto.decrypt_string(&password_enc)?;
|
||||
|
||||
let cookies: Option<String> = if let Some(cookies_enc) = self.cookies {
|
||||
let cookies = crypto.decrypt_credentials(&cookies_enc)?;
|
||||
let cookies = crypto.decrypt_string(&cookies_enc)?;
|
||||
Some(cookies)
|
||||
} else {
|
||||
None
|
||||
|
Loading…
Reference in New Issue
Block a user