Skip to content

Commit 2a4869d

Browse files
committed
backend: Add better error description when token is unknown
fix #210
1 parent f53cd90 commit 2a4869d

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

backend/src/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ pub enum Error {
6060
ChargerDoesNotExist,
6161
#[display("Invalid payload")]
6262
InvalidPayload,
63+
#[display("Recovery token unknown or already used")]
64+
InvalidRecoveryToken,
65+
#[display("Authorization token invalid")]
66+
AuthorizationTokenInvalid,
67+
#[display("Authorization token already used")]
68+
AuthorizationTokenAlreadyUsed,
6369
}
6470

6571
impl error::ResponseError for Error {
@@ -88,6 +94,9 @@ impl error::ResponseError for Error {
8894
Self::ChargerCredentialsWrong => StatusCode::UNAUTHORIZED,
8995
Self::ChargerDoesNotExist => StatusCode::BAD_REQUEST,
9096
Self::InvalidPayload => StatusCode::BAD_REQUEST,
97+
Self::InvalidRecoveryToken => StatusCode::BAD_REQUEST,
98+
Self::AuthorizationTokenInvalid => StatusCode::UNAUTHORIZED,
99+
Self::AuthorizationTokenAlreadyUsed => StatusCode::UNAUTHORIZED,
91100
}
92101
}
93102
}

backend/src/routes/charger/add_with_token.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,5 +211,65 @@ mod tests {
211211
println!("{resp:?}");
212212
println!("{:?}", resp.response().body());
213213
assert_eq!(resp.status(), 401);
214+
let body = test::read_body(resp).await;
215+
let body_str = String::from_utf8(body.to_vec()).unwrap();
216+
assert!(body_str.contains("Authorization token invalid"));
217+
}
218+
219+
#[actix_web::test]
220+
async fn test_one_time_token_reuse() {
221+
let (mut user, mail) = TestUser::random().await; // store mail
222+
user.login().await;
223+
let auth_token = user.create_authorization_token(true).await; // one-time token
224+
225+
let app = App::new().configure(configure).service(add_with_token);
226+
let app = test::init_service(app).await;
227+
228+
let keys = generate_random_keys();
229+
let cid = uuid::Uuid::new_v4().to_string();
230+
let uid = OsRng.try_next_u32().unwrap() as i32;
231+
let base_schema = |token: String| AddChargerWithTokenSchema {
232+
user_id: get_test_uuid(&mail).unwrap().to_string(),
233+
token,
234+
charger: ChargerSchema {
235+
uid: bs58::encode(uid.to_be_bytes())
236+
.with_alphabet(bs58::Alphabet::FLICKR)
237+
.into_string(),
238+
charger_pub: keys[0].charger_public.clone(),
239+
wg_charger_ip: IpNetwork::V4(
240+
Ipv4Network::new(Ipv4Addr::new(0, 0, 0, 0), 0).unwrap(),
241+
),
242+
wg_server_ip: IpNetwork::V4(
243+
Ipv4Network::new(Ipv4Addr::new(0, 0, 0, 0), 0).unwrap(),
244+
),
245+
psk: String::new(),
246+
},
247+
keys: keys.clone(),
248+
name: String::new(),
249+
note: String::new(),
250+
};
251+
252+
// First use succeeds
253+
let req = test::TestRequest::put()
254+
.uri("/add_with_token")
255+
.set_json(base_schema(auth_token.token.clone()))
256+
.to_request();
257+
let resp = test::call_service(&app, req).await;
258+
assert!(resp.status().is_success());
259+
260+
// Second use fails with already used message
261+
let req = test::TestRequest::put()
262+
.uri("/add_with_token")
263+
.set_json(base_schema(auth_token.token.clone()))
264+
.to_request();
265+
let resp = test::call_service(&app, req).await;
266+
assert_eq!(resp.status(), 401);
267+
let body = test::read_body(resp).await;
268+
let body_str = String::from_utf8(body.to_vec()).unwrap();
269+
assert!(body_str.contains("Authorization token already used"));
270+
271+
let _ = remove_test_keys(&mail);
272+
remove_allowed_test_users(&cid);
273+
remove_test_charger(&cid);
214274
}
215275
}

backend/src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ pub async fn validate_auth_token(
133133
.get_result(&mut conn)
134134
{
135135
Ok(v) => Ok(v),
136-
Err(NotFound) => Err(Error::Unauthorized),
136+
Err(NotFound) => Err(Error::AuthorizationTokenInvalid),
137137
Err(_err) => Err(Error::InternalError),
138138
}
139139
})
140140
.await?;
141141

142142
if token.use_once && token.last_used_at.is_some() {
143-
return Err(Error::Unauthorized.into());
143+
return Err(Error::AuthorizationTokenAlreadyUsed.into());
144144
}
145145

146146
let mut conn = get_connection(state)?;

0 commit comments

Comments
 (0)