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