feat(api): fully implemented the two (GET and DELETE) `tokens` endpoints
This commit is contained in:
parent
d33df76b96
commit
ce96035711
4
API.md
4
API.md
|
@ -153,8 +153,8 @@ Lists all active auth tokens for the account.
|
|||
##### 200 - Success
|
||||
__Content - JSON:__
|
||||
| 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
|
||||
The provided auth token doesn't allow you to perform this operation.
|
||||
##### 403 - Error: Forbidden
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::api::account::{data, handlers};
|
||||
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 log::error;
|
||||
|
||||
|
@ -48,7 +48,9 @@ async fn authenticate(
|
|||
data::AuthenticateResponse::Success(b) => HttpResponse::Ok().json(web::Json(b)),
|
||||
data::AuthenticateResponse::WrongPassword => HttpResponse::Unauthorized().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(),
|
||||
},
|
||||
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,
|
||||
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> {
|
||||
if !token.is_alpha() {
|
||||
pub async fn delete(pool: &MySqlPool, auth: String) -> Result<data::DeleteResponse> {
|
||||
if !auth.is_alpha() {
|
||||
return Ok(data::DeleteResponse::Blocked);
|
||||
}
|
||||
|
||||
let token = match AuthToken::check(pool, &token).await? {
|
||||
let token = match AuthToken::check(pool, &auth).await? {
|
||||
Some(t) => t,
|
||||
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)
|
||||
}
|
||||
|
||||
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::authenticate)
|
||||
.service(account::calls::delete)
|
||||
.service(account::calls::tokens_delete)
|
||||
.service(account::calls::tokens_get)
|
||||
.app_data(web::Data::new(ApiState { pool: pool.clone() }))
|
||||
})
|
||||
.bind(("127.0.0.1", port))?
|
||||
|
|
Loading…
Reference in New Issue