diff --git a/src/front/static/ts/views/LoginPage.ts b/src/front/static/ts/views/LoginPage.ts index da0deec..97e6ed0 100644 --- a/src/front/static/ts/views/LoginPage.ts +++ b/src/front/static/ts/views/LoginPage.ts @@ -73,11 +73,17 @@ export default class extends Aview { } else if (data_req.status === 401) { const data = await data_req.json(); - const error = document.createElement("p"); - error.innerHTML = data.error; - error.classList.add("text-red-700", "dark:text-red-500"); + if (!document.getElementById("error-totp")) { + const error = document.createElement("p"); + error.innerHTML = data.error; + error.classList.add("text-red-700", "dark:text-red-500"); + + idWindow.appendChild(error); + } else { + const error = document.getElementById("error-totp") as HTMLParagraphElement; + error.innerHTML = data.error; + } - idWindow.appendChild(error); } else { console.log(data_req.status) console.log(await data_req.json()) @@ -140,7 +146,7 @@ export default class extends Aview { const tokenTitle = document.createElement("h1"); tokenTitle.innerHTML = `hey ${username}, please submit your 2fa code below :`; - tokenTitle.classList.add("text-gray-900", "dark_text-white", "text-lg", "pt-0", "pb-4", "justify-center"); + tokenTitle.classList.add("text-gray-900", "dark:text-white", "text-lg", "pt-0", "pb-4", "justify-center"); const form = document.createElement("form"); form.method = "dialog"; diff --git a/src/front/static/ts/views/Settings.ts b/src/front/static/ts/views/Settings.ts index 94e6500..021b215 100644 --- a/src/front/static/ts/views/Settings.ts +++ b/src/front/static/ts/views/Settings.ts @@ -2,12 +2,12 @@ import Aview from "./Aview.ts" import { dragElement } from "./drag.ts"; import { setOnekoState } from "../oneko.ts" import { isLogged, navigationManager } from "../main.ts" - +import { totpEnablePopup } from "./TotpEnable.ts"; +import { totpVerify } from "../../../../api/auth/totpVerify.js"; export default class extends Aview { - constructor() - { + constructor() { super(); this.setTitle("profile"); setOnekoState("default"); @@ -29,62 +29,109 @@ export default class extends Aview {
- + `; } - async run() { - if (!await isLogged()) - navigationManager("/"); + async run() { + if (!await isLogged()) + navigationManager("/"); - dragElement(document.getElementById("window")); + dragElement(document.getElementById("window")); - let uuid: String; - uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; - const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { - method: "GET", - credentials: "include", - }); - if (userdata_req.status == 404) { - console.error("invalid user"); - return; - } - let userdata = await userdata_req.json(); + const isTOTPEnabled = async () => { + const totpVerify_req = await fetch('http://localhost:3001/2fa', { + method: "GET", + credentials: "include" + }) - (document.getElementById("displayName-input") as HTMLInputElement).placeholder = userdata.displayName; - (document.getElementById("displayName-input") as HTMLInputElement).value = userdata.displayName; + if (totpVerify_req.status === 200) { + const totpVerify_data = await totpVerify_req.json(); + if (totpVerify_data.totp == true) { + return true; + } + } + return false; + }; - document.getElementById("displayName-button")?.addEventListener("click", async () => { - const changeDisplayName_req = await fetch(`http://localhost:3002/users/${uuid}/displayName`, { - method: "PATCH", - headers: { "Content-Type": "application/json", }, - credentials: "include", - body: JSON.stringify({ displayName: (document.getElementById("displayName-input") as HTMLInputElement).value }) - }); - if (changeDisplayName_req.status == 200) { - // idk display success - } - else { - // display error ig, uuuh it's in await changeDisplayName.json().error - } - }); + let uuid: String; + uuid = document.cookie.match(new RegExp('(^| )' + "uuid" + '=([^;]+)'))[2]; + const userdata_req = await fetch(`http://localhost:3002/users/${uuid}`, { + method: "GET", + credentials: "include", + }); + if (userdata_req.status == 404) { + console.error("invalid user"); + return; + } + let userdata = await userdata_req.json(); - document.getElementById("deleteAccount-button")?.addEventListener("click", async () => { - const delete_req = await fetch(`http://localhost:3001/`, { - method: "DELETE", - credentials: "include", - }); + (document.getElementById("displayName-input") as HTMLInputElement).placeholder = userdata.displayName; + (document.getElementById("displayName-input") as HTMLInputElement).value = userdata.displayName; - if (delete_req.status == 200) - navigationManager("/"); - else - console.error("xd"); // xd????????????? - }); + document.getElementById("displayName-button")?.addEventListener("click", async () => { + const changeDisplayName_req = await fetch(`http://localhost:3002/users/${uuid}/displayName`, { + method: "PATCH", + headers: { "Content-Type": "application/json", }, + credentials: "include", + body: JSON.stringify({ displayName: (document.getElementById("displayName-input") as HTMLInputElement).value }) + }); + if (changeDisplayName_req.status == 200) { + // idk display success + } + else { + // display error ig, uuuh it's in await changeDisplayName.json().error + } + }); - document.getElementById("2fa-button")?.addEventListener("click", async () => { - - }); - } + document.getElementById("deleteAccount-button")?.addEventListener("click", async () => { + const delete_req = await fetch(`http://localhost:3001/`, { + method: "DELETE", + credentials: "include", + }); + + if (delete_req.status == 200) + navigationManager("/"); + else + console.error("xd"); // xd????????????? + }); + + + const totpButton = document.getElementById("2fa-button") as HTMLButtonElement; + + if ((await isTOTPEnabled()) === true) { + totpButton.innerHTML = "disable 2fa"; + + document.getElementById("2fa-button")?.addEventListener("click", async () => { + const totp_req = await fetch(`http://localhost:3001/2fa`, { + method: "DELETE", + credentials: "include" + }) + if (totp_req.status === 200) { + console.log("working") + navigationManager("/settings") + } else { + console.log("wut") + } + }); + } else { + totpButton.innerHTML = "enable 2fa"; + + document.getElementById("2fa-button")?.addEventListener("click", async () => { + const totp_req = await fetch(`http://localhost:3001/2fa`, { + method: "POST", + credentials: "include" + }) + if (totp_req.status === 200) { + console.log("working") + const totp_data = await totp_req.json(); + totpEnablePopup(uuid, totp_data.secret, totp_data.otpauthUrl); + } else { + console.log("wut") + } + }); + } + } } diff --git a/src/front/static/ts/views/TotpEnable.ts b/src/front/static/ts/views/TotpEnable.ts new file mode 100644 index 0000000..89488c1 --- /dev/null +++ b/src/front/static/ts/views/TotpEnable.ts @@ -0,0 +1,110 @@ +import { navigationManager } from "../main.ts"; +import { dragElement } from "./drag.ts"; + +async function totpVerify() { + const code = (document.getElementById("totpPin") as HTMLInputElement).value; + const data_req = await fetch('http://localhost:3001/2fa/verify', { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + token: code + }) + }) + + if (data_req.status === 200) { + navigationManager("/settings"); + } else if (data_req.status === 401 || data_req.status === 400) { + const popup_content = document.getElementById("2fa-enable-content"); + + if (!document.getElementById("error-totp")) { + const error = document.createElement("p"); + error.id = "error-totp"; + error.classList.add("text-red-700", "dark:text-red-500"); + error.innerHTML = (await data_req.json()).error; + + popup_content?.appendChild(error) + } else { + const error = document.getElementById("error-totp") as HTMLParagraphElement; + error.innerHTML = (await data_req.json()).error; + } + } else { + console.log("Unexpected error") + } +} + +export async function totpEnablePopup(username: String, secret: String, url: String) { + const popup: HTMLDivElement = document.createElement("div"); + popup.id = "2fa-enable-popup"; + popup.classList.add("z-10", "absolute", "default-border"); + const header = popup.appendChild(document.createElement("div"));; + header.classList.add("bg-linear-to-r", "from-orange-200", "to-orange-300", "flex", "flex-row", "min-w-35", "justify-between", "px-2"); + header.id = "2fa-enable-popup-header"; + header.appendChild(document.createElement("span")).innerText = "2fa_enable.ts"; + const btn = header.appendChild(document.createElement("button")); + btn.innerText = " × "; + btn.onclick = () => { document.getElementById("2fa-enable-popup")?.remove(); }; + + const popup_content: HTMLSpanElement = popup.appendChild(document.createElement("div")); + popup_content.id = "2fa-enable-content"; + popup_content.classList.add("flex", "flex-col", "bg-neutral-200", "dark:bg-neutral-800", "p-6", "pt-4", "text-neutral-900", "dark:text-white", "space-y-4"); + + const qrDivTOTP = document.createElement("div"); + qrDivTOTP.classList.add("flex", "justify-center"); + + const qrCodeTOTP = document.createElement("img"); + qrCodeTOTP.id = "qrCodeTOTP"; + qrCodeTOTP.src = `https://api.qrserver.com/v1/create-qr-code/?margin=10&size=512x512&data=${url}`; + qrCodeTOTP.classList.add("w-60"); + qrDivTOTP.appendChild(qrCodeTOTP); + + const secretText = document.createElement("p"); + secretText.innerHTML = `key:
${secret}
`; + secretText.classList.add("text-center") + + const tokenInput = document.createElement("input"); + tokenInput.type = "tel"; + tokenInput.id = "totpPin"; + tokenInput.name = "totpPin"; + tokenInput.placeholder = "TOTP code"; + tokenInput.required = true; + tokenInput.autocomplete = "off"; + tokenInput.pattern = "[0-9]*"; + tokenInput.setAttribute("inputmode", "numeric"); + tokenInput.classList.add("bg-white", "text-neutral-900", "w-full", "px-4", "py-2", "input-border"); + + const tokenSubmit = document.createElement("button"); + tokenSubmit.type = "submit"; + tokenSubmit.classList.add("default-button", "w-full"); + tokenSubmit.id = "totp-submit"; + tokenSubmit.innerHTML = "submit"; + + const hr = document.createElement("hr"); + hr.classList.add("my-2", "w-full", "reverse-border"); + + const t = document.createElement("h2"); + t.innerHTML = "hey " + username + + ` you are trying to add 2fa
+ just add the following to your app and enter the code bellow ↓ + `; + t.classList.add("text-center") + + document.getElementById("app")?.appendChild(popup); + + const form = document.createElement("form"); + form.method = "dialog"; + form.classList.add("space-y-4"); + form.appendChild(tokenInput); + form.appendChild(tokenSubmit); + + popup_content.appendChild(t) + popup_content.appendChild(qrDivTOTP); + popup_content.appendChild(secretText); + popup_content.appendChild(hr) + popup_content.appendChild(form); + dragElement(document.getElementById("2fa-enable-popup")); + + document.getElementById("totp-submit")?.addEventListener("click", totpVerify) +}