Skip to content

Commit a6df250

Browse files
committed
🐛 Fix breaking changes in actix, secrery::Secret -> secrey::SecretBox
1 parent 609128c commit a6df250

File tree

7 files changed

+45
-42
lines changed

7 files changed

+45
-42
lines changed

src/authentication/middleware.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use crate::utils::{e500, see_other};
33
use actix_web::body::MessageBody;
44
use actix_web::dev::{ServiceRequest, ServiceResponse};
55
use actix_web::error::InternalError;
6+
use actix_web::middleware::Next;
67
use actix_web::{FromRequest, HttpMessage};
7-
use actix_web_lab::middleware::Next;
88
use std::fmt::Display;
99
use std::ops::Deref;
1010
use uuid::Uuid;

src/authentication/password.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::telemetry::spawn_blocking_with_tracing;
22
use anyhow::Context;
33

44
use argon2::{Algorithm, Argon2, Params, PasswordHash, PasswordHasher, PasswordVerifier, Version};
5-
use secrecy::{ExposeSecret, Secret};
5+
use secrecy::{ExposeSecret, SecretString};
66
use sqlx::PgPool;
77

88
use argon2::password_hash::SaltString;
@@ -19,7 +19,7 @@ pub enum AuthError {
1919
// This user input maps this struct, which is commonly called DTO: Data Transfer Object.
2020
pub struct Credentials {
2121
pub username: String,
22-
pub password: Secret<String>,
22+
pub password: SecretString,
2323
}
2424

2525
#[tracing::instrument(name = "Validate credentials", skip(credentials, pool))]
@@ -29,12 +29,11 @@ pub async fn validate_credentials(
2929
) -> Result<Uuid, AuthError> {
3030
// These two lines are for forcing calculating hash in blocking task.
3131
let mut user_id = None;
32-
let mut expected_password_hash = Secret::new(
32+
let mut expected_password_hash = SecretString::new(Box::from(
3333
"$argon2id$v=19$m=15000,t=2,p=1$\
3434
gZiV/M1gPc22ElAH/Jh1Hw$\
35-
CWOrkoo7oJBQ/iyh7uJ0LO2aLEfrHwTWllSAxT0zRno"
36-
.to_string(),
37-
);
35+
CWOrkoo7oJBQ/iyh7uJ0LO2aLEfrHwTWllSAxT0zRno",
36+
));
3837

3938
// Fetch user information from the database
4039
if let Some((stored_user_id, stored_hash_password)) =
@@ -60,8 +59,8 @@ pub async fn validate_credentials(
6059
skip(expected_password_hash, password_candidate)
6160
)]
6261
fn verify_password_hash(
63-
expected_password_hash: Secret<String>,
64-
password_candidate: Secret<String>,
62+
expected_password_hash: SecretString,
63+
password_candidate: SecretString,
6564
) -> Result<(), AuthError> {
6665
// Calculate the password hash by using the password_hash stored in the database, following PHC string format.
6766
let expected_password_hash = PasswordHash::new(expected_password_hash.expose_secret())
@@ -81,7 +80,7 @@ fn verify_password_hash(
8180
pub async fn get_stored_credentials(
8281
credentials: &Credentials,
8382
pool: &PgPool,
84-
) -> Result<Option<(Uuid, Secret<String>)>, anyhow::Error> {
83+
) -> Result<Option<(Uuid, SecretString)>, anyhow::Error> {
8584
let q = sqlx::query!(
8685
r#"
8786
SELECT user_id, password_hash
@@ -95,7 +94,7 @@ pub async fn get_stored_credentials(
9594
.fetch_optional(pool)
9695
.await
9796
.context("Failed to perform query to validate auth credentials.")?
98-
.map(|row| (row.user_id, Secret::new(row.password_hash)));
97+
.map(|row| (row.user_id, SecretString::new(Box::from(row.password_hash))));
9998
Ok(row)
10099
}
101100

@@ -122,7 +121,7 @@ pub async fn change_password_in_db(
122121
Ok(())
123122
}
124123

125-
fn compute_password_hash(password: Password) -> Result<Secret<String>, anyhow::Error> {
124+
fn compute_password_hash(password: Password) -> Result<SecretString, anyhow::Error> {
126125
// 1. Generate random salt
127126
let salt = SaltString::generate(&mut rand::thread_rng());
128127
// 2. Argon2 algorithm.
@@ -134,11 +133,11 @@ fn compute_password_hash(password: Password) -> Result<Secret<String>, anyhow::E
134133
.hash_password(password.expose_secret().as_bytes(), &salt)?
135134
.to_string();
136135

137-
Ok(Secret::new(password_hash))
136+
Ok(SecretString::new(Box::from(password_hash)))
138137
}
139138

140139
#[derive(Clone)]
141-
pub struct Password(Secret<String>);
140+
pub struct Password(SecretString);
142141

143142
impl Password {
144143
/// # OWASP’s a minimum set of requirements for password
@@ -163,14 +162,14 @@ impl Password {
163162
));
164163
}
165164

166-
Ok(Password(Secret::new(s)))
165+
Ok(Password(SecretString::new(Box::from(s))))
167166
}
168167

169-
pub fn inner_ref(&self) -> &Secret<String> {
168+
pub fn inner_ref(&self) -> &SecretString {
170169
&self.0
171170
}
172171

173-
pub fn expose_secret(&self) -> String {
174-
self.0.expose_secret().clone()
172+
pub fn expose_secret(&self) -> &str {
173+
self.0.expose_secret()
175174
}
176175
}

src/configuration.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use secrecy::{ExposeSecret, Secret};
1+
use secrecy::{ExposeSecret, SecretString};
22
use serde::Deserialize;
33
use serde_aux::field_attributes::deserialize_number_from_string;
44
use sqlx::postgres::{PgConnectOptions, PgSslMode};
@@ -16,7 +16,7 @@ pub struct Settings {
1616
pub database: DatabaseSettings,
1717
pub application: ApplicationSettings,
1818
pub email_client: EmailClientSettings,
19-
pub redis_uri: Secret<String>,
19+
pub redis_uri: SecretString,
2020
}
2121

2222
#[derive(Deserialize, Clone)]
@@ -25,7 +25,7 @@ pub struct ApplicationSettings {
2525
#[serde(deserialize_with = "deserialize_number_from_string")]
2626
pub port: u16,
2727
pub base_url: String,
28-
pub hmac_secret: Secret<String>,
28+
pub hmac_secret: SecretString,
2929
}
3030

3131
impl ApplicationSettings {
@@ -37,7 +37,7 @@ impl ApplicationSettings {
3737
#[derive(Deserialize, Clone)]
3838
pub struct DatabaseSettings {
3939
pub username: String,
40-
pub password: Secret<String>,
40+
pub password: SecretString,
4141
pub host: String,
4242
#[serde(deserialize_with = "deserialize_number_from_string")]
4343
pub port: u16,
@@ -62,15 +62,15 @@ impl DatabaseSettings {
6262

6363
pub fn with_db(&self) -> PgConnectOptions {
6464
let opts = self.without_db().database(&self.database_name);
65-
opts.log_statements(tracing_log::log::LevelFilter::Trace)
65+
opts.log_statements(log::LevelFilter::Trace)
6666
}
6767
}
6868

6969
#[derive(Deserialize, Clone)]
7070
pub struct EmailClientSettings {
7171
pub base_url: String,
7272
pub sender_email: String,
73-
pub authorization_token: Secret<String>,
73+
pub authorization_token: SecretString,
7474
pub timeout_milliseconds: u64,
7575
}
7676

src/email_client.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use secrecy::{ExposeSecret, Secret};
1+
use secrecy::{ExposeSecret, SecretString};
22
use serde::Serialize;
33

44
use crate::domain::SubscriberEmail;
@@ -11,14 +11,14 @@ pub struct EmailClient {
1111
// ? SubscriberEmail is a domain type, so why is it used here?
1212
base_url: String,
1313
// external service url to send email
14-
authorization_token: Secret<String>,
14+
authorization_token: SecretString,
1515
}
1616

1717
impl EmailClient {
1818
pub fn new(
1919
base_url: String,
2020
sender: SubscriberEmail,
21-
authorization_token: Secret<String>,
21+
authorization_token: SecretString,
2222
time_out: std::time::Duration,
2323
) -> Self {
2424
let http_client = reqwest::Client::builder()
@@ -102,7 +102,7 @@ mod tests {
102102
use fake::faker::internet::en::SafeEmail;
103103
use fake::faker::lorem::en::{Paragraph, Sentence};
104104
use fake::{Fake, Faker};
105-
use secrecy::Secret;
105+
use secrecy::SecretString;
106106
use wiremock::http::Method;
107107
use wiremock::matchers::{any, header, header_exists, method, path};
108108
use wiremock::{Mock, MockServer, Request, ResponseTemplate};
@@ -128,8 +128,8 @@ mod tests {
128128
SubscriberEmail::parse(SafeEmail().fake()).unwrap()
129129
}
130130

131-
fn authorization_token() -> Secret<String> {
132-
Secret::new(Faker.fake())
131+
fn authorization_token() -> SecretString {
132+
SecretString::new(Box::from(Faker.fake::<String>()))
133133
}
134134

135135
fn subject() -> String {

src/routes/admin/password/post.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ use crate::routes::admin::dashboard::get_username;
66
use crate::utils::{e500, see_other};
77
use actix_web::{web, HttpResponse};
88
use actix_web_flash_messages::FlashMessage;
9-
use secrecy::{ExposeSecret, Secret};
9+
use secrecy::{ExposeSecret, SecretBox};
1010
use serde::Deserialize;
1111
use sqlx::PgPool;
1212

1313
#[derive(Deserialize)]
1414
pub struct FormData {
15-
current_password: Secret<String>,
16-
new_password: Secret<String>,
17-
new_password_check: Secret<String>,
15+
current_password: SecretBox<String>,
16+
new_password: SecretBox<String>,
17+
new_password_check: SecretBox<String>,
1818
}
1919

2020
struct ValidPasswords {

src/routes/login/post.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use actix_web::http::header::LOCATION;
33
use actix_web::http::StatusCode;
44
use actix_web::{web, HttpResponse, ResponseError};
55
use actix_web_flash_messages::FlashMessage;
6-
use secrecy::Secret;
6+
use secrecy::SecretString;
77
use serde::Deserialize;
88
use sqlx::PgPool;
99
use std::fmt::{Debug, Formatter};
@@ -15,7 +15,7 @@ use crate::session_state::TypedSession;
1515
#[derive(Deserialize)]
1616
pub struct FormData {
1717
username: String,
18-
password: Secret<String>,
18+
password: SecretString,
1919
}
2020

2121
#[derive(thiserror::Error)]

src/startup.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ use std::net::TcpListener;
55
use crate::authentication::reject_anonymous_user;
66
use actix_web::cookie::Key;
77
use actix_web::dev::Server;
8+
use actix_web::middleware::from_fn;
89
use actix_web::{web, App, HttpServer};
910
use actix_web_flash_messages::storage::CookieMessageStore;
1011
use actix_web_flash_messages::FlashMessagesFramework;
11-
use actix_web_lab::middleware::from_fn;
12-
use secrecy::{ExposeSecret, Secret};
12+
use secrecy::{ExposeSecret, SecretString};
13+
1314
use sqlx::postgres::PgPoolOptions;
1415
use sqlx::PgPool;
1516
use tracing_actix_web::TracingLogger;
@@ -33,7 +34,10 @@ impl Application {
3334

3435
let email_client = configuration.email_client.client();
3536
let listener = TcpListener::bind(configuration.application.addr())?;
36-
let port = listener.local_addr().unwrap().port();
37+
let port = listener
38+
.local_addr()
39+
.expect("Failed to get local address")
40+
.port();
3741
let server = run(
3842
listener,
3943
connection_pool,
@@ -60,7 +64,7 @@ impl Application {
6064
pub struct ApplicationBaseUrl(pub String);
6165

6266
#[derive(Clone)]
63-
pub struct HmacSecret(pub Secret<String>);
67+
pub struct HmacSecret(pub SecretString);
6468

6569
pub fn get_connection_pool(database_settings: &DatabaseSettings) -> PgPool {
6670
PgPoolOptions::new()
@@ -73,8 +77,8 @@ pub async fn run(
7377
db_pool: PgPool,
7478
email_client: EmailClient,
7579
base_url: String,
76-
hmac_secret: Secret<String>,
77-
redis_uri: Secret<String>,
80+
hmac_secret: SecretString,
81+
redis_uri: SecretString,
7882
) -> Result<Server, anyhow::Error> {
7983
let connection = web::Data::new(db_pool);
8084
let email_client = web::Data::new(email_client);

0 commit comments

Comments
 (0)