feat(api): fully implemented the two (GET and DELETE) `tokens` endpoints
This commit is contained in:
parent
d33df76b96
commit
ce96035711
6
API.md
6
API.md
|
@ -152,9 +152,9 @@ Lists all active auth tokens for the account.
|
||||||
#### Responses
|
#### Responses
|
||||||
##### 200 - Success
|
##### 200 - Success
|
||||||
__Content - JSON:__
|
__Content - JSON:__
|
||||||
| Field | Description |
|
| Field | Description |
|
||||||
|--------|-------------------------------------------|
|
|--------|-------------------------------------------------------------------------------------------------|
|
||||||
| tokens | A list of (token, expiration date) pairs. |
|
| tokens | A list of (token, expiration date) pairs. The expiration date is given as a UTC UNIX timestamp. |
|
||||||
##### 401 - Error: Unauthorized
|
##### 401 - Error: Unauthorized
|
||||||
The provided auth token doesn't allow you to perform this operation.
|
The provided auth token doesn't allow you to perform this operation.
|
||||||
##### 403 - Error: Forbidden
|
##### 403 - Error: Forbidden
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::api::account::{data, handlers};
|
use crate::api::account::{data, handlers};
|
||||||
use crate::api::ApiState;
|
use crate::api::ApiState;
|
||||||
use actix_web::{delete, post, web, HttpResponse, Responder};
|
use actix_web::{delete, get, post, web, HttpResponse, Responder};
|
||||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
|
@ -48,7 +48,9 @@ async fn authenticate(
|
||||||
data::AuthenticateResponse::Success(b) => HttpResponse::Ok().json(web::Json(b)),
|
data::AuthenticateResponse::Success(b) => HttpResponse::Ok().json(web::Json(b)),
|
||||||
data::AuthenticateResponse::WrongPassword => HttpResponse::Unauthorized().finish(),
|
data::AuthenticateResponse::WrongPassword => HttpResponse::Unauthorized().finish(),
|
||||||
data::AuthenticateResponse::UserNotFound => HttpResponse::NotFound().finish(),
|
data::AuthenticateResponse::UserNotFound => HttpResponse::NotFound().finish(),
|
||||||
data::AuthenticateResponse::NotVerified => HttpResponse::new(actix_web::http::StatusCode::FAILED_DEPENDENCY),
|
data::AuthenticateResponse::NotVerified => {
|
||||||
|
HttpResponse::new(actix_web::http::StatusCode::FAILED_DEPENDENCY)
|
||||||
|
}
|
||||||
data::AuthenticateResponse::Blocked => HttpResponse::Forbidden().finish(),
|
data::AuthenticateResponse::Blocked => HttpResponse::Forbidden().finish(),
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -72,3 +74,38 @@ async fn delete(data: web::Data<ApiState>, auth: BearerAuth) -> impl Responder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[delete("/account/tokens")]
|
||||||
|
async fn tokens_delete(
|
||||||
|
data: web::Data<ApiState>,
|
||||||
|
auth: BearerAuth,
|
||||||
|
body: web::Json<data::TokenDeleteRequest>,
|
||||||
|
) -> impl Responder {
|
||||||
|
match handlers::token_delete(&data.pool, auth.token().to_string(), body.into_inner()).await {
|
||||||
|
Ok(resp) => match resp {
|
||||||
|
data::TokenDeleteResponse::Success => HttpResponse::Ok().finish(),
|
||||||
|
data::TokenDeleteResponse::Unauthorized => HttpResponse::Unauthorized().finish(),
|
||||||
|
data::TokenDeleteResponse::Blocked => HttpResponse::Forbidden().finish(),
|
||||||
|
data::TokenDeleteResponse::TokenNotFound => HttpResponse::NotFound().finish(),
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("While handling token delete request: {e}");
|
||||||
|
HttpResponse::InternalServerError().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/account/tokens")]
|
||||||
|
async fn tokens_get(data: web::Data<ApiState>, auth: BearerAuth) -> impl Responder {
|
||||||
|
match handlers::token_list(&data.pool, auth.token().to_string()).await {
|
||||||
|
Ok(resp) => match resp {
|
||||||
|
data::TokenListResponse::Success(b) => HttpResponse::Ok().json(web::Json(b)),
|
||||||
|
data::TokenListResponse::Unauthorized => HttpResponse::Unauthorized().finish(),
|
||||||
|
data::TokenListResponse::Blocked => HttpResponse::Forbidden().finish(),
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("While handling token list request: {e}");
|
||||||
|
HttpResponse::InternalServerError().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -60,3 +60,28 @@ pub enum DeleteResponse {
|
||||||
Blocked,
|
Blocked,
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct TokenDeleteRequest {
|
||||||
|
pub token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TokenDeleteResponse {
|
||||||
|
Success,
|
||||||
|
Unauthorized,
|
||||||
|
Blocked,
|
||||||
|
TokenNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct TokenListSuccess {
|
||||||
|
pub tokens: Vec<(String, i64)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TokenListResponse {
|
||||||
|
Success(TokenListSuccess),
|
||||||
|
Unauthorized,
|
||||||
|
Blocked,
|
||||||
|
}
|
||||||
|
|
|
@ -130,12 +130,12 @@ pub async fn authenticate(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(pool: &MySqlPool, token: String) -> Result<data::DeleteResponse> {
|
pub async fn delete(pool: &MySqlPool, auth: String) -> Result<data::DeleteResponse> {
|
||||||
if !token.is_alpha() {
|
if !auth.is_alpha() {
|
||||||
return Ok(data::DeleteResponse::Blocked);
|
return Ok(data::DeleteResponse::Blocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = match AuthToken::check(pool, &token).await? {
|
let token = match AuthToken::check(pool, &auth).await? {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => return Ok(data::DeleteResponse::Unauthorized),
|
None => return Ok(data::DeleteResponse::Unauthorized),
|
||||||
};
|
};
|
||||||
|
@ -153,3 +153,57 @@ pub async fn delete(pool: &MySqlPool, token: String) -> Result<data::DeleteRespo
|
||||||
|
|
||||||
Ok(data::DeleteResponse::Success)
|
Ok(data::DeleteResponse::Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn token_delete(
|
||||||
|
pool: &MySqlPool,
|
||||||
|
auth: String,
|
||||||
|
request: data::TokenDeleteRequest,
|
||||||
|
) -> Result<data::TokenDeleteResponse> {
|
||||||
|
if !auth.is_alpha() {
|
||||||
|
return Ok(data::TokenDeleteResponse::Blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = match AuthToken::check(pool, &auth).await? {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return Ok(data::TokenDeleteResponse::Unauthorized),
|
||||||
|
};
|
||||||
|
|
||||||
|
let delete_token = match AuthToken::check(pool, &request.token).await? {
|
||||||
|
Some(t) => {
|
||||||
|
if t.account == token.account {
|
||||||
|
t
|
||||||
|
} else {
|
||||||
|
return Ok(data::TokenDeleteResponse::TokenNotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => return Ok(data::TokenDeleteResponse::TokenNotFound),
|
||||||
|
};
|
||||||
|
|
||||||
|
delete_token.delete(pool).await?;
|
||||||
|
|
||||||
|
Ok(data::TokenDeleteResponse::Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn token_list(pool: &MySqlPool, auth: String) -> Result<data::TokenListResponse> {
|
||||||
|
if !auth.is_alpha() {
|
||||||
|
return Ok(data::TokenListResponse::Blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = match AuthToken::check(pool, &auth).await? {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return Ok(data::TokenListResponse::Unauthorized),
|
||||||
|
};
|
||||||
|
|
||||||
|
let list: Vec<(String, i64)> = sqlx::query_as!(
|
||||||
|
AuthToken,
|
||||||
|
r#"SELECT * FROM AuthTokens WHERE account = ?;"#,
|
||||||
|
token.account
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.map(|t| (t.token.clone(), t.expire.timestamp()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(data::TokenListResponse::Success(data::TokenListSuccess {tokens: list}))
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ pub async fn start(port: u16, pool: MySqlPool) -> Result<()> {
|
||||||
.service(account::calls::verify)
|
.service(account::calls::verify)
|
||||||
.service(account::calls::authenticate)
|
.service(account::calls::authenticate)
|
||||||
.service(account::calls::delete)
|
.service(account::calls::delete)
|
||||||
|
.service(account::calls::tokens_delete)
|
||||||
|
.service(account::calls::tokens_get)
|
||||||
.app_data(web::Data::new(ApiState { pool: pool.clone() }))
|
.app_data(web::Data::new(ApiState { pool: pool.clone() }))
|
||||||
})
|
})
|
||||||
.bind(("127.0.0.1", port))?
|
.bind(("127.0.0.1", port))?
|
||||||
|
|
Loading…
Reference in New Issue