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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b"
|
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]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -5152,6 +5161,7 @@ dependencies = [
|
|||||||
"maplit",
|
"maplit",
|
||||||
"mockito",
|
"mockito",
|
||||||
"moka",
|
"moka",
|
||||||
|
"nanoid",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"opendal",
|
"opendal",
|
||||||
"openidconnect",
|
"openidconnect",
|
||||||
|
@ -115,6 +115,7 @@ reqwest_cookie_store = "0.8.0"
|
|||||||
downloader = { workspace = true }
|
downloader = { workspace = true }
|
||||||
util = { workspace = true }
|
util = { workspace = true }
|
||||||
fetch = { workspace = true }
|
fetch = { workspace = true }
|
||||||
|
nanoid = "0.4.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "3"
|
serial_test = "3"
|
||||||
|
@ -16,7 +16,7 @@ impl CryptoService {
|
|||||||
Ok(Self { config })
|
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 key = rand::rng().random::<[u8; 32]>();
|
||||||
let mut cocoon = Cocoon::new(&key);
|
let mut cocoon = Cocoon::new(&key);
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ impl CryptoService {
|
|||||||
Ok(BASE64_URL_SAFE.encode(combined))
|
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 decoded = BASE64_URL_SAFE.decode(data)?;
|
||||||
|
|
||||||
let (key, remain) = decoded.split_at(32);
|
let (key, remain) = decoded.split_at(32);
|
||||||
@ -45,20 +45,17 @@ impl CryptoService {
|
|||||||
String::from_utf8(data).map_err(CryptoError::from)
|
String::from_utf8(data).map_err(CryptoError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encrypt_credentials<T: Serialize>(
|
pub fn encrypt_serialize<T: Serialize>(&self, credentials: &T) -> Result<String, CryptoError> {
|
||||||
&self,
|
|
||||||
credentials: &T,
|
|
||||||
) -> Result<String, CryptoError> {
|
|
||||||
let json = serde_json::to_string(credentials)?;
|
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,
|
&self,
|
||||||
encrypted: &str,
|
encrypted: &str,
|
||||||
) -> Result<T, CryptoError> {
|
) -> Result<T, CryptoError> {
|
||||||
let data = self.decrypt_data(encrypted)?;
|
let data = self.decrypt_string(encrypted)?;
|
||||||
|
|
||||||
serde_json::from_str(&data).map_err(CryptoError::from)
|
serde_json::from_str(&data).map_err(CryptoError::from)
|
||||||
}
|
}
|
||||||
|
@ -242,3 +242,92 @@ impl Deref for MikanClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HttpClientTrait 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();
|
let crypto = ctx.crypto();
|
||||||
|
|
||||||
if let ActiveValue::Set(Some(username)) = self.username {
|
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));
|
self.username = ActiveValue::Set(Some(username_enc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ActiveValue::Set(Some(password)) = self.password {
|
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));
|
self.password = ActiveValue::Set(Some(password_enc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ActiveValue::Set(Some(cookies)) = self.cookies {
|
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));
|
self.cookies = ActiveValue::Set(Some(cookies_enc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ impl Model {
|
|||||||
source: None.into(),
|
source: None.into(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let username: String = crypto.decrypt_credentials(&username_enc)?;
|
let username: String = crypto.decrypt_string(&username_enc)?;
|
||||||
|
|
||||||
let password_enc = self
|
let password_enc = self
|
||||||
.password
|
.password
|
||||||
@ -124,10 +124,10 @@ impl Model {
|
|||||||
source: None.into(),
|
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: 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)
|
Some(cookies)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
Loading…
Reference in New Issue
Block a user