@opengis/fastify-table 2.1.2 → 2.1.4
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/index.js +1 -1
- package/dist/server/helpers/list/descriptionList.d.ts.map +1 -1
- package/dist/server/helpers/list/descriptionList.js +9 -5
- package/dist/server/plugins/auth/index.d.ts.map +1 -1
- package/dist/server/plugins/auth/index.js +8 -4
- package/dist/server/plugins/auth/onRequest.d.ts +4 -0
- package/dist/server/plugins/auth/onRequest.d.ts.map +1 -0
- package/dist/server/plugins/auth/onRequest.js +104 -0
- package/dist/server/plugins/crud/funcs/dataInsert.d.ts +2 -1
- package/dist/server/plugins/crud/funcs/dataInsert.d.ts.map +1 -1
- package/dist/server/plugins/crud/funcs/dataInsert.js +13 -11
- package/dist/server/plugins/crud/funcs/dataUpdate.d.ts +2 -1
- package/dist/server/plugins/crud/funcs/dataUpdate.d.ts.map +1 -1
- package/dist/server/plugins/crud/funcs/dataUpdate.js +13 -11
- package/dist/server/plugins/policy/funcs/checkAuth.d.ts +4 -0
- package/dist/server/plugins/policy/funcs/checkAuth.d.ts.map +1 -0
- package/dist/server/plugins/policy/funcs/checkAuth.js +104 -0
- package/dist/server/plugins/policy/funcs/checkPermissions.d.ts +4 -2
- package/dist/server/plugins/policy/funcs/checkPermissions.d.ts.map +1 -1
- package/dist/server/plugins/policy/funcs/checkPermissions.js +2 -4
- package/dist/server/plugins/policy/funcs/checkPolicy.d.ts +4 -2
- package/dist/server/plugins/policy/funcs/checkPolicy.d.ts.map +1 -1
- package/dist/server/plugins/policy/funcs/checkPolicy.js +8 -8
- package/dist/server/plugins/policy/index.d.ts +1 -1
- package/dist/server/plugins/policy/index.d.ts.map +1 -1
- package/dist/server/plugins/policy/index.js +6 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -111,8 +111,8 @@ function plugin(fastify) {
|
|
|
111
111
|
// core migrations (second argument for core only)
|
|
112
112
|
execMigrations(path.join(cwd, "server/migrations"), pgClients.client, true).catch((err) => console.warn(err.toString()));
|
|
113
113
|
// plugins / utils / funcs
|
|
114
|
-
policyPlugin(fastify);
|
|
115
114
|
authPlugin(fastify); // fastify-auth api + hooks integrated to core
|
|
115
|
+
policyPlugin(fastify);
|
|
116
116
|
metricPlugin();
|
|
117
117
|
redisPlugin(fastify);
|
|
118
118
|
pgPlugin(fastify);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"descriptionList.d.ts","sourceRoot":"","sources":["../../../../server/helpers/list/descriptionList.ts"],"names":[],"mappings":"AAkBA,wBAA8B,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"descriptionList.d.ts","sourceRoot":"","sources":["../../../../server/helpers/list/descriptionList.ts"],"names":[],"mappings":"AAkBA,wBAA8B,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,gBAkChE"}
|
|
@@ -33,11 +33,15 @@ export default async function descriptionList(data, opt) {
|
|
|
33
33
|
continue;
|
|
34
34
|
const key = keys[i + 1];
|
|
35
35
|
const d1 = (await format(data[key], key, data)) || '-';
|
|
36
|
-
result.push(`<div class="grid grid-cols-
|
|
37
|
-
<dt class="text-gray-900
|
|
38
|
-
|
|
39
|
-
</
|
|
40
|
-
|
|
36
|
+
result.push(`<div class="flex flex-wrap sm:grid sm:grid-cols-3 gap-1 py-3 even:bg-gray-50 text-[12px]">
|
|
37
|
+
<dt class="text-gray-900 w-full sm:w-auto sm:col-span-1 pr-2 break-words">
|
|
38
|
+
${nameHBS || name}
|
|
39
|
+
</dt>
|
|
40
|
+
|
|
41
|
+
<dd class="text-gray-700 sm:col-span-2 w-full sm:w-auto break-words whitespace-normal">
|
|
42
|
+
${d1}
|
|
43
|
+
</dd>
|
|
44
|
+
</div>`);
|
|
41
45
|
}
|
|
42
46
|
return `<dl class=" divide-y divide-gray-100 py-[5px] w-full">${result.join('')}</dl>`;
|
|
43
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/plugins/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAYxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAMtD,wBAAsB,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/plugins/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAYxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAMtD,wBAAsB,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,iBA+HxE;AAED,iBAAS,MAAM,CAAC,OAAO,EAAE,eAAe,QAmCvC;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -21,11 +21,12 @@ export async function onRequest(req, reply) {
|
|
|
21
21
|
req.ip === "127.0.0.1" ||
|
|
22
22
|
req.ip?.startsWith?.("192.168.") ||
|
|
23
23
|
config.debug) &&
|
|
24
|
-
req.headers?.token &&
|
|
25
|
-
|
|
24
|
+
((req.headers?.token && config.auth?.tokens?.includes?.(headers.token)) ||
|
|
25
|
+
process.env.NODE_ENV === "test" ||
|
|
26
|
+
process.env.VITEST);
|
|
26
27
|
if (validToken && !req?.user?.uid) {
|
|
27
28
|
req.user = {
|
|
28
|
-
uid: req.headers?.uid?.toString?.(),
|
|
29
|
+
uid: req.headers?.uid?.toString?.() || "1",
|
|
29
30
|
user_type: req.headers?.user_type?.toString?.() || "regular",
|
|
30
31
|
};
|
|
31
32
|
}
|
|
@@ -112,6 +113,10 @@ function plugin(fastify) {
|
|
|
112
113
|
if (!config.redis) {
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
116
|
+
fastify.addHook("onRequest", onRequest);
|
|
117
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
115
120
|
fastify.register(cookie, {
|
|
116
121
|
parseOptions: config?.auth?.cookieOptions || { secure: false },
|
|
117
122
|
});
|
|
@@ -131,6 +136,5 @@ function plugin(fastify) {
|
|
|
131
136
|
fastifyPassport.registerUserSerializer(async (user) => ({ user }));
|
|
132
137
|
// deserialize user used to add user info from session store to req
|
|
133
138
|
fastifyPassport.registerUserDeserializer(async (passport) => passport?.user || passport);
|
|
134
|
-
fastify.addHook("onRequest", onRequest);
|
|
135
139
|
}
|
|
136
140
|
export default plugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onRequest.d.ts","sourceRoot":"","sources":["../../../../server/plugins/auth/onRequest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAItD,wBAA8B,SAAS,CACrC,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,YAAY,iBA+HpB"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import config from "../../../config.js";
|
|
3
|
+
const { prefix = "/api" } = config;
|
|
4
|
+
export default async function onRequest(req, reply) {
|
|
5
|
+
const { hostname, headers, routeOptions } = req;
|
|
6
|
+
const { config: routeConfig, method, handler, url } = routeOptions || {};
|
|
7
|
+
const { policy } = routeConfig || {};
|
|
8
|
+
const isApi = method && url && typeof handler === "function" && url !== "*";
|
|
9
|
+
// handle non-api at vite/vike
|
|
10
|
+
if (!isApi) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
// proxy from old apps to editor, bi etc.
|
|
14
|
+
const validToken = (req.ip === "193.239.152.181" ||
|
|
15
|
+
req.ip === "127.0.0.1" ||
|
|
16
|
+
req.ip?.startsWith?.("192.168.") ||
|
|
17
|
+
config.debug) &&
|
|
18
|
+
req.headers?.token &&
|
|
19
|
+
config.auth?.tokens?.includes?.(headers.token);
|
|
20
|
+
if (validToken && !req?.user?.uid) {
|
|
21
|
+
req.user = {
|
|
22
|
+
uid: req.headers?.uid?.toString?.(),
|
|
23
|
+
user_type: req.headers?.user_type?.toString?.() || "regular",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const isAdmin = process.env.NODE_ENV === "admin" ||
|
|
27
|
+
hostname?.split?.(":")?.shift?.() === config.adminDomain ||
|
|
28
|
+
config.admin ||
|
|
29
|
+
hostname?.startsWith?.("admin");
|
|
30
|
+
const isPublic = Array.isArray(policy)
|
|
31
|
+
? policy.includes("public")
|
|
32
|
+
: policy === "L0";
|
|
33
|
+
if (req.cookies?.["session_auth"] &&
|
|
34
|
+
!req.session?.passport?.user?.uid &&
|
|
35
|
+
(config.auth?.disable || config.auth?.user)) {
|
|
36
|
+
req.session = req.session || {};
|
|
37
|
+
req.session.passport = req.session.passport || {}; // ensure passport session exists
|
|
38
|
+
req.session.passport.user = {
|
|
39
|
+
...(config.auth?.user || {}),
|
|
40
|
+
uid: config.auth?.user?.uid?.toString?.() || "1",
|
|
41
|
+
user_rnokpp: config.auth?.user?.rnokpp,
|
|
42
|
+
user_type: config.auth?.user?.type || "regular",
|
|
43
|
+
};
|
|
44
|
+
req.user = req.session.passport.user;
|
|
45
|
+
}
|
|
46
|
+
// ! intentional: null || undefined > undefined
|
|
47
|
+
req.user = req.user || req.session?.passport?.user || undefined; // fix for user.uid errors, by default user is null, while with express passport it was {}, unauthorized user does not trigger serializer
|
|
48
|
+
// currently 2factor + auth with passwd file not supported
|
|
49
|
+
const ispasswd = (existsSync("passwd") && !config.auth?.["2factor"]) || config.auth?.passwd;
|
|
50
|
+
const loginPageUrl = config.auth?.link?.core?.login || config?.auth?.redirect || "/login";
|
|
51
|
+
if (!req.user?.uid &&
|
|
52
|
+
!config.auth?.disable &&
|
|
53
|
+
isAdmin &&
|
|
54
|
+
!isPublic &&
|
|
55
|
+
!config.auth?.disableRedirect &&
|
|
56
|
+
!req.url.startsWith(prefix) &&
|
|
57
|
+
!req.url.startsWith("/api") &&
|
|
58
|
+
!req.url.includes(loginPageUrl) &&
|
|
59
|
+
!req.url.includes(".") &&
|
|
60
|
+
!req.url.includes("@")) {
|
|
61
|
+
if (isApi) {
|
|
62
|
+
return reply.status(401).send({ error: "unauthorized", code: 401 });
|
|
63
|
+
}
|
|
64
|
+
return reply.redirect(`${loginPageUrl}` + `?redirect=${req.url}`);
|
|
65
|
+
}
|
|
66
|
+
// by default, disable 2factor for id.gov.ua auth
|
|
67
|
+
const check = req.user?.auth_type === "govid" ? config.auth?.["2factor"]?.govid : true;
|
|
68
|
+
const login2faPage = config.auth?.link?.["2fa"]?.login || "/2factor";
|
|
69
|
+
// example: 2factor for admin env only, while public env does not require it
|
|
70
|
+
const checkEnv = () => {
|
|
71
|
+
if (!config.auth?.["2factorEnv"])
|
|
72
|
+
return true;
|
|
73
|
+
if ((config.auth?.["2factorEnv"] &&
|
|
74
|
+
process.env.NODE_ENV === config.auth?.["2factorEnv"]) ||
|
|
75
|
+
(config.auth?.["2factorEnv"] === "admin" && isAdmin)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
};
|
|
80
|
+
// if 2factor is enabled globally + for user and secondFactorPassed not true => redirect to 2factor login page
|
|
81
|
+
if (req.user?.uid &&
|
|
82
|
+
req.user?.twofa &&
|
|
83
|
+
// config.auth?.["2factor"] &&
|
|
84
|
+
// !isPublic &&
|
|
85
|
+
(routeOptions?.method || "GET") === "GET" &&
|
|
86
|
+
!req.session?.secondFactorPassed &&
|
|
87
|
+
!ispasswd &&
|
|
88
|
+
!config.auth?.disableRedirect &&
|
|
89
|
+
!config.auth?.disable &&
|
|
90
|
+
check &&
|
|
91
|
+
checkEnv() &&
|
|
92
|
+
!req.url.startsWith(login2faPage) &&
|
|
93
|
+
!routeOptions.url?.includes?.("/logout") &&
|
|
94
|
+
!routeOptions.url?.includes?.("/2fa") &&
|
|
95
|
+
!routeOptions.url?.includes?.("/assets")) {
|
|
96
|
+
if (isApi) {
|
|
97
|
+
return reply
|
|
98
|
+
.status(403)
|
|
99
|
+
.send({ error: "access restricted: twofa", code: 403 });
|
|
100
|
+
}
|
|
101
|
+
return reply.redirect(login2faPage);
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtendedPG } from "../../../types/core.js";
|
|
2
|
-
export default function dataInsert({ id, table: table1, referer, data, pg: pg1, uid, tokenData, }: {
|
|
2
|
+
export default function dataInsert({ id, table: table1, referer, data, pg: pg1, uid, tokenData, log, }: {
|
|
3
3
|
id?: string | number;
|
|
4
4
|
table: string;
|
|
5
5
|
referer?: string;
|
|
@@ -7,5 +7,6 @@ export default function dataInsert({ id, table: table1, referer, data, pg: pg1,
|
|
|
7
7
|
pg?: ExtendedPG;
|
|
8
8
|
uid?: string;
|
|
9
9
|
tokenData?: Record<string, any>;
|
|
10
|
+
log?: Boolean;
|
|
10
11
|
}): Promise<any>;
|
|
11
12
|
//# sourceMappingURL=dataInsert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataInsert.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/crud/funcs/dataInsert.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgBzD,wBAA8B,UAAU,CAAC,EACvC,EAAE,EACF,KAAK,EAAE,MAAM,EACb,OAAO,EACP,IAAI,EACJ,EAAE,EAAE,GAAG,EACP,GAAG,EACH,SAAc,
|
|
1
|
+
{"version":3,"file":"dataInsert.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/crud/funcs/dataInsert.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgBzD,wBAA8B,UAAU,CAAC,EACvC,EAAE,EACF,KAAK,EAAE,MAAM,EACb,OAAO,EACP,IAAI,EACJ,EAAE,EAAE,GAAG,EACP,GAAG,EACH,SAAc,EACd,GAAU,GACX,EAAE;IACD,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,gBAsKA"}
|
|
@@ -9,7 +9,7 @@ import logger from "../../logger/getLogger.js";
|
|
|
9
9
|
import extraData from "../../extra/extraData.js";
|
|
10
10
|
import getMeta from "../../pg/funcs/getMeta.js";
|
|
11
11
|
const rclient = getRedis();
|
|
12
|
-
export default async function dataInsert({ id, table: table1, referer, data, pg: pg1, uid, tokenData = {}, }) {
|
|
12
|
+
export default async function dataInsert({ id, table: table1, referer, data, pg: pg1, uid, tokenData = {}, log = true, }) {
|
|
13
13
|
const pg = pg1 || getPG({ name: "client" });
|
|
14
14
|
if (!pg) {
|
|
15
15
|
return null;
|
|
@@ -95,16 +95,18 @@ export default async function dataInsert({ id, table: table1, referer, data, pg:
|
|
|
95
95
|
Object.assign(res.rows[0], { [key]: parentRows.filter(Boolean) });
|
|
96
96
|
}));
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
if (log) {
|
|
99
|
+
await logChanges({
|
|
100
|
+
pg: client,
|
|
101
|
+
table,
|
|
102
|
+
tokenData,
|
|
103
|
+
referer,
|
|
104
|
+
data,
|
|
105
|
+
id: id1,
|
|
106
|
+
uid,
|
|
107
|
+
type: "INSERT",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
108
110
|
if (config.redis && rclient?.status !== "end") {
|
|
109
111
|
rclient.incr(`pg:${client.options?.database}:${table}:crud`);
|
|
110
112
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ExtendedPG } from "../../../types/core.js";
|
|
2
|
-
export default function dataUpdate({ table: table1, tokenData, referer, id, data, pg: pg1, uid, }: {
|
|
2
|
+
export default function dataUpdate({ table: table1, tokenData, referer, id, data, pg: pg1, uid, log, }: {
|
|
3
3
|
table: string;
|
|
4
4
|
tokenData?: Record<string, any>;
|
|
5
5
|
referer?: string;
|
|
@@ -7,5 +7,6 @@ export default function dataUpdate({ table: table1, tokenData, referer, id, data
|
|
|
7
7
|
data: Record<string, any>;
|
|
8
8
|
pg?: ExtendedPG;
|
|
9
9
|
uid?: string;
|
|
10
|
+
log?: Boolean;
|
|
10
11
|
}): Promise<any>;
|
|
11
12
|
//# sourceMappingURL=dataUpdate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataUpdate.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/crud/funcs/dataUpdate.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAepD,wBAA8B,UAAU,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,SAAS,EACT,OAAO,EACP,EAAE,EACF,IAAI,EACJ,EAAE,EAAE,GAAG,EACP,GAAG,
|
|
1
|
+
{"version":3,"file":"dataUpdate.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/crud/funcs/dataUpdate.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAepD,wBAA8B,UAAU,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,SAAS,EACT,OAAO,EACP,EAAE,EACF,IAAI,EACJ,EAAE,EAAE,GAAG,EACP,GAAG,EACH,GAAU,GACX,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,gBAwPA"}
|
|
@@ -19,7 +19,7 @@ function assignValue(key, i, srid = 4326, columnType = "text") {
|
|
|
19
19
|
}
|
|
20
20
|
return `"${key}"=$${i + 2}`;
|
|
21
21
|
}
|
|
22
|
-
export default async function dataUpdate({ table: table1, tokenData, referer, id, data, pg: pg1, uid, }) {
|
|
22
|
+
export default async function dataUpdate({ table: table1, tokenData, referer, id, data, pg: pg1, uid, log = true, }) {
|
|
23
23
|
if (!data || !table1 || !id) {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
@@ -161,16 +161,18 @@ export default async function dataUpdate({ table: table1, tokenData, referer, id
|
|
|
161
161
|
}
|
|
162
162
|
}));
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
164
|
+
if (log) {
|
|
165
|
+
await logChanges({
|
|
166
|
+
pg: client,
|
|
167
|
+
table,
|
|
168
|
+
tokenData,
|
|
169
|
+
referer,
|
|
170
|
+
data,
|
|
171
|
+
id,
|
|
172
|
+
uid,
|
|
173
|
+
type: "UPDATE",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
174
176
|
if (config.redis && rclient?.status !== "end") {
|
|
175
177
|
rclient.incr(`pg:${client.options?.database}:${table}:crud`);
|
|
176
178
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkAuth.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,wBAA8B,SAAS,CACrC,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,YAAY,iBA+HpB"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import config from "../../../../config.js";
|
|
3
|
+
const { prefix = "/api" } = config;
|
|
4
|
+
export default async function onRequest(req, reply) {
|
|
5
|
+
const { hostname, headers, routeOptions } = req;
|
|
6
|
+
const { config: routeConfig, method, handler, url } = routeOptions || {};
|
|
7
|
+
const { policy } = routeConfig || {};
|
|
8
|
+
const isApi = method && url && typeof handler === "function" && url !== "*";
|
|
9
|
+
// handle non-api at vite/vike
|
|
10
|
+
if (!isApi) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
// proxy from old apps to editor, bi etc.
|
|
14
|
+
const validToken = (req.ip === "193.239.152.181" ||
|
|
15
|
+
req.ip === "127.0.0.1" ||
|
|
16
|
+
req.ip?.startsWith?.("192.168.") ||
|
|
17
|
+
config.debug) &&
|
|
18
|
+
req.headers?.token &&
|
|
19
|
+
config.auth?.tokens?.includes?.(headers.token);
|
|
20
|
+
if (validToken && !req?.user?.uid) {
|
|
21
|
+
req.user = {
|
|
22
|
+
uid: req.headers?.uid?.toString?.(),
|
|
23
|
+
user_type: req.headers?.user_type?.toString?.() || "regular",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const isAdmin = process.env.NODE_ENV === "admin" ||
|
|
27
|
+
hostname?.split?.(":")?.shift?.() === config.adminDomain ||
|
|
28
|
+
config.admin ||
|
|
29
|
+
hostname?.startsWith?.("admin");
|
|
30
|
+
const isPublic = Array.isArray(policy)
|
|
31
|
+
? policy.includes("public")
|
|
32
|
+
: policy === "L0";
|
|
33
|
+
if (req.cookies?.["session_auth"] &&
|
|
34
|
+
!req.session?.passport?.user?.uid &&
|
|
35
|
+
(config.auth?.disable || config.auth?.user)) {
|
|
36
|
+
req.session = req.session || {};
|
|
37
|
+
req.session.passport = req.session.passport || {}; // ensure passport session exists
|
|
38
|
+
req.session.passport.user = {
|
|
39
|
+
...(config.auth?.user || {}),
|
|
40
|
+
uid: config.auth?.user?.uid?.toString?.() || "1",
|
|
41
|
+
user_rnokpp: config.auth?.user?.rnokpp,
|
|
42
|
+
user_type: config.auth?.user?.type || "regular",
|
|
43
|
+
};
|
|
44
|
+
req.user = req.session.passport.user;
|
|
45
|
+
}
|
|
46
|
+
// ! intentional: null || undefined > undefined
|
|
47
|
+
req.user = req.user || req.session?.passport?.user || undefined; // fix for user.uid errors, by default user is null, while with express passport it was {}, unauthorized user does not trigger serializer
|
|
48
|
+
// currently 2factor + auth with passwd file not supported
|
|
49
|
+
const ispasswd = (existsSync("passwd") && !config.auth?.["2factor"]) || config.auth?.passwd;
|
|
50
|
+
const loginPageUrl = config.auth?.link?.core?.login || config?.auth?.redirect || "/login";
|
|
51
|
+
if (!req.user?.uid &&
|
|
52
|
+
!config.auth?.disable &&
|
|
53
|
+
isAdmin &&
|
|
54
|
+
!isPublic &&
|
|
55
|
+
!config.auth?.disableRedirect &&
|
|
56
|
+
!req.url.startsWith(prefix) &&
|
|
57
|
+
!req.url.startsWith("/api") &&
|
|
58
|
+
!req.url.includes(loginPageUrl) &&
|
|
59
|
+
!req.url.includes(".") &&
|
|
60
|
+
!req.url.includes("@")) {
|
|
61
|
+
if (isApi) {
|
|
62
|
+
return reply.status(401).send({ error: "unauthorized", code: 401 });
|
|
63
|
+
}
|
|
64
|
+
return reply.redirect(`${loginPageUrl}` + `?redirect=${req.url}`);
|
|
65
|
+
}
|
|
66
|
+
// by default, disable 2factor for id.gov.ua auth
|
|
67
|
+
const check = req.user?.auth_type === "govid" ? config.auth?.["2factor"]?.govid : true;
|
|
68
|
+
const login2faPage = config.auth?.link?.["2fa"]?.login || "/2factor";
|
|
69
|
+
// example: 2factor for admin env only, while public env does not require it
|
|
70
|
+
const checkEnv = () => {
|
|
71
|
+
if (!config.auth?.["2factorEnv"])
|
|
72
|
+
return true;
|
|
73
|
+
if ((config.auth?.["2factorEnv"] &&
|
|
74
|
+
process.env.NODE_ENV === config.auth?.["2factorEnv"]) ||
|
|
75
|
+
(config.auth?.["2factorEnv"] === "admin" && isAdmin)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
};
|
|
80
|
+
// if 2factor is enabled globally + for user and secondFactorPassed not true => redirect to 2factor login page
|
|
81
|
+
if (req.user?.uid &&
|
|
82
|
+
req.user?.twofa &&
|
|
83
|
+
// config.auth?.["2factor"] &&
|
|
84
|
+
// !isPublic &&
|
|
85
|
+
(routeOptions?.method || "GET") === "GET" &&
|
|
86
|
+
!req.session?.secondFactorPassed &&
|
|
87
|
+
!ispasswd &&
|
|
88
|
+
!config.auth?.disableRedirect &&
|
|
89
|
+
!config.auth?.disable &&
|
|
90
|
+
check &&
|
|
91
|
+
checkEnv() &&
|
|
92
|
+
!req.url.startsWith(login2faPage) &&
|
|
93
|
+
!routeOptions.url?.includes?.("/logout") &&
|
|
94
|
+
!routeOptions.url?.includes?.("/2fa") &&
|
|
95
|
+
!routeOptions.url?.includes?.("/assets")) {
|
|
96
|
+
if (isApi) {
|
|
97
|
+
return reply
|
|
98
|
+
.status(403)
|
|
99
|
+
.send({ error: "access restricted: twofa", code: 403 });
|
|
100
|
+
}
|
|
101
|
+
return reply.redirect(login2faPage);
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { FastifyReply } from "fastify";
|
|
2
1
|
import type { ExtendedRequest } from "../../../types/core.js";
|
|
3
|
-
export default function checkPermissions(req: ExtendedRequest
|
|
2
|
+
export default function checkPermissions(req: ExtendedRequest): Promise<{
|
|
3
|
+
error: string;
|
|
4
|
+
code: number;
|
|
5
|
+
} | null>;
|
|
4
6
|
//# sourceMappingURL=checkPermissions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkPermissions.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkPermissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"checkPermissions.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkPermissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAMhC,wBAA8B,gBAAgB,CAAC,GAAG,EAAE,eAAe;;;UA+DlE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logger from "../../logger/getLogger.js";
|
|
2
2
|
import getUserPermissions from "../../access/funcs/getUserPermissions.js";
|
|
3
3
|
import pgClients from "../../pg/pgClients.js";
|
|
4
|
-
export default async function checkPermissions(req
|
|
4
|
+
export default async function checkPermissions(req) {
|
|
5
5
|
const { originalUrl: path, query, params, method, routeOptions, pg = pgClients.client, } = req;
|
|
6
6
|
const user = req.user || req.session?.passport?.user;
|
|
7
7
|
const body = req.body
|
|
@@ -31,9 +31,7 @@ export default async function checkPermissions(req, reply) {
|
|
|
31
31
|
message: "access restricted: permissions",
|
|
32
32
|
uid: user?.uid,
|
|
33
33
|
});
|
|
34
|
-
return
|
|
35
|
-
.status(403)
|
|
36
|
-
.send({ error: "access restricted: permissions", code: 403 });
|
|
34
|
+
return { error: "access restricted: permissions", code: 403 };
|
|
37
35
|
}
|
|
38
36
|
return null;
|
|
39
37
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { FastifyReply } from "fastify";
|
|
2
1
|
import type { ExtendedRequest } from "../../../types/core.js";
|
|
3
|
-
export default function checkPolicy(req: ExtendedRequest
|
|
2
|
+
export default function checkPolicy(req: ExtendedRequest): {
|
|
3
|
+
error: string;
|
|
4
|
+
code: number;
|
|
5
|
+
} | null;
|
|
4
6
|
//# sourceMappingURL=checkPolicy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkPolicy.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"checkPolicy.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,wBAAwB,CAAC;AAKhC,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,GAAG,EAAE,eAAe;;;SAoKvD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { config, logger } from "../../../../utils.js";
|
|
2
2
|
import block from "../sqlInjection.js";
|
|
3
|
-
export default function checkPolicy(req
|
|
3
|
+
export default function checkPolicy(req) {
|
|
4
4
|
const { originalUrl: path, hostname, query, params, headers, method, routeOptions, } = req;
|
|
5
5
|
const user = req.user || req.session?.passport?.user;
|
|
6
6
|
const body = req.body
|
|
@@ -31,7 +31,7 @@ export default function checkPolicy(req, reply) {
|
|
|
31
31
|
method,
|
|
32
32
|
userRole: user.user_type,
|
|
33
33
|
});
|
|
34
|
-
return
|
|
34
|
+
return { error: "access restricted: 0", code: 403 };
|
|
35
35
|
}
|
|
36
36
|
// ! role
|
|
37
37
|
if (isRole) {
|
|
@@ -45,7 +45,7 @@ export default function checkPolicy(req, reply) {
|
|
|
45
45
|
body,
|
|
46
46
|
uid: user?.uid,
|
|
47
47
|
});
|
|
48
|
-
return
|
|
48
|
+
return { error: "access restricted: 0", code: 403 };
|
|
49
49
|
}
|
|
50
50
|
// ! file injection
|
|
51
51
|
if (JSON.stringify(params || {})?.includes("../") ||
|
|
@@ -59,7 +59,7 @@ export default function checkPolicy(req, reply) {
|
|
|
59
59
|
body,
|
|
60
60
|
uid: user?.uid,
|
|
61
61
|
});
|
|
62
|
-
return
|
|
62
|
+
return { error: "access restricted: 1", code: 409 };
|
|
63
63
|
}
|
|
64
64
|
// ! invalid file extension
|
|
65
65
|
if (path.includes("files/") && allowExtPublic.includes(ext)) {
|
|
@@ -77,7 +77,7 @@ export default function checkPolicy(req, reply) {
|
|
|
77
77
|
stopWords,
|
|
78
78
|
uid: user?.uid,
|
|
79
79
|
});
|
|
80
|
-
return
|
|
80
|
+
return { error: "access restricted: 2", code: 409 };
|
|
81
81
|
}
|
|
82
82
|
// ! user required, but not logged in
|
|
83
83
|
if (requireUser && !user) {
|
|
@@ -88,7 +88,7 @@ export default function checkPolicy(req, reply) {
|
|
|
88
88
|
query,
|
|
89
89
|
body,
|
|
90
90
|
});
|
|
91
|
-
return
|
|
91
|
+
return { error: "access restricted: 3", code: 401 };
|
|
92
92
|
}
|
|
93
93
|
// ! referer
|
|
94
94
|
if (requireReferer && !headers?.referer?.includes?.(hostname)) {
|
|
@@ -100,7 +100,7 @@ export default function checkPolicy(req, reply) {
|
|
|
100
100
|
body,
|
|
101
101
|
uid: user?.uid,
|
|
102
102
|
});
|
|
103
|
-
return
|
|
103
|
+
return { error: "access restricted: 4", code: 403 };
|
|
104
104
|
}
|
|
105
105
|
// ! public / token
|
|
106
106
|
if (isPublic || config.debug) {
|
|
@@ -120,7 +120,7 @@ export default function checkPolicy(req, reply) {
|
|
|
120
120
|
message: "access restricted: 6",
|
|
121
121
|
uid: user?.uid,
|
|
122
122
|
});
|
|
123
|
-
return
|
|
123
|
+
return { error: "access restricted: 6", code: 403 };
|
|
124
124
|
}
|
|
125
125
|
return null;
|
|
126
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/plugins/policy/index.ts"],"names":[],"mappings":"AAKA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/plugins/policy/index.ts"],"names":[],"mappings":"AAKA,iBAAS,MAAM,CAAC,OAAO,EAAE,GAAG,QAiC3B;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import config from "../../../config.js";
|
|
2
2
|
import checkPolicy from "./funcs/checkPolicy.js";
|
|
3
3
|
import checkPermissions from "./funcs/checkPermissions.js";
|
|
4
|
-
|
|
5
|
-
fastify.addHook("
|
|
4
|
+
function plugin(fastify) {
|
|
5
|
+
fastify.addHook("preHandler", async (request, reply) => {
|
|
6
6
|
// ! skip locally, skip tests
|
|
7
7
|
if ((process.env.local === "true" || process.env.NODE_ENV === "test") &&
|
|
8
8
|
!config.debugAuth &&
|
|
@@ -18,13 +18,13 @@ async function plugin(fastify) {
|
|
|
18
18
|
if (!isApi) {
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
21
|
-
const resp1 = await checkPermissions(request
|
|
21
|
+
const resp1 = await checkPermissions(request);
|
|
22
22
|
if (resp1) {
|
|
23
|
-
return resp1;
|
|
23
|
+
return reply.status(resp1.code || 403).send(resp1);
|
|
24
24
|
}
|
|
25
|
-
const resp = checkPolicy(request
|
|
25
|
+
const resp = checkPolicy(request);
|
|
26
26
|
if (resp) {
|
|
27
|
-
return resp;
|
|
27
|
+
return reply.status(resp.code || 403).send(resp);
|
|
28
28
|
}
|
|
29
29
|
return null;
|
|
30
30
|
});
|