UNPKG

@opengis/fastify-table

Version:

core-plugins

92 lines (91 loc) 4.07 kB
import path from "node:path"; import { fileURLToPath } from "url"; import { readFile } from "node:fs/promises"; import config from "../../../../../config.js"; import getTemplate from "../../../../plugins/table/funcs/getTemplate.js"; import pgClients from "../../../../plugins/pg/pgClients.js"; import { handlebars } from "../../../../helpers/index.js"; import { verify, deleteSecret } from "./providers/totp.js"; import sendNotification from "../../../../plugins/auth/funcs/sendNotification.js"; const template = "recovery-codes-email-template"; const dirname = path.dirname(fileURLToPath(import.meta.url)); /** * Відновлення при втраті доступу до застосунку двохфакторної авторизації * * @method GET|POST * @summary Відновлення при втраті доступу до застосунку двохфакторної авторизації * @priority 3 * @alias recovery * @type api * @tag auth * @requires 2fa * @param {Object} body.code Код, який використовується для перевірки у заданому провайдері двофакторної авторизації * @errors 500 * @returns {Number} status Номер помилки * @returns {String|Object} error Опис помилки * @returns {String|Object} message Повідомлення про успішне виконання або об'єкт з параметрами * @returns {String} redirect Шлях до переадресації */ export default async function recovery(req, reply) { const { pg = pgClients.client, user, body = {}, method } = req; if (!user?.uid) { return reply.status(401).send({ error: "unauthorized", code: 401 }); } if (!user.twofa) { return reply.status(400).send({ error: "2fa not enabled", code: 400 }); } if (!config.pg) { return reply.status(400).send({ error: "empty pg", code: 400 }); } const { code } = body; const { uid, email } = user || {}; if (!code) { if (!email) { return reply .status(404) .send({ error: "user recovery email not set", code: 404 }); } // return reply.status(400).send('not enough params'); const customPt = await getTemplate("pt", template); const pt = customPt || (await readFile(path.join(dirname, `../../../../../templates/pt/${template}.html`), "utf8")); const recoveryCodes = await pg .query(`select social_auth_obj->'codesArray' as "recoveryCodes" from admin.users_social_auth where uid = $1 and social_auth_type = $2`, [uid, "TOTP"]) .then((el) => el.rows?.[0]?.recoveryCodes || []); if (!recoveryCodes?.length) { return reply .status(404) .send({ error: "user recovery code not found", code: 404 }); } const html = await handlebars.compile(pt)({ recoveryCodes: [recoveryCodes[0]], domain: `${req.protocol || "https"}://${req.hostname}`, }); await sendNotification({ pg, to: email, template: html, title: `Recovery code for ${req.hostname} 2-factor authentication`, nocache: config.local || config.debug || user?.user_type?.includes?.("admin"), }); if (method === "POST") { return reply.status(200).send({ redirectUrl: "/2factor?recovery=1" }); } return reply.redirect("/2factor?recovery=1"); } try { // validate recovery code await verify({ uid, code, pg }); // delete old secret await deleteSecret({ pg, uid }); const redirectUrl = config.auth?.link?.["2fa"]?.login || "/2factor"; if (method === "POST") { return reply.status(200).send({ redirectUrl }); } return reply.redirect(redirectUrl); } catch (err) { return reply.status(500).send({ error: err.toString(), code: 500 }); } }