Skip to content

Commit

Permalink
Merge pull request #87 from robur-coop/logout
Browse files Browse the repository at this point in the history
Logout functionality
  • Loading branch information
PizieDust authored Nov 5, 2024
2 parents fc3e462 + 34e71b9 commit 52ba8d3
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 135 deletions.
45 changes: 43 additions & 2 deletions assets/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
document.addEventListener('DOMContentLoaded', function () {
AOS.init();

const flashMessage = getCookie('flash_msg');
if (flashMessage) {
if (flashMessage.startsWith("error:")) {
postAlert("bg-secondary-300", flashMessage);
} else {
postAlert("bg-primary-300", flashMessage);
}
document.cookie = "flash_msg=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 UTC;";
}

if (window.location.pathname.startsWith("/admin/user/")) {
const tabs = document.querySelectorAll(".tab-link");
const tabPanes = document.querySelectorAll(".tab-pane");
Expand All @@ -25,6 +36,16 @@ document.addEventListener('DOMContentLoaded', function () {
}
});

function getCookie(name) {
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const [cookieName, cookieValue] = cookie.split("=");
if (cookieName === name) {
return decodeURIComponent(cookieValue);
}
}
}

function getUnikernelName(url) {
const urlObj = new URL(url);
const pathParts = urlObj.pathname.split('/');
Expand Down Expand Up @@ -142,7 +163,7 @@ function postAlert(bg_color, content) {
alertContainer.classList.remove("block", `${bg_color}`)
alertContainer.classList.add("hidden")
alertContainer.removeChild(alert);
}, 1600);
}, 2500);
}

async function deployUnikernel() {
Expand Down Expand Up @@ -427,7 +448,7 @@ async function updatePassword() {
const new_password = document.getElementById("new-password").value;
const confirm_password = document.getElementById("confirm-password").value;
const formAlert = document.getElementById("form-alert");
if (!current_password || !new_password || !confirm_password ) {
if (!current_password || !new_password || !confirm_password) {
formAlert.classList.remove("hidden", "text-primary-500");
formAlert.classList.add("text-secondary-500");
formAlert.textContent = "Please fill in all the required passwords"
Expand Down Expand Up @@ -488,3 +509,23 @@ async function closeSessions() {
buttonLoading(sessionButton, false, "Logout all other sessions")
}
}

async function logout() {
const logoutButton = document.getElementById("logout-button");
try {
buttonLoading(logoutButton, true, "Closing session..")
const molly_csrf = document.getElementById("molly-csrf").value;
fetch('/logout', {
method: 'POST',
body: JSON.stringify(
{
molly_csrf,
}),
headers: { 'Content-Type': 'application/json' }
});
setTimeout(() => window.location.reload(), 1000);
} catch (error) {
postAlert("bg-secondary-300", error);
buttonLoading(logoutButton, false, "Logout")
}
}
18 changes: 16 additions & 2 deletions dashboard.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
open Tyxml

let dashboard_layout (user : User_model.user) ~icon
let dashboard_layout ~csrf (user : User_model.user) ~icon
?(page_title = "Dashboard | Mollymawk") ?message ~content () =
let page =
Html.(
Expand All @@ -18,6 +18,7 @@ let dashboard_layout (user : User_model.user) ~icon
];
]
[
Utils.csrf_form_input csrf;
div
~a:
[
Expand Down Expand Up @@ -154,7 +155,7 @@ let dashboard_layout (user : User_model.user) ~icon
a_class
[
"absolute top-1/4 rounded-md right-4 z-50 w-fit \
space-y-2 p-4 shadow border text-wrap hidden";
space-y-2 p-4 shadow text-wrap hidden";
];
]
[];
Expand Down Expand Up @@ -544,6 +545,19 @@ let dashboard_layout (user : User_model.user) ~icon
];
]
else div []);
button
~a:
[
a_id "logout-button";
a_onclick "logout()";
a_class
[
"my-3 py-3 rounded bg-secondary-500 \
hover:bg-secondary-800 w-full text-gray-50 \
font-semibold";
];
]
[ txt "Logout" ];
];
];
section
Expand Down
70 changes: 39 additions & 31 deletions middleware.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,48 @@ let cookie cookie_name (reqd : Httpaf.Reqd.t) =
(fun cookie ->
let parts = cookie |> String.split_on_char '=' in
match parts with
| [ name; _ ] -> String.equal name cookie_name
| [ name; _ ] -> String.equal (String.trim name) cookie_name
| _ -> false)
cookie_list
| _ -> None

let apply_middleware middlewares handler =
List.fold_right (fun middleware acc -> middleware acc) middlewares handler

let redirect_to_login reqd ?(msg = "") () =
let header_list =
[
( "Set-Cookie",
User_model.session_cookie
^ "=;Path=/;HttpOnly=true;Expires=2023-10-27T11:00:00.778Z" );
("location", "/sign-in");
("Content-Length", string_of_int (String.length msg));
]
let redirect_to_page ~path ?(clear_session = false) ?(with_error = false) reqd
?(msg = "") () =
let msg_cookie =
if with_error then "flash_msg=error: " ^ Uri.pct_encode msg ^ ";"
else "flash_msg=" ^ Uri.pct_encode msg ^ ";"
in
let headers = Httpaf.Headers.of_list header_list in
let response = Httpaf.Response.create ~headers `Found in
Httpaf.Reqd.respond_with_string reqd response msg;
Lwt.return_unit

let redirect_to_register reqd ?(msg = "") () =
let header_list =
[
( "Set-Cookie",
User_model.session_cookie
^ "=;Path=/;HttpOnly=true;Expires=2023-10-27T11:00:00.778Z" );
("location", "/sign-up");
("Content-Length", string_of_int (String.length msg));
]
let session_header =
if clear_session then
[
( "Set-Cookie",
User_model.session_cookie
^ "=; Path=/; HttpOnly=true; Expires=2023-10-27T11:00:00.778Z" );
]
else []
in
session_header
@ [
("Set-Cookie", msg_cookie);
("location", path);
("Content-Length", string_of_int (String.length msg));
]
in
let headers = Httpaf.Headers.of_list header_list in
let response = Httpaf.Response.create ~headers `Found in
Httpaf.Reqd.respond_with_string reqd response msg;
Lwt.return_unit

let redirect_to_error ~title ~data status user code api_meth reqd () =
let redirect_to_error ~title ~data status code api_meth reqd () =
let error = { Utils.Status.code; title; success = false; data } in
let data =
if api_meth then Utils.Status.to_json error
else
Dashboard.dashboard_layout user ~page_title:(title ^ " | Mollymawk")
Guest_layout.guest_layout ~page_title:(title ^ " | Mollymawk")
~content:(Error_page.error_layout error)
~icon:"/images/robur.png" ()
in
Expand Down Expand Up @@ -179,15 +177,21 @@ let auth_middleware now users handler reqd =
match user_of_cookie users now reqd with
| Ok user ->
if user.User_model.active then handler reqd
else redirect_to_login ~msg:"User account is deactivated." reqd ()
| Error (`Msg msg) -> redirect_to_login ~msg reqd ()
else
redirect_to_page ~path:"/sign-in" ~clear_session:true ~with_error:true
~msg:"User account is deactivated." reqd ()
| Error (`Msg msg) ->
redirect_to_page ~path:"/sign-in" ~clear_session:true ~with_error:true
~msg reqd ()

let email_verified_middleware now users handler reqd =
match user_of_cookie users now reqd with
| Ok user ->
if User_model.is_email_verified user then handler reqd
else redirect_to_verify_email reqd ()
| Error (`Msg msg) -> redirect_to_login ~msg reqd ()
| Error (`Msg msg) ->
redirect_to_page ~path:"/sign-in" ~clear_session:true ~with_error:true
~msg reqd ()

let is_user_admin_middleware api_meth now users handler reqd =
match user_of_cookie users now reqd with
Expand All @@ -197,8 +201,10 @@ let is_user_admin_middleware api_meth now users handler reqd =
redirect_to_error ~title:"Unauthorized"
~data:
"You don't have the necessary permissions to access this service."
`Unauthorized user 401 api_meth reqd ()
| Error (`Msg msg) -> redirect_to_login ~msg reqd ()
`Unauthorized 401 api_meth reqd ()
| Error (`Msg err) ->
redirect_to_page ~path:"/sign-in" ~clear_session:true ~with_error:true
~msg:err reqd ()

let csrf_match ~input_csrf ~check_csrf = String.equal input_csrf check_csrf

Expand Down Expand Up @@ -237,4 +243,6 @@ let csrf_verification users now form_csrf handler reqd =
http_response
~data:"Missing CSRF token. Please referesh and try again."
~title:"Missing CSRF Token" reqd `Bad_request)
| Error (`Msg err) -> redirect_to_login ~msg:err reqd ()
| Error (`Msg err) ->
redirect_to_page ~path:"/sign-in" ~clear_session:true ~with_error:true
~msg:err reqd ()
3 changes: 1 addition & 2 deletions settings_page.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let settings_layout ~csrf (configuration : Configuration.t) =
let settings_layout (configuration : Configuration.t) =
let ip = Ipaddr.to_string configuration.server_ip in
let port = string_of_int configuration.server_port in
let certificate = X509.Certificate.encode_pem configuration.certificate in
Expand All @@ -11,7 +11,6 @@ let settings_layout ~csrf (configuration : Configuration.t) =
div
~a:[ a_class [ "px-3 flex justify-between items-center" ] ]
[
Utils.csrf_form_input csrf;
div
[
p
Expand Down
11 changes: 11 additions & 0 deletions sign_in.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ let login_page ~icon () =
];
]
[
div
~a:
[
a_id "alert-container";
a_class
[
"absolute top-1/4 rounded-md right-4 z-50 w-fit \
space-y-2 p-4 shadow text-wrap hidden";
];
]
[];
div
~a:[ a_class [ "w-full max-w-lg mt-16 pb-16 mx-auto" ] ]
[
Expand Down
4 changes: 2 additions & 2 deletions sign_up.ml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ let register_page ~csrf ~icon =
a_class
[
"absolute top-1/4 rounded-md right-4 z-50 \
w-fit space-y-2 p-4 shadow border \
text-wrap hidden";
w-fit space-y-2 p-4 shadow text-wrap \
hidden";
];
]
[];
Expand Down
Loading

0 comments on commit 52ba8d3

Please sign in to comment.