Skip to content

Commit 131ffd0

Browse files
committed
refactor secret again
1 parent 3bc3800 commit 131ffd0

File tree

5 files changed

+50
-53
lines changed

5 files changed

+50
-53
lines changed

Cargo.toml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,18 @@ opt-level = "z"
2424
strip = true
2525

2626
[workspace.dependencies]
27-
anyhow = "1.0.78"
27+
anyhow = "1.0.79"
2828
argon2 = "0.5.2"
29-
assert_cmd = "2.0.12"
29+
assert_cmd = "2.0.13"
3030
async-stream = {version = "0.3.5"}
31-
async-trait = "0.1.76"
32-
axum = {version = "0.7.3", features = ["multipart"]}
33-
axum-extra = {version = "0.9.1", features = ["async-read-body"]}
34-
base64 = "0.21.5"
31+
async-trait = "0.1.77"
32+
axum = {version = "0.7.4", features = ["multipart"]}
33+
axum-extra = {version = "0.9.2", features = ["async-read-body"]}
34+
base64 = "0.21.7"
3535
bincode = "1.3.3"
3636
build_html = "2.4.0"
3737
chrono = {version = "0.4.31", features = ["serde"]}
38-
clap = {version = "4.4.11", features = ["derive"]}
38+
clap = {version = "4.4.18", features = ["derive"]}
3939
config = {version = "0.13.4", default-features = false, features = ["toml"]}
4040
cuid2 = "0.1.2"
4141
fake = {version = "2.9.2", features = ['derive', 'uuid', 'chrono']}
@@ -53,16 +53,16 @@ qrcodegen = "1.8.0"
5353
rand = "0.8.5"
5454
regex = "1.10.2"
5555
reqwest = {version = "0.11.23", default-features = false, features = ["json", "multipart", "stream", "rustls-tls"]}
56-
serde = {version = "1.0.193", features = ["derive"]}
57-
serde_json = "1.0.108"
56+
serde = {version = "1.0.195", features = ["derive"]}
57+
serde_json = "1.0.111"
5858
sled = "0.34.7"
5959
strum = { version = "0.25.0", features = ["derive"] }
6060
test-context = "0.1.4"
61-
thiserror = "1.0.53"
61+
thiserror = "1.0.56"
6262
tokio = {version = "1.35.1", features = ["macros", "time", "process", "net", "rt-multi-thread"]}
6363
tokio-util = "0.7.10"
6464
tower = {version = "0.4.13", features = ["util"]}
65-
tower-http = {version = "0.5.0", features = ["fs"]}
65+
tower-http = {version = "0.5.1", features = ["fs"]}
6666
tracing = "0.1.40"
6767
tracing-subscriber = "0.3.18"
6868
url = "2.5.0"

api/src/database/mod.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::sync::Arc;
22
use std::time::Duration;
33
use std::{collections::BTreeSet, path::PathBuf};
44

5+
use crate::util::secret::SecretHash;
56
use crate::{
67
configure::DatabaseConfig,
78
error::{ApiError, ApiResult},
@@ -204,7 +205,7 @@ impl FilePath {
204205
pub struct MetaDataFile {
205206
pub created_at: DateTime<Utc>,
206207
pub expiration_date: DateTime<Utc>,
207-
pub auth: Option<String>,
208+
pub secret: Option<SecretHash>,
208209
pub delete_manually: bool,
209210
pub max_download: Option<u32>,
210211
pub count_downloads: u32,
@@ -309,7 +310,7 @@ mod tests {
309310
let meta = MetaDataFile {
310311
created_at: Utc::now(),
311312
expiration_date: Utc::now() + chrono::Duration::seconds(10),
312-
auth: None,
313+
secret: None,
313314
delete_manually: true,
314315
max_download: None,
315316
count_downloads: 1,
@@ -323,7 +324,7 @@ mod tests {
323324
let result = ctx.state.db.fetch(&path).unwrap().unwrap();
324325
assert_eq!(result.created_at, meta.created_at);
325326
assert_eq!(result.expiration_date, meta.expiration_date);
326-
assert_eq!(result.auth, meta.auth);
327+
assert_eq!(result.secret, meta.secret);
327328
assert_eq!(result.max_download, meta.max_download);
328329
assert_eq!(result.count_downloads, meta.count_downloads);
329330
}
@@ -335,7 +336,7 @@ mod tests {
335336
let meta = MetaDataFile {
336337
created_at: Utc::now(),
337338
expiration_date: Utc::now() + chrono::Duration::seconds(10),
338-
auth: None,
339+
secret: None,
339340
delete_manually: true,
340341
max_download: None,
341342
count_downloads: 0,
@@ -349,7 +350,7 @@ mod tests {
349350
let result = ctx.state.db.fetch_count(&path).await.unwrap().unwrap();
350351
assert_eq!(result.created_at, meta.created_at);
351352
assert_eq!(result.expiration_date, meta.expiration_date);
352-
assert_eq!(result.auth, meta.auth);
353+
assert_eq!(result.secret, meta.secret);
353354
assert_eq!(result.max_download, meta.max_download);
354355
assert_eq!(result.count_downloads, meta.count_downloads);
355356
}
@@ -361,7 +362,7 @@ mod tests {
361362
let meta = MetaDataFile {
362363
created_at: Utc::now(),
363364
expiration_date: Utc::now() + chrono::Duration::seconds(10),
364-
auth: None,
365+
secret: None,
365366
delete_manually: true,
366367
max_download: None,
367368
count_downloads: 0,
@@ -376,7 +377,7 @@ mod tests {
376377
let result = ctx.state.db.fetch_count(&path).await.unwrap().unwrap();
377378
assert_eq!(result.created_at, meta.created_at);
378379
assert_eq!(result.expiration_date, meta.expiration_date);
379-
assert_eq!(result.auth, meta.auth);
380+
assert_eq!(result.secret, meta.secret);
380381
assert_eq!(result.max_download, meta.max_download);
381382
assert_eq!(result.count_downloads, meta.count_downloads + 1);
382383
}
@@ -388,7 +389,7 @@ mod tests {
388389
let meta = MetaDataFile {
389390
created_at: Utc::now(),
390391
expiration_date: Utc::now() + chrono::Duration::seconds(10),
391-
auth: None,
392+
secret: None,
392393
delete_manually: true,
393394
max_download: None,
394395
count_downloads: 0,
@@ -410,7 +411,7 @@ mod tests {
410411
let meta = MetaDataFile {
411412
created_at: Utc::now(),
412413
expiration_date: Utc::now(),
413-
auth: None,
414+
secret: None,
414415
delete_manually: true,
415416
max_download: None,
416417
count_downloads: 0,
@@ -433,7 +434,7 @@ mod tests {
433434
let meta = MetaDataFile {
434435
created_at: Utc::now(),
435436
expiration_date: Utc::now() + chrono::Duration::seconds(10),
436-
auth: None,
437+
secret: None,
437438
delete_manually: true,
438439
max_download: None,
439440
count_downloads: 0,

api/src/service/file.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::error::{ApiError, ApiResult, ToApiResult};
2-
use crate::util::secret::Secret;
2+
use crate::util::secret::{Secret, SecretHash};
33
use anyhow::anyhow;
44
use axum::extract::multipart::Field;
55
use axum::extract::Multipart;
@@ -22,7 +22,7 @@ pub async fn store(
2222
secret: Option<Secret>,
2323
mut multipart: Multipart,
2424
) -> ApiResult<(FilePath, DateTime<Utc>)> {
25-
let auth = secret.map(|s| s.hash()).transpose()?;
25+
let secret = secret.map(|s| s.hash()).transpose()?;
2626
let expire_secs = query
2727
.expire_time
2828
.unwrap_or(state.config.default_expire_secs) as i64;
@@ -36,7 +36,7 @@ pub async fn store(
3636
expiration_date,
3737
delete_manually: query.delete_manually.unwrap_or(true),
3838
max_download: query.max_download,
39-
auth,
39+
secret,
4040
count_downloads: 0,
4141
};
4242
while let Ok(Some(field)) = multipart.next_field().await {
@@ -72,7 +72,9 @@ pub async fn store(
7272
state.db.flush().await?;
7373
return Ok((path, expiration_date));
7474
}
75-
Err(ApiError::BadRequest("multpart is empty".to_string()))
75+
Err(ApiError::BadRequest(
76+
"multipart/form-data empty body".to_string(),
77+
))
7678
}
7779

7880
pub async fn store_stream(file_path: &PathBuf, field: Field<'_>) -> ApiResult<()> {
@@ -91,7 +93,7 @@ pub async fn info(
9193
state: &ApiState,
9294
code: &str,
9395
file_name: &str,
94-
auth: Option<Secret>,
96+
secret: Option<Secret>,
9597
) -> ApiResult<MetaDataFile> {
9698
let path = FilePath {
9799
code: code.to_string(),
@@ -104,7 +106,7 @@ pub async fn info(
104106
return Err(ApiError::NotFound(format!("{} not found", path.url_path())));
105107
}
106108
}
107-
authenticate(auth, &meta.auth)?;
109+
authorize_user(secret, &meta.secret)?;
108110
Ok(meta)
109111
}
110112

@@ -125,7 +127,7 @@ pub async fn fetch(
125127
return Err(ApiError::NotFound(format!("{} not found", path.url_path())));
126128
}
127129
}
128-
authenticate(secret, &meta.auth)?;
130+
authorize_user(secret, &meta.secret)?;
129131
read_file(&state.config.fs.base_dir.join(&path.url_path())).await
130132
}
131133

@@ -141,7 +143,7 @@ pub async fn delete(
141143
};
142144
if let Some(meta) = state.db.fetch(&path)? {
143145
if meta.delete_manually {
144-
authenticate(secret, &meta.auth)?;
146+
authorize_user(secret, &meta.secret)?;
145147
let file_path = path.fs_path(&state.config.fs.base_dir);
146148
tokio::fs::remove_file(file_path).await?;
147149
state.db.delete(path).await?;
@@ -160,34 +162,25 @@ pub async fn read_file(file_path: &PathBuf) -> ApiResult<ServeFile> {
160162
Ok(ServeFile::new(file_path))
161163
}
162164

163-
pub fn authenticate(secret: Option<Secret>, hash: &Option<String>) -> ApiResult<()> {
164-
if let Some(hash) = hash {
165-
match secret.map(|s| s.check(hash)) {
165+
pub fn authorize_user(secret: Option<Secret>, secret_hash: &Option<SecretHash>) -> ApiResult<()> {
166+
if let Some(hash) = secret_hash {
167+
match secret.map(|s| s.verify(hash)) {
166168
Some(Ok(_)) => return Ok(()),
167169
Some(Err(e)) if e == argon2::password_hash::Error::Password => Err(
168170
ApiError::PermissionDenied("Secret token is invalid".to_string()),
169171
),
170172
Some(Err(e)) => Err(ApiError::Unknown(anyhow!(
171-
"Unexpected error happened: {}",
172-
e
173+
"An Unexpected error occurred: {e}",
173174
))),
174175
None => Err(ApiError::PermissionDenied(
175-
"Authorization header should be set".to_string(),
176+
"Authorization header required.".to_string(),
176177
)),
177178
}
178179
} else {
179180
Ok(())
180181
}
181182
}
182183

183-
pub fn hash(auth: Option<String>) -> ApiResult<Option<String>> {
184-
auth
185-
.as_ref()
186-
.map(crate::util::hash::argon_hash)
187-
.transpose()
188-
.map_err(|e| ApiError::HashError(e.to_string()))
189-
}
190-
191184
pub fn calc_expiration_date(now: DateTime<Utc>, secs: i64) -> DateTime<Utc> {
192185
now + chrono::Duration::seconds(secs)
193186
}

api/src/util/http.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use hyper::HeaderMap;
22

3-
use crate::error::{invalid_input_error, ApiError, ApiResult};
3+
use crate::error::{invalid_input_error, ApiResult};
44

55
use super::secret::Secret;
66

api/src/util/secret.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
use crate::error::{ApiError, ApiResult};
22

3-
#[derive(Debug)]
4-
pub struct Secret {
5-
inner: String,
6-
}
3+
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
4+
pub struct Secret(String);
5+
6+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
7+
pub struct SecretHash(String);
78

89
impl Secret {
910
pub fn new(secret: String) -> Self {
10-
Self { inner: secret }
11+
Self(secret)
1112
}
1213

13-
pub fn check(&self, hash: &str) -> Result<(), argon2::password_hash::Error> {
14-
crate::util::hash::argon_verify(&self.inner, hash)
14+
pub fn verify(&self, hash: &SecretHash) -> Result<(), argon2::password_hash::Error> {
15+
crate::util::hash::argon_verify(&self.0, &hash.0)
1516
}
1617

17-
pub fn hash(&self) -> ApiResult<String> {
18-
crate::util::hash::argon_hash(&self.inner).map_err(|e| ApiError::HashError(e.to_string()))
18+
pub fn hash(&self) -> ApiResult<SecretHash> {
19+
crate::util::hash::argon_hash(&self.0)
20+
.map_err(|e| ApiError::HashError(e.to_string()))
21+
.map(|hash| SecretHash(hash))
1922
}
2023
}

0 commit comments

Comments
 (0)