feat(auth): Added 2FA/OTP manage endpoints

- CodeWise: Changed everything to use undefined when not present
- CodeWise: checks for nonpresent value using `isNullish`
- enableOtp: enable Otp, return topt url. Does nothing when
  already enabled
- disableOtp: disable 2FA Totp for the user
- statusOtp: get the 2FA status for the user. return the Totp Url if
  enabled
- loginDemo: split into two files
- loginDemo: supports for 2FA
- loginDemo: better response box
This commit is contained in:
Maieul BOYER 2025-08-31 16:27:42 +02:00 committed by Maix0
parent 29a5d38530
commit a7c753f38b
17 changed files with 341 additions and 175 deletions

View file

@ -1,84 +1,38 @@
<!DOCTYPE HTML>
<html>
<head>
<title> Demo Page For Login :) </title>
</head>
<body>
<h1> Welcome <span id="t-username"> </span> </h1>
<head>
<title>Demo Page For Login :)</title>
</head>
<input id="i-username" type="text" placeholder="Username"> </input>
<input id="i-password" type="text" placeholder="Password"> </input>
<br />
<br />
<body>
<h1>
Welcome <span id="t-username"></span>
</h1>
<input id="i-username" type="text" placeholder="Username">
</input>
<input id="i-password" type="text" placeholder="Password">
</input>
<br />
<input id="i-otp" type="text" placeholder="OTP">
</input>
<button id="b-otpSend">OTP - Send</button>
<br />
<br />
<button id="b-login">Login</button>
<br />
<button id="b-logout">Logout</button>
<br />
<button id="b-signin">Signin</button>
<br />
<button id="b-whoami">Whoami</button>
<div>
<button id="b-otpStatus">OTP - Status</button>
<button id="b-otpEnable">OTP - Enable</button>
<button id="b-otpDisable">OTP - Disable</button>
</div>
<pre id="d-response"></pre>
<script src="./login_demo.js"> </script>
</body>
<button id="b-login"> Login </button>
<br />
<button id="b-logout"> Logout </button>
<br />
<button id="b-signin"> Signin </button>
<br />
<button id="b-whoami"> Whoami </button>
<div id="d-response">
</div>
<script>
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
const tUsername = document.querySelector("#t-username")
const iUsername = document.querySelector("#i-username");
const iPassword = document.querySelector("#i-password");
const bLogin = document.querySelector("#b-login");
const bLogout = document.querySelector("#b-logout");
const bSignin = document.querySelector("#b-signin");
const bWhoami = document.querySelector("#b-whoami");
const dResponse = document.querySelector("#d-response");
bWhoami.addEventListener("click", async () => {
let username = "";
try {
let res = await fetch("/api/auth/whoami");
const json = await res.json();
if (json?.kind === "success")
username = json?.payload?.name;
else
username = `<not logged in: ${json.msg}>`
} catch {
username = `<not logged in: threw>`
}
tUsername.innerText = username;
}, 1000);
bLogin.addEventListener("click", async () => {
const name = iUsername.value;
const password = iPassword.value;
let res = await fetch("/api/auth/login", {method: "POST", body: JSON.stringify({name, password}), headers});
let j = await res.json();
if (j?.payload?.token)
document.cookie = `token=${j?.payload?.token}`;
dResponse.innerText = JSON.stringify(j, space=4);
})
bLogout.addEventListener("click", async () => {
let res = await fetch("/api/auth/logout", { method: "POST" });
dResponse.innerText = `done - status:${res.status}`;
})
bSignin.addEventListener("click", async () => {
const name = iUsername.value;
const password = iPassword.value;
let res = await fetch("/api/auth/signin", {method: "POST", body: JSON.stringify({name, password}), headers});
let j = await res.json();
if (j?.payload?.token)
document.cookie = `token=${j?.payload?.token};`;
dResponse.innerText = JSON.stringify(j, space=4);
})
</script>
</body>
</html>

View file

@ -0,0 +1,107 @@
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
const tUsername = document.querySelector("#t-username")
const iUsername = document.querySelector("#i-username");
const iPassword = document.querySelector("#i-password");
const iOtp = document.querySelector("#i-otp");
const bOtpSend = document.querySelector("#b-otpSend");
const bLogin = document.querySelector("#b-login");
const bLogout = document.querySelector("#b-logout");
const bSignin = document.querySelector("#b-signin");
const bWhoami = document.querySelector("#b-whoami");
const bOtpStatus = document.querySelector("#b-otpStatus");
const bOtpEnable = document.querySelector("#b-otpEnable");
const bOtpDisable = document.querySelector("#b-otpDisable");
const dResponse = document.querySelector("#d-response");
function setResponse(obj) {
let obj_str = JSON.stringify(obj, null, 4);
dResponse.innerText = obj_str;
}
let otpToken = null;
bOtpSend.addEventListener("click", async () => {
let res = await fetch("/api/auth/otp", { method: "POST", body: JSON.stringify({ code: iOtp.value, token: otpToken }), headers });
const json = await res.json();
setResponse(json);
if (json.kind === "success") {
if (json?.payload?.token)
document.cookie = `token=${json?.payload?.token}`;
}
});
bOtpStatus.addEventListener("click", async () => {
let res = await fetch("/api/auth/statusOtp");
const json = await res.json();
setResponse(json);
});
bOtpEnable.addEventListener("click", async () => {
let res = await fetch("/api/auth/enableOtp", { method: "PUT" });
const json = await res.json();
setResponse(json);
});
bOtpDisable.addEventListener("click", async () => {
let res = await fetch("/api/auth/disableOtp", { method: "PUT" });
const json = await res.json();
setResponse(json);
});
bWhoami.addEventListener("click", async () => {
let username = "";
try {
let res = await fetch("/api/auth/whoami");
const json = await res.json();
setResponse(json);
if (json?.kind === "success")
username = json?.payload?.name;
else
username = `<not logged in:${json.msg}>`
} catch {
username = `<not logged in: threw>`
}
tUsername.innerText = username;
});
bLogin.addEventListener("click", async () => {
const name = iUsername.value;
const password = iPassword.value;
let res = await fetch("/api/auth/login", { method: "POST", body: JSON.stringify({ name, password }), headers });
let json = await res.json();
if (json?.kind === "otpRequired") {
otpToken = json?.payload?.token;
} else if (json?.kind === "success") {
if (json?.payload?.token)
document.cookie = `token=${json?.payload?.token}`;
}
setResponse(json);
})
bLogout.addEventListener("click", async () => {
let res = await fetch("/api/auth/logout", { method: "POST" });
setResponse(await res.json());
})
bSignin.addEventListener("click", async () => {
const name = iUsername.value;
const password = iPassword.value;
let res = await fetch("/api/auth/signin", { method: "POST", body: JSON.stringify({ name, password }), headers });
let json = await res.json();
if (json?.payload?.token)
document.cookie = `token=${json?.payload?.token};`;
setResponse(json);
})