@opengis/fastify-table 2.0.89 → 2.0.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/plugins/auth/index.js +1 -1
- package/dist/server/plugins/policy/funcs/checkPolicy.d.ts.map +1 -1
- package/dist/server/plugins/policy/funcs/checkPolicy.js +1 -1
- package/dist/server/routes/auth/controllers/2factor/providers/totp.d.ts +3 -4
- package/dist/server/routes/auth/controllers/2factor/providers/totp.d.ts.map +1 -1
- package/dist/server/routes/auth/controllers/2factor/providers/totp.js +7 -11
- package/dist/server/routes/auth/controllers/2factor/qrcode.d.ts.map +1 -1
- package/dist/server/routes/auth/controllers/2factor/qrcode.js +3 -5
- package/dist/server/routes/auth/controllers/2factor/recovery.d.ts +1 -1
- package/dist/server/routes/auth/controllers/2factor/recovery.d.ts.map +1 -1
- package/dist/server/routes/auth/controllers/2factor/recovery.js +26 -18
- package/dist/server/routes/auth/controllers/2factor/reset.d.ts +3 -0
- package/dist/server/routes/auth/controllers/2factor/reset.d.ts.map +1 -0
- package/dist/server/routes/auth/controllers/2factor/reset.js +17 -0
- package/dist/server/routes/auth/controllers/2factor/verify.d.ts.map +1 -1
- package/dist/server/routes/auth/controllers/2factor/verify.js +15 -14
- package/dist/server/routes/auth/controllers/page/login2faTemplate.d.ts.map +1 -1
- package/dist/server/routes/auth/controllers/page/login2faTemplate.js +6 -8
- package/dist/server/routes/auth/index.d.ts.map +1 -1
- package/dist/server/routes/auth/index.js +4 -0
- package/package.json +1 -1
|
@@ -78,7 +78,7 @@ export async function onRequest(req, reply) {
|
|
|
78
78
|
// if 2factor is enabled globally + for user and secondFactorPassed not true => redirect to 2factor login page
|
|
79
79
|
if (req.user?.uid &&
|
|
80
80
|
req.user?.twofa &&
|
|
81
|
-
config.auth?.["2factor"] &&
|
|
81
|
+
// config.auth?.["2factor"] &&
|
|
82
82
|
!isPublic &&
|
|
83
83
|
(routeOptions?.method || "GET") === "GET" &&
|
|
84
84
|
!req.session?.secondFactorPassed &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkPolicy.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAKhC,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"checkPolicy.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAKhC,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,oSA+K5E"}
|
|
@@ -10,7 +10,7 @@ export default function checkPolicy(req, reply) {
|
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
12
|
// ! skip non-API Requests
|
|
13
|
-
const isApi =
|
|
13
|
+
const isApi = routeOptions.method && routeOptions.url && routeOptions.handler;
|
|
14
14
|
if (!isApi) {
|
|
15
15
|
return null;
|
|
16
16
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ExtendedPG } from "../../../../../types/core.js";
|
|
2
2
|
interface ISecret {
|
|
3
3
|
uid: string;
|
|
4
|
-
TYPE?: string;
|
|
5
4
|
pg: ExtendedPG;
|
|
6
5
|
}
|
|
7
6
|
interface ICode {
|
|
@@ -10,9 +9,9 @@ interface ICode {
|
|
|
10
9
|
pg: ExtendedPG;
|
|
11
10
|
enable?: boolean;
|
|
12
11
|
}
|
|
13
|
-
declare const enableSecret: ({ uid,
|
|
14
|
-
declare const deleteSecret: ({ uid,
|
|
15
|
-
declare const getSecret: ({ uid,
|
|
12
|
+
declare const enableSecret: ({ uid, pg }: ISecret) => Promise<void>;
|
|
13
|
+
declare const deleteSecret: ({ uid, pg }: ISecret) => Promise<void>;
|
|
14
|
+
declare const getSecret: ({ uid, pg }: ISecret) => Promise<{
|
|
16
15
|
secret: any;
|
|
17
16
|
enabled: any;
|
|
18
17
|
recoveryCodes: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp.d.ts","sourceRoot":"","sources":["../../../../../../../server/routes/auth/controllers/2factor/providers/totp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAQ1D,UAAU,OAAO;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,
|
|
1
|
+
{"version":3,"file":"totp.d.ts","sourceRoot":"","sources":["../../../../../../../server/routes/auth/controllers/2factor/providers/totp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAQ1D,UAAU,OAAO;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,UAAU,CAAC;CAChB;AAED,UAAU,KAAK;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,UAAU,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAYD,QAAA,MAAM,YAAY,GAAU,aAAa,OAAO,kBAK/C,CAAC;AAEF,QAAA,MAAM,YAAY,GAAU,aAAa,OAAO,kBAK/C,CAAC;AAEF,QAAA,MAAM,SAAS,GAAU,aAAa,OAAO;;;;EAc5C,CAAC;AAuBF,QAAA,MAAM,QAAQ,GAAU,aAAa,OAAO;;;;;;;;;;;;EA0C3C,CAAC;AAEF,QAAA,MAAM,MAAM,GAAU,0BAA0B,KAAK;;;EAiBpD,CAAC;AAKF,QAAA,MAAM,MAAM,GAAU,2BAA2B,KAAK,iBAqBrD,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;;AAE3E,wBAAoB"}
|
|
@@ -2,13 +2,13 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import qrcode from "qrcode";
|
|
3
3
|
import { authenticator } from "otplib";
|
|
4
4
|
const TYPE = "TOTP";
|
|
5
|
-
const enableSecret = async ({ uid,
|
|
5
|
+
const enableSecret = async ({ uid, pg }) => {
|
|
6
6
|
await pg.query("update admin.users_social_auth set enabled=true where uid = $1 and social_auth_type = $2", [uid, TYPE]);
|
|
7
7
|
};
|
|
8
|
-
const deleteSecret = async ({ uid,
|
|
8
|
+
const deleteSecret = async ({ uid, pg }) => {
|
|
9
9
|
await pg.query("delete from admin.users_social_auth where uid=$1 and social_auth_type = $2", [uid, TYPE]);
|
|
10
10
|
};
|
|
11
|
-
const getSecret = async ({ uid,
|
|
11
|
+
const getSecret = async ({ uid, pg }) => {
|
|
12
12
|
const { social_auth_code: secret, enabled, recoveryCodes, } = await pg
|
|
13
13
|
.query(`select social_auth_code, enabled, social_auth_obj->'codesArray' as "recoveryCodes"
|
|
14
14
|
from admin.users_social_auth
|
|
@@ -16,11 +16,11 @@ const getSecret = async ({ uid, TYPE, pg }) => {
|
|
|
16
16
|
.then((el) => el.rows?.[0] || {});
|
|
17
17
|
return { secret, enabled, recoveryCodes };
|
|
18
18
|
};
|
|
19
|
-
const addSecret = async ({ uid, secret,
|
|
19
|
+
const addSecret = async ({ uid, secret, pg, recoveryCodes, otp }) => {
|
|
20
20
|
await pg.query(`insert into admin.users_social_auth(uid, social_auth_code, social_auth_type, social_auth_obj, social_auth_url, enabled)
|
|
21
21
|
values($1, $2, $3, $4::json, $5, false)`, [uid, secret, TYPE, { codesArray: recoveryCodes }, otp]);
|
|
22
22
|
};
|
|
23
|
-
const updateSecret = async ({ uid,
|
|
23
|
+
const updateSecret = async ({ uid, pg, secret, recoveryCodes, otp }) => {
|
|
24
24
|
const result = await pg
|
|
25
25
|
.query(`update admin.users_social_auth
|
|
26
26
|
set social_auth_code=$3, social_auth_obj=$4::json, social_auth_url=$5
|
|
@@ -30,7 +30,7 @@ const updateSecret = async ({ uid, TYPE, pg, secret, recoveryCodes, otp, }) => {
|
|
|
30
30
|
};
|
|
31
31
|
// return a new secret until it's enabled
|
|
32
32
|
const generate = async ({ uid, pg }) => {
|
|
33
|
-
const { enabled } = await getSecret({ uid,
|
|
33
|
+
const { enabled } = await getSecret({ uid, pg });
|
|
34
34
|
if (enabled)
|
|
35
35
|
return { enabled };
|
|
36
36
|
const secret = authenticator.generateSecret();
|
|
@@ -48,7 +48,6 @@ const generate = async ({ uid, pg }) => {
|
|
|
48
48
|
await addSecret({
|
|
49
49
|
uid,
|
|
50
50
|
secret,
|
|
51
|
-
TYPE,
|
|
52
51
|
pg,
|
|
53
52
|
recoveryCodes,
|
|
54
53
|
otp,
|
|
@@ -58,7 +57,6 @@ const generate = async ({ uid, pg }) => {
|
|
|
58
57
|
await updateSecret({
|
|
59
58
|
uid,
|
|
60
59
|
secret,
|
|
61
|
-
TYPE,
|
|
62
60
|
pg,
|
|
63
61
|
recoveryCodes,
|
|
64
62
|
otp,
|
|
@@ -72,7 +70,7 @@ const generate = async ({ uid, pg }) => {
|
|
|
72
70
|
};
|
|
73
71
|
};
|
|
74
72
|
const verify = async ({ uid, code: token, pg }) => {
|
|
75
|
-
const { secret, enabled, recoveryCodes } = await getSecret({ uid,
|
|
73
|
+
const { secret, enabled, recoveryCodes } = await getSecret({ uid, pg });
|
|
76
74
|
// console.debug('secret', secret, 'enabled', enabled, 'verification', 'token', authenticator.generate(secret), authenticator.verify({ token: authenticator.generate(secret), secret }));
|
|
77
75
|
if (!secret) {
|
|
78
76
|
throw new Error("Включіть двофакторну аутентифікацію");
|
|
@@ -99,14 +97,12 @@ const toggle = async ({ uid, code, pg, enable }) => {
|
|
|
99
97
|
if (enable) {
|
|
100
98
|
await enableSecret({
|
|
101
99
|
uid,
|
|
102
|
-
TYPE,
|
|
103
100
|
pg,
|
|
104
101
|
});
|
|
105
102
|
return recoveryCodes;
|
|
106
103
|
}
|
|
107
104
|
await deleteSecret({
|
|
108
105
|
uid,
|
|
109
|
-
TYPE,
|
|
110
106
|
pg,
|
|
111
107
|
});
|
|
112
108
|
return "Відключено";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qrcode.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/qrcode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAa5D,wBAA8B,MAAM,CAClC,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"qrcode.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/qrcode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAa5D,wBAA8B,MAAM,CAClC,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,YAAY,kBAoDpB"}
|
|
@@ -7,7 +7,7 @@ const headers = {
|
|
|
7
7
|
};
|
|
8
8
|
export default async function qrCode(req, reply) {
|
|
9
9
|
const { pg = pgClients.client } = req;
|
|
10
|
-
const { uid } = req.
|
|
10
|
+
const { uid } = req.user || {};
|
|
11
11
|
if (!uid) {
|
|
12
12
|
return reply.status(401).send({ error: "unauthorized", code: 401 });
|
|
13
13
|
}
|
|
@@ -20,12 +20,10 @@ export default async function qrCode(req, reply) {
|
|
|
20
20
|
const userExists = await pg
|
|
21
21
|
.query(`select uid from admin.users where uid=$1`, [uid])
|
|
22
22
|
.then((el) => el.rows?.[0]?.uid);
|
|
23
|
-
if (!userExists
|
|
23
|
+
if (!userExists) {
|
|
24
24
|
return reply.status(404).send({ error: "invalid user", code: 404 });
|
|
25
25
|
}
|
|
26
|
-
const { enabled, secret } = pg
|
|
27
|
-
? await getSecret({ pg, TYPE: "TOTP", uid })
|
|
28
|
-
: {};
|
|
26
|
+
const { enabled, secret } = await getSecret({ pg, uid });
|
|
29
27
|
const otp = secret
|
|
30
28
|
? await pg
|
|
31
29
|
.query(`select social_auth_url
|
|
@@ -16,5 +16,5 @@ import { FastifyReply } from "fastify";
|
|
|
16
16
|
* @returns {String|Object} message Повідомлення про успішне виконання або об'єкт з параметрами
|
|
17
17
|
* @returns {String} redirect Шлях до переадресації
|
|
18
18
|
*/
|
|
19
|
-
export default function
|
|
19
|
+
export default function recovery(req: any, reply: FastifyReply): Promise<never>;
|
|
20
20
|
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAiBvC;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAA8B,
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAiBvC;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAA8B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,kBAqFnE"}
|
|
@@ -26,19 +26,24 @@ const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
26
26
|
* @returns {String|Object} message Повідомлення про успішне виконання або об'єкт з параметрами
|
|
27
27
|
* @returns {String} redirect Шлях до переадресації
|
|
28
28
|
*/
|
|
29
|
-
export default async function
|
|
30
|
-
const { pg = pgClients.client,
|
|
31
|
-
if (!
|
|
32
|
-
return reply.status(
|
|
29
|
+
export default async function recovery(req, reply) {
|
|
30
|
+
const { pg = pgClients.client, user, body = {}, method } = req;
|
|
31
|
+
if (!user?.uid) {
|
|
32
|
+
return reply.status(401).send({ error: "unauthorized", code: 401 });
|
|
33
|
+
}
|
|
34
|
+
if (!user.twofa) {
|
|
35
|
+
return reply.status(400).send({ error: "2fa not enabled", code: 400 });
|
|
33
36
|
}
|
|
34
37
|
if (!config.pg) {
|
|
35
|
-
return reply.status(400).send("empty pg");
|
|
38
|
+
return reply.status(400).send({ error: "empty pg", code: 400 });
|
|
36
39
|
}
|
|
37
40
|
const { code } = body;
|
|
38
|
-
const { uid, email } =
|
|
41
|
+
const { uid, email } = user || {};
|
|
39
42
|
if (!code) {
|
|
40
43
|
if (!email) {
|
|
41
|
-
return reply
|
|
44
|
+
return reply
|
|
45
|
+
.status(404)
|
|
46
|
+
.send({ error: "user recovery email not set", code: 404 });
|
|
42
47
|
}
|
|
43
48
|
// return reply.status(400).send('not enough params');
|
|
44
49
|
const customPt = await getTemplate("pt", template);
|
|
@@ -49,8 +54,9 @@ export default async function recoveryFunction(req, reply) {
|
|
|
49
54
|
where uid = $1 and social_auth_type = $2`, [uid, "TOTP"])
|
|
50
55
|
.then((el) => el.rows?.[0]?.recoveryCodes || []);
|
|
51
56
|
if (!recoveryCodes?.length) {
|
|
52
|
-
return reply
|
|
53
|
-
|
|
57
|
+
return reply
|
|
58
|
+
.status(404)
|
|
59
|
+
.send({ error: "user recovery code not found", code: 404 });
|
|
54
60
|
}
|
|
55
61
|
const html = await handlebars.compile(pt)({
|
|
56
62
|
recoveryCodes: [recoveryCodes[0]],
|
|
@@ -61,23 +67,25 @@ export default async function recoveryFunction(req, reply) {
|
|
|
61
67
|
to: email,
|
|
62
68
|
template: html,
|
|
63
69
|
title: `Recovery code for ${req.hostname} 2-factor authentication`,
|
|
64
|
-
nocache: config.local || config.debug,
|
|
70
|
+
nocache: config.local || config.debug || user?.user_type?.includes?.("admin"),
|
|
65
71
|
});
|
|
72
|
+
if (method === "POST") {
|
|
73
|
+
return reply.status(200).send({ redirectUrl: "/2factor?recovery=1" });
|
|
74
|
+
}
|
|
66
75
|
return reply.redirect("/2factor?recovery=1");
|
|
67
|
-
// return reply.status(200).send('recovery code sent to user email');
|
|
68
76
|
}
|
|
69
77
|
try {
|
|
70
78
|
// validate recovery code
|
|
71
79
|
await verify({ uid, code, pg });
|
|
72
80
|
// delete old secret
|
|
73
|
-
await deleteSecret({
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
return reply.redirect(
|
|
81
|
+
await deleteSecret({ pg, uid });
|
|
82
|
+
const redirectUrl = config.auth?.link?.["2fa"]?.login || "/2factor";
|
|
83
|
+
if (method === "POST") {
|
|
84
|
+
return reply.status(200).send({ redirectUrl });
|
|
85
|
+
}
|
|
86
|
+
return reply.redirect(redirectUrl);
|
|
79
87
|
}
|
|
80
88
|
catch (err) {
|
|
81
|
-
return reply.status(500).send(err.toString());
|
|
89
|
+
return reply.status(500).send({ error: err.toString(), code: 500 });
|
|
82
90
|
}
|
|
83
91
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/reset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAOvC,wBAA8B,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,kBAiBhE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import config from "../../../../../config.js";
|
|
2
|
+
import pgClients from "../../../../plugins/pg/pgClients.js";
|
|
3
|
+
import { deleteSecret } from "./providers/totp.js";
|
|
4
|
+
export default async function reset(req, reply) {
|
|
5
|
+
const { pg = pgClients.client, query } = req;
|
|
6
|
+
if (!query?.uid) {
|
|
7
|
+
return reply.status(400).send({
|
|
8
|
+
error: "not enough query params: uid",
|
|
9
|
+
code: 400,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
if (!config.pg) {
|
|
13
|
+
return reply.status(400).send({ error: "empty pg", code: 400 });
|
|
14
|
+
}
|
|
15
|
+
await deleteSecret({ pg, uid: query.uid });
|
|
16
|
+
return reply.status(200).send({ ok: true });
|
|
17
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA0BvC;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAA8B,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/2factor/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA0BvC;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAA8B,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,kBAwEzE"}
|
|
@@ -30,26 +30,23 @@ const defaultPt = existsSync(path.join(dirname, `../../../../templates/pt/${temp
|
|
|
30
30
|
* @returns {String} redirect Шлях до переадресації
|
|
31
31
|
*/
|
|
32
32
|
export default async function verifyFunction(req, reply) {
|
|
33
|
-
const { pg = pgClients.client,
|
|
34
|
-
const { uid, twofa, email } =
|
|
35
|
-
// const { nocache = config.local } = query;
|
|
33
|
+
const { pg = pgClients.client, user = {}, body = {} } = req;
|
|
34
|
+
const { uid, twofa, email } = user || {};
|
|
36
35
|
const { code } = body;
|
|
37
36
|
if (!twofa) {
|
|
38
|
-
return reply.status(400).send("2fa not enabled");
|
|
37
|
+
return reply.status(400).send({ error: "2fa not enabled", code: 400 });
|
|
39
38
|
}
|
|
40
39
|
if (!config.pg) {
|
|
41
|
-
return reply.status(400).send("empty pg");
|
|
40
|
+
return reply.status(400).send({ error: "empty pg", code: 400 });
|
|
42
41
|
}
|
|
43
42
|
if (!code) {
|
|
44
|
-
return reply
|
|
43
|
+
return reply
|
|
44
|
+
.status(400)
|
|
45
|
+
.send({ error: "not enough body params: code", code: 400 });
|
|
45
46
|
}
|
|
46
47
|
try {
|
|
47
48
|
const { enabled } = await verify({ uid, code, pg });
|
|
48
|
-
await enableSecret({
|
|
49
|
-
pg,
|
|
50
|
-
TYPE: "TOTP",
|
|
51
|
-
uid,
|
|
52
|
-
});
|
|
49
|
+
await enableSecret({ pg, uid });
|
|
53
50
|
req.session.secondFactorPassed = true;
|
|
54
51
|
if (!enabled && email) {
|
|
55
52
|
const { recoveryCodes } = await pg
|
|
@@ -68,7 +65,7 @@ export default async function verifyFunction(req, reply) {
|
|
|
68
65
|
to: email,
|
|
69
66
|
template: html,
|
|
70
67
|
title: `Recovery codes for ${req.hostname} 2-factor authentication`,
|
|
71
|
-
nocache: config.local || config.debug,
|
|
68
|
+
nocache: config.local || config.debug || user?.user_type?.includes?.("admin"),
|
|
72
69
|
});
|
|
73
70
|
}
|
|
74
71
|
const redirectUrl = req.headers?.referer?.match?.(/[?&]redirect=([^&]+)/)?.[1] || "/";
|
|
@@ -78,8 +75,12 @@ export default async function verifyFunction(req, reply) {
|
|
|
78
75
|
.send({ redirectUrl: redirectUrl.startsWith("/") ? redirectUrl : "/" });
|
|
79
76
|
}
|
|
80
77
|
catch (err) {
|
|
81
|
-
if (
|
|
82
|
-
|
|
78
|
+
if ([
|
|
79
|
+
"Невірний код",
|
|
80
|
+
"Вже знаходиться у даному стані",
|
|
81
|
+
"Включіть двофакторну аутентифікацію",
|
|
82
|
+
].includes(err.message)) {
|
|
83
|
+
return reply.status(400).send({ error: err.message, code: 400 });
|
|
83
84
|
}
|
|
84
85
|
return reply.status(500).send(err.toString());
|
|
85
86
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login2faTemplate.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/page/login2faTemplate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"login2faTemplate.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/auth/controllers/page/login2faTemplate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAiC5D,wBAA8B,aAAa,CACzC,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,YAAY,kBAgEpB"}
|
|
@@ -10,6 +10,8 @@ import { getSecret, generate } from "../2factor/providers/totp.js";
|
|
|
10
10
|
// relative default template filepath
|
|
11
11
|
const filename = fileURLToPath(import.meta.url);
|
|
12
12
|
const dirname = path.dirname(filename);
|
|
13
|
+
const twoFactorPagePath = path.join(dirname, "../../../../../server/templates/page/2factor.html");
|
|
14
|
+
const defaultPagePath = path.join(dirname, "../../../../../server/templates/page/2factor-recovery.html");
|
|
13
15
|
const headers = {
|
|
14
16
|
"Content-Type": "text/html; charset=UTF-8",
|
|
15
17
|
"Cache-Control": "no-cache",
|
|
@@ -17,9 +19,9 @@ const headers = {
|
|
|
17
19
|
};
|
|
18
20
|
export default async function loginTemplate(req, reply) {
|
|
19
21
|
const { pg = pgClients.client } = req;
|
|
20
|
-
const { uid } = req.
|
|
22
|
+
const { uid } = req.user || {};
|
|
21
23
|
if (!uid) {
|
|
22
|
-
return reply.
|
|
24
|
+
return reply.status(401).send({ error: "unauthorized", code: 401 });
|
|
23
25
|
}
|
|
24
26
|
const userExists = pg?.pk?.["admin.users"]
|
|
25
27
|
? await pg
|
|
@@ -27,14 +29,11 @@ export default async function loginTemplate(req, reply) {
|
|
|
27
29
|
.then((el) => el.rows?.[0]?.uid)
|
|
28
30
|
: false;
|
|
29
31
|
if (!userExists && config.pg) {
|
|
30
|
-
return reply.status(
|
|
32
|
+
return reply.status(404).send({ error: "user not found in db", code: 400 });
|
|
31
33
|
}
|
|
32
|
-
const twoFactorPagePath = path.join(dirname, "../../../../../server/templates/page/2factor.html");
|
|
33
34
|
const customBody = await getTemplate("page", "2factor");
|
|
34
35
|
const body = customBody || (await readFile(twoFactorPagePath, "utf8"));
|
|
35
|
-
const { enabled, secret } = config.pg
|
|
36
|
-
? await getSecret({ pg, TYPE: "TOTP", uid })
|
|
37
|
-
: {};
|
|
36
|
+
const { enabled, secret } = config.pg ? await getSecret({ pg, uid }) : {};
|
|
38
37
|
const { otp, recoveryCodes, key } = secret && pg?.pk?.["admin.users_social_auth"]
|
|
39
38
|
? await pg
|
|
40
39
|
.query(`select social_auth_obj->'codesArray' as "recoveryCodes", enabled, social_auth_url as otp
|
|
@@ -44,7 +43,6 @@ export default async function loginTemplate(req, reply) {
|
|
|
44
43
|
/* -- access recovery start */
|
|
45
44
|
// user already authorized via euSign / social / login
|
|
46
45
|
if (uid && !req.session?.secondFactorPassed && req.query?.recovery) {
|
|
47
|
-
const defaultPagePath = path.join(dirname, "../../../../../server/templates/page/2factor-recovery.html");
|
|
48
46
|
const customBodyRecovery = await getTemplate("page", "2factor-recovery");
|
|
49
47
|
const bodyRecovery = customBodyRecovery || (await readFile(defaultPagePath, "utf8"));
|
|
50
48
|
const html = await handlebars.compile(bodyRecovery)({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/routes/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/routes/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAmC1C,iBAAS,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,GAAE,GAAQ,QAiFlD;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -12,6 +12,7 @@ import updateUserInfo from "./controllers/core/updateUserInfo.js";
|
|
|
12
12
|
// 2factor / totp
|
|
13
13
|
import verify from "./controllers/2factor/verify.js";
|
|
14
14
|
import recovery from "./controllers/2factor/recovery.js";
|
|
15
|
+
import reset from "./controllers/2factor/reset.js";
|
|
15
16
|
// pages
|
|
16
17
|
import loginTemplate from "./controllers/page/loginTemplate.js";
|
|
17
18
|
import login2faTemplate from "./controllers/page/login2faTemplate.js";
|
|
@@ -49,6 +50,9 @@ function plugin(app, opt = {}) {
|
|
|
49
50
|
if (!app.hasRoute({ method: "GET", url: "/2factor/recovery" })) {
|
|
50
51
|
app.get("/2factor/recovery", params, recovery);
|
|
51
52
|
}
|
|
53
|
+
if (!app.hasRoute({ method: "GET", url: "/2factor/reset" })) {
|
|
54
|
+
app.get("/2factor/reset", { config: { role: "admin" } }, reset);
|
|
55
|
+
}
|
|
52
56
|
// get/edit user info
|
|
53
57
|
if (!app.hasRoute({ method: "GET", url: "/user" })) {
|
|
54
58
|
app.get("/user", params, getUserInfo);
|