@opengis/fastify-table
Version:
core-plugins
92 lines (91 loc) • 4.07 kB
JavaScript
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 });
}
}