bitwarden_generators/username_forwarders/
duckduckgo.rs1use reqwest::{header::CONTENT_TYPE, StatusCode};
2
3use crate::username::UsernameError;
4
5pub async fn generate(http: &reqwest::Client, token: String) -> Result<String, UsernameError> {
6 generate_with_api_url(http, token, "https://quack.duckduckgo.com".into()).await
7}
8
9async fn generate_with_api_url(
10 http: &reqwest::Client,
11 token: String,
12 api_url: String,
13) -> Result<String, UsernameError> {
14 let response = http
15 .post(format!("{api_url}/api/email/addresses"))
16 .header(CONTENT_TYPE, "application/json")
17 .bearer_auth(token)
18 .send()
19 .await?;
20
21 if response.status() == StatusCode::UNAUTHORIZED {
22 return Err(UsernameError::InvalidApiKey);
23 }
24
25 response.error_for_status_ref()?;
27
28 #[derive(serde::Deserialize)]
29 struct Response {
30 address: String,
31 }
32 let response: Response = response.json().await?;
33
34 Ok(format!("{}@duck.com", response.address))
35}
36
37#[cfg(test)]
38mod tests {
39 use serde_json::json;
40
41 use crate::username::UsernameError;
42 #[tokio::test]
43 async fn test_mock_server() {
44 use wiremock::{matchers, Mock, ResponseTemplate};
45
46 let server = wiremock::MockServer::start().await;
47
48 server
50 .register(
51 Mock::given(matchers::path("/api/email/addresses"))
52 .and(matchers::method("POST"))
53 .and(matchers::header("Content-Type", "application/json"))
54 .and(matchers::header("Authorization", "Bearer MY_TOKEN"))
55 .respond_with(ResponseTemplate::new(201).set_body_json(json!({
56 "address": "bw7prt"
57 })))
58 .expect(1),
59 )
60 .await;
61 server
63 .register(
64 Mock::given(matchers::path("/api/email/addresses"))
65 .and(matchers::method("POST"))
66 .and(matchers::header("Content-Type", "application/json"))
67 .and(matchers::header("Authorization", "Bearer MY_FAKE_TOKEN"))
68 .respond_with(ResponseTemplate::new(401))
69 .expect(1),
70 )
71 .await;
72
73 let address = super::generate_with_api_url(
74 &reqwest::Client::new(),
75 "MY_TOKEN".into(),
76 format!("http://{}", server.address()),
77 )
78 .await
79 .unwrap();
80 assert_eq!(address, "[email protected]");
81
82 let fake_token_error = super::generate_with_api_url(
83 &reqwest::Client::new(),
84 "MY_FAKE_TOKEN".into(),
85 format!("http://{}", server.address()),
86 )
87 .await
88 .unwrap_err();
89
90 assert_eq!(
91 fake_token_error.to_string(),
92 UsernameError::InvalidApiKey.to_string()
93 );
94
95 server.verify().await;
96 }
97}