Skip to content

Commit

Permalink
Session started
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajdip019 committed May 3, 2024
1 parent e64fb16 commit a78aafc
Show file tree
Hide file tree
Showing 10 changed files with 373 additions and 89 deletions.
2 changes: 0 additions & 2 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.9'

services:
server:
build:
Expand Down
202 changes: 193 additions & 9 deletions src/core/session.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,46 @@
use bson::DateTime;
use crate::{
errors::{Error, Result},
traits::{decryption::Decrypt, encryption::Encrypt},
utils::{encryption_utils::Encryption, session_utils::{IDToken, RefreshToken}},
};
use bson::{doc, DateTime};
use futures::StreamExt;
use mongodb::{Client, Collection};
use serde::{Deserialize, Serialize};
use crate ::{
errors::{Error, Result}, traits::encryption::Encrypt
};

use super::{dek::Dek, user::User};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session{
pub struct Session {
pub uid: String,
pub email: String,
pub id_token: String,
pub refresh_token: String,
pub user_agent: String,
pub is_active: bool,
pub created_at: DateTime,
pub updated_at: DateTime,
}

impl Session {
pub fn new(uid: String, email: String, id_token: String, refresh_token: String) -> Self {
pub fn new(user: &User, user_agent: &str) -> Self {
let id_token = match IDToken::new(user).sign() {
Ok(token) => token,
Err(_) => "".to_string(),
};

let refresh_token = match RefreshToken::new(&user.uid).sign() {
Ok(token) => token,
Err(_) => "".to_string(),
};

Self {
uid,
email,
uid: user.uid.to_string(),
email: user.email.to_string(),
id_token,
refresh_token,
user_agent: user_agent.to_string(),
is_active: true,
created_at: DateTime::now(),
updated_at: DateTime::now(),
}
Expand All @@ -40,4 +59,169 @@ impl Session {
}),
}
}
}

pub async fn verify(
mongo_client: &Client,
id_token: &str,
) -> Result<IDToken> {
let token_data = match IDToken::verify(&id_token) {
Ok(token_data) => {
let db = mongo_client.database("test");
let collection_session: Collection<Session> = db.collection("sessions");

let dek_data = match Dek::get(mongo_client, &token_data.uid).await {
Ok(dek) => dek,
Err(e) => return Err(e),
};

let encrypted_id = Encryption::encrypt_data(&token_data.uid, &dek_data.dek);
let encrypted_id_token = Encryption::encrypt_data(&id_token, &dek_data.dek);

let session = match collection_session
.count_documents(doc! {
"uid": encrypted_id,
"id_token": encrypted_id_token,
"is_active": true,
}, None)
.await
{
Ok(count) => {
if count > 0 {
Ok(())
} else {
Err(Error::SessionExpired {
message: "Invalid token".to_string(),
})
}
},
Err(e) => Err(Error::ServerError {
message: e.to_string(),
}),
};
if session.is_err() {
return Err(Error::InvalidToken {
message: "Invalid token".to_string(),
});
} else {
Ok(token_data)
}
},
Err(e) => return Err(e),
};
token_data
}

pub async fn get_all_from_uid(mongo_client: &Client, uid: &str) -> Result<Vec<Session>> {
let db = mongo_client.database("test");
let collection_session: Collection<Session> = db.collection("sessions");

let dek_data = match Dek::get(mongo_client, uid).await {
Ok(dek) => dek,
Err(e) => return Err(e),
};

let encrypted_uid = Encryption::encrypt_data(uid, &dek_data.dek);

let mut cursor = collection_session
.find(
doc! {
"uid": encrypted_uid,
"is_active": true,
},
None,
)
.await
.unwrap();

let mut sessions: Vec<Session> = Vec::new();
while let Some(session) = cursor.next().await {
match session {
Ok(data) => {
let decrypted_session = data.decrypt(&dek_data.dek);
sessions.push(decrypted_session);
}
Err(e) => return Err(Error::ServerError { message: e.to_string() }),
}
}
Ok(sessions)
}

pub async fn revoke_all(mongo_client: &Client, uid: &str) -> Result<()> {
let db = mongo_client.database("test");
let collection_session: Collection<Session> = db.collection("sessions");

match collection_session
.update_many(
doc! {"uid": uid},
doc! {"$set": {"is_active": false}},
None,
)
.await
{
Ok(_) => Ok(()),
Err(e) => Err(Error::ServerError {
message: e.to_string(),
}),
}
}

pub async fn revoke(
id_token: &str,
refresh_token: &str,
mongo_client: &Client,
) -> Result<()> {
let db = mongo_client.database("test");
let collection_session: Collection<Session> = db.collection("sessions");

match collection_session
.update_one(
doc! {"id_token": id_token, "refresh_token": refresh_token },
doc! {"$set": {"is_active": false}},
None,
)
.await
{
Ok(_) => Ok(()),
Err(e) => Err(Error::ServerError {
message: e.to_string(),
}),
}
}

pub async fn delete(id_token: &str, refresh_token: &str, mongo_client: &Client) -> Result<()> {
let db = mongo_client.database("test");
let collection_session: Collection<Session> = db.collection("sessions");

match collection_session
.delete_one(
doc! {"id_token": id_token, "refresh_token": refresh_token },
None,
)
.await
{
Ok(_) => Ok(()),
Err(e) => Err(Error::ServerError {
message: e.to_string(),
}),
}
}


pub async fn delete_all(mongo_client: &Client, uid: &str) -> Result<()> {
let db = mongo_client.database("test");
let collection_session: Collection<Session> = db.collection("sessions");

match collection_session
.delete_many(
doc! {"uid": uid},
None,
)
.await
{
Ok(_) => Ok(()),
Err(e) => Err(Error::ServerError {
message: e.to_string(),
}),
}
}
}
4 changes: 2 additions & 2 deletions src/core/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ impl User {
Ok("Password updated successfully".to_string())
}

pub async fn delete(mongo_client: &Client, email: &str) -> Result<()> {
pub async fn delete(mongo_client: &Client, email: &str) -> Result<String> {
let db = mongo_client.database("test");
let collection: Collection<User> = db.collection("users");
let collection_dek: Collection<Dek> = db.collection("deks");
Expand Down Expand Up @@ -552,7 +552,7 @@ impl User {
message: "DEK not found".to_string(),
});
}
Ok(())
Ok(dek_data.uid)
}
Err(_) => {
return Err(Error::ServerError {
Expand Down
30 changes: 22 additions & 8 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@ pub enum Error {

// -- Session Errors
InvalidToken { message: String },

ServerError { message: String },

// -- Encryption Errors
KeyNotFound { message: String },
RefreshTokenCreationError { message: String },
IdTokenCreationError { message: String },
PublicKeyLoadError { message: String },
PrivateKeyLoadError { message: String },
SignatureVerificationError { message: String },
ExpiredSignature { message: String },
IdTokenCreationError { message: String },
SessionExpired { message: String },


// -- Encryption Errors
KeyNotFound { message: String },

ServerError { message: String },
}

impl IntoResponse for Error {
Expand Down Expand Up @@ -104,12 +107,22 @@ impl Error {
Self::InvalidToken { message: _ } => {
(StatusCode::UNAUTHORIZED, ClientError::INVALID_TOKEN)
}
Self::IdTokenCreationError { message: _ } => (
StatusCode::INTERNAL_SERVER_ERROR,
ClientError::SERVICE_ERROR,
),

Self::ServerError { message: _ } => (
Self::RefreshTokenCreationError { message: _ } => (
StatusCode::INTERNAL_SERVER_ERROR,
ClientError::SERVICE_ERROR,
),
Self::IdTokenCreationError { message: _ } => (

Self::SessionExpired { message: _ } => (
StatusCode::UNAUTHORIZED,
ClientError::SESSION_EXPIRED,
),

Self::ServerError { message: _ } => (
StatusCode::INTERNAL_SERVER_ERROR,
ClientError::SERVICE_ERROR,
),
Expand All @@ -134,6 +147,7 @@ pub enum ClientError {
INVALID_TOKEN,
SIGNATURE_VERIFICATION_ERROR,
EXPIRED_SIGNATURE,
SESSION_EXPIRED
}

// region: --- Error Boilerplate
Expand Down
37 changes: 30 additions & 7 deletions src/handlers/session_handler.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
use axum::Json;
use axum::{extract::State, Json};
use axum_macros::debug_handler;
use serde_json::{json, Value};

use crate::{errors::{Error, Result}, models::session_model::VerifyJwt, utils::session_utils::IDToken};
use crate::{core::session::Session, errors::{Error, Result}, models::{session_model::VerifyJwt, user_model::UserIdPayload}, utils::session_utils::IDToken, AppState};

#[debug_handler]
pub async fn verify_jwt_handler(
pub async fn verify_session(
State(state): State<AppState>,
payload: Json<VerifyJwt>,
) -> Result<Json<Value>> {
) -> Result<Json<IDToken>> {
// check if the token is not empty
if payload.token.is_empty() {
return Err(Error::InvalidPayload { message: "Invalid payload passed".to_string() });
}

// verify the token
let _ = match IDToken::verify(&payload.token) {
Ok(val) => return Ok(Json(json!(val))),
match Session::verify(&state.mongo_client, &payload.token).await {
Ok(data) => {
return Ok(Json(data));
}
Err(e) => return Err(e),

};
}

#[debug_handler]
pub async fn get_all_from_uid(
State(state): State<AppState>,
payload: Json<UserIdPayload>,
) -> Result<Json<Vec<Session>>> {
// check if the token is not empty
if payload.uid.is_empty() {
return Err(Error::InvalidPayload { message: "Invalid payload passed".to_string() });
}

// verify the token
match Session::get_all_from_uid(&state.mongo_client, &payload.uid).await {
Ok(data) => {
return Ok(Json(data));
}
Err(e) => return Err(e),

};
}
10 changes: 7 additions & 3 deletions src/handlers/user_handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
core::{dek::Dek, user::User},
core::{dek::Dek, session::Session, user::User},
errors::{Error, Result},
models::user_model::{
ToggleUserActivationStatusPayload, ToggleUserActivationStatusResponse, UpdateUserPayload,
Expand Down Expand Up @@ -201,8 +201,12 @@ pub async fn delete_user_handler(
});
}

match User::delete(&State(state).mongo_client, &payload.email).await {
Ok(_) => {
match User::delete(&State(&state).mongo_client, &payload.email).await {
Ok(uid) => {
match Session::delete_all(&State(&state).mongo_client, &uid).await {
Ok(_) => {}
Err(e) => return Err(e),
}
return Ok(Json(UserEmailResponse {
message: "User deleted".to_string(),
email: payload.email.to_owned(),
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
.merge(routes::auth_routes::routes(State(app_state.clone())))
.merge(routes::user_routes::routes(State(app_state.clone())))
.merge(routes::password_routes::routes(State(app_state.clone())))
.merge(routes::session_routes::routes())
.merge(routes::session_routes::routes(State(app_state.clone())))
.layer(middleware::map_response(main_response_mapper));

let app = Router::new().nest("/api", routes);
Expand Down
Loading

0 comments on commit a78aafc

Please sign in to comment.