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 serde_json::json;
43
44 use crate::username::UsernameError;
45 #[tokio::test]
46 async fn test_mock_server() {
47 use wiremock::{Mock, ResponseTemplate, matchers};
48
49 let server = wiremock::MockServer::start().await;
50
51 server
53 .register(
54 Mock::given(matchers::path("/api/email/addresses"))
55 .and(matchers::method("POST"))
56 .and(matchers::header("Content-Type", "application/json"))
57 .and(matchers::header("Authorization", "Bearer MY_TOKEN"))
58 .respond_with(ResponseTemplate::new(201).set_body_json(json!({
59 "address": "bw7prt"
60 })))
61 .expect(1),
62 )
63 .await;
64 server
66 .register(
67 Mock::given(matchers::path("/api/email/addresses"))
68 .and(matchers::method("POST"))
69 .and(matchers::header("Content-Type", "application/json"))
70 .and(matchers::header("Authorization", "Bearer MY_FAKE_TOKEN"))
71 .respond_with(ResponseTemplate::new(401))
72 .expect(1),
73 )
74 .await;
75
76 let address = super::generate_with_api_url(
77 &reqwest::Client::new(),
78 "MY_TOKEN".into(),
79 format!("http://{}", server.address()),
80 )
81 .await
82 .unwrap();
83 assert_eq!(address, "[email protected]");
84
85 let fake_token_error = super::generate_with_api_url(
86 &reqwest::Client::new(),
87 "MY_FAKE_TOKEN".into(),
88 format!("http://{}", server.address()),
89 )
90 .await
91 .unwrap_err();
92
93 assert_eq!(
94 fake_token_error.to_string(),
95 UsernameError::InvalidApiKey.to_string()
96 );
97
98 server.verify().await;
99 }
100}