@opengis/fastify-table 2.5.20 → 2.5.21
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/funcs/getQuery.d.ts.map +1 -1
- package/dist/server/plugins/auth/funcs/getQuery.js +1 -1
- package/dist/server/plugins/file/uploadMultiPart.d.ts.map +1 -1
- package/dist/server/plugins/file/uploadMultiPart.js +4 -1
- package/dist/server/plugins/policy/funcs/checkPolicy.d.ts.map +1 -1
- package/dist/server/plugins/policy/funcs/checkPolicy.js +2 -16
- package/dist/server/plugins/policy/funcs/checkTraversal.d.ts +2 -0
- package/dist/server/plugins/policy/funcs/checkTraversal.d.ts.map +1 -0
- package/dist/server/plugins/policy/funcs/checkTraversal.js +22 -0
- package/dist/server/plugins/policy/index.d.ts.map +1 -1
- package/dist/server/plugins/policy/index.js +3 -1
- package/dist/server/plugins/upload/startUpload.d.ts.map +1 -1
- package/dist/server/plugins/upload/startUpload.js +12 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getQuery.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/auth/funcs/getQuery.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,wBAA8B,QAAQ,CAAC,EACrC,EAAE,EACF,IAAI,GACL,EAAE;IACD,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B,
|
|
1
|
+
{"version":3,"file":"getQuery.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/auth/funcs/getQuery.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,wBAA8B,QAAQ,CAAC,EACrC,EAAE,EACF,IAAI,GACL,EAAE;IACD,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B,gBAoIA"}
|
|
@@ -124,5 +124,5 @@ export default async function getQuery({ pg, data, }) {
|
|
|
124
124
|
.query(`select * from admin.users where uid =(select uid from admin.users_social_auth
|
|
125
125
|
where ${id ? "social_auth_id=$1" : "email=$1"} limit 1)`, [id || email])
|
|
126
126
|
.then((el) => el.rows?.[0] || {});
|
|
127
|
-
return result;
|
|
127
|
+
return { ...result, isNewUser: !(userId || socialUserId) };
|
|
128
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploadMultiPart.d.ts","sourceRoot":"","sources":["../../../../server/plugins/file/uploadMultiPart.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,KAAK;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA2CD,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAkBvE;AAED,wBAAsB,gBAAgB,CACpC,EACE,IAAI,EAAE,QAAQ,EACd,MAA2C,EAC3C,MAAM,GACP,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACpD,MAAM,MAAW,mBA+BlB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,GAAG,EACR,EACE,UAAU,EACV,GAAG,EACH,MAAM,EACN,gBAAwB,GACzB,GAAE;IACD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACvB,GACL,OAAO,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"uploadMultiPart.d.ts","sourceRoot":"","sources":["../../../../server/plugins/file/uploadMultiPart.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,KAAK;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA2CD,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,mBAkBvE;AAED,wBAAsB,gBAAgB,CACpC,EACE,IAAI,EAAE,QAAQ,EACd,MAA2C,EAC3C,MAAM,GACP,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACpD,MAAM,MAAW,mBA+BlB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,GAAG,EACR,EACE,UAAU,EACV,GAAG,EACH,MAAM,EACN,gBAAwB,GACzB,GAAE;IACD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACvB,GACL,OAAO,CAAC,KAAK,CAAC,CAwHhB;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -90,6 +90,10 @@ export async function uploadMultiPart(req, { extensions, raw, subdir, originalFi
|
|
|
90
90
|
if (extensions && !extensions.includes(ext)) {
|
|
91
91
|
throw new BadRequestError("file extension is not allowed");
|
|
92
92
|
}
|
|
93
|
+
const dir = subdir != null ? subdir : req.params?.["*"] || "uploads";
|
|
94
|
+
if (dir.replace(/%2e/g, ".").replace(/%2E/g, ".").includes("..")) {
|
|
95
|
+
throw new ConflictError("path traversal is not allowed");
|
|
96
|
+
}
|
|
93
97
|
// ! check extension by core list if custom not provided - from filename
|
|
94
98
|
if (!extensions && !allowedExtensions.includes(ext.substring(1))) {
|
|
95
99
|
throw new BadRequestError("file extension is not allowed");
|
|
@@ -119,7 +123,6 @@ export async function uploadMultiPart(req, { extensions, raw, subdir, originalFi
|
|
|
119
123
|
if (fileExtension !== nameExt) {
|
|
120
124
|
throw new ConflictError("file type spoofing attempt detected");
|
|
121
125
|
}
|
|
122
|
-
const dir = subdir != null ? subdir : req.params?.["*"] || "uploads";
|
|
123
126
|
const yearMonthDay = subdir != null ? "" : new Date().toISOString().split("T")[0];
|
|
124
127
|
const dbname = req.pg?.options?.database || req.pg?.database || config.pg?.database; // request / config params / default config params
|
|
125
128
|
const rootDir = config.root || `/data/local/${dbname || ""}`;
|
|
@@ -1 +1 @@
|
|
|
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,EAAE,GAAG,CAAC,EAAE,GAAG,
|
|
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,EAAE,GAAG,CAAC,EAAE,GAAG,QAkIlE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { config, logger } from "../../../../utils.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ForbiddenError } from "../../../../errors.js";
|
|
3
3
|
export default function checkPolicy(req, jwt) {
|
|
4
4
|
const { originalUrl: path, hostname, query, params, headers, method, routeOptions, } = req;
|
|
5
5
|
const user = req.user || req.session?.passport?.user;
|
|
@@ -12,7 +12,7 @@ export default function checkPolicy(req, jwt) {
|
|
|
12
12
|
hostname.startsWith("admin");
|
|
13
13
|
const { role, referer, policy = [], } = (routeOptions?.config || {});
|
|
14
14
|
// role=admin|regular
|
|
15
|
-
const isRole = (role && (!user?.user_type || !
|
|
15
|
+
const isRole = (role && (!user?.user_type || !user?.user_type?.includes?.(role))) ||
|
|
16
16
|
(policy.includes("admin") && !user?.user_type?.includes?.("admin"));
|
|
17
17
|
const allowExtPublic = [".png", ".jpg", ".svg"];
|
|
18
18
|
const ext = path.toLowerCase().substr(-4);
|
|
@@ -47,20 +47,6 @@ export default function checkPolicy(req, jwt) {
|
|
|
47
47
|
});
|
|
48
48
|
throw ForbiddenError("access restricted: 0");
|
|
49
49
|
}
|
|
50
|
-
// ! file injection
|
|
51
|
-
if (JSON.stringify(params || {})?.includes("../") ||
|
|
52
|
-
JSON.stringify(query || {})?.includes("../") ||
|
|
53
|
-
path?.includes("../")) {
|
|
54
|
-
logger.file("injection/file", {
|
|
55
|
-
path,
|
|
56
|
-
method,
|
|
57
|
-
params,
|
|
58
|
-
query,
|
|
59
|
-
body,
|
|
60
|
-
uid: user?.uid,
|
|
61
|
-
});
|
|
62
|
-
throw ConflictError("access restricted: 1");
|
|
63
|
-
}
|
|
64
50
|
// ! invalid file extension
|
|
65
51
|
if (path.includes("files/") && allowExtPublic.includes(ext)) {
|
|
66
52
|
return null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkTraversal.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/policy/funcs/checkTraversal.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,OAAO,EAAE,GAAG,QAgBlD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { logger } from "../../../../utils.js";
|
|
2
|
+
import { ConflictError } from "../../../../errors.js";
|
|
3
|
+
const decodeTraversal = (str) => str
|
|
4
|
+
.replace(/%2e/g, ".")
|
|
5
|
+
.replace(/%2E/g, ".")
|
|
6
|
+
.replace(/%2f/g, "/")
|
|
7
|
+
.replace(/%2F/g, "/");
|
|
8
|
+
export default function checkTraversal(request) {
|
|
9
|
+
const { method, originalUrl, query, params, user } = request;
|
|
10
|
+
if (decodeTraversal(JSON.stringify(params || {})).includes("../") ||
|
|
11
|
+
decodeTraversal(JSON.stringify(query || {})).includes("../") ||
|
|
12
|
+
decodeTraversal(originalUrl).includes("../")) {
|
|
13
|
+
logger.file("injection/file", {
|
|
14
|
+
path: originalUrl,
|
|
15
|
+
method,
|
|
16
|
+
params,
|
|
17
|
+
query,
|
|
18
|
+
uid: user?.uid,
|
|
19
|
+
});
|
|
20
|
+
throw ConflictError("path traversal detected");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/plugins/policy/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/plugins/policy/index.ts"],"names":[],"mappings":"AAOA,iBAAS,MAAM,CAAC,OAAO,EAAE,GAAG,QA+B3B;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import config from "../../../config.js";
|
|
2
2
|
import checkPolicy from "./funcs/checkPolicy.js";
|
|
3
|
+
import checkTraversal from "./funcs/checkTraversal.js";
|
|
3
4
|
import checkPermissions from "./funcs/checkPermissions.js";
|
|
4
5
|
import checkJWT from "./funcs/checkJWT.js";
|
|
5
6
|
function plugin(fastify) {
|
|
6
|
-
fastify.addHook("preHandler", async (request
|
|
7
|
+
fastify.addHook("preHandler", async (request) => {
|
|
8
|
+
checkTraversal(request);
|
|
7
9
|
// ! skip locally, skip tests
|
|
8
10
|
if ((process.env.local === "true" || process.env.NODE_ENV === "test") &&
|
|
9
11
|
!config.debugAuth &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startUpload.d.ts","sourceRoot":"","sources":["../../../../server/plugins/upload/startUpload.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"startUpload.d.ts","sourceRoot":"","sources":["../../../../server/plugins/upload/startUpload.ts"],"names":[],"mappings":"AAyBA,wBAA8B,WAAW,CAAC,EACxC,IAAI,EACJ,EAAE,EACF,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,gBAAwB,GACzB,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,gBA2GA"}
|
|
@@ -4,20 +4,29 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import config from "../../../config.js";
|
|
5
5
|
import getUploadStatus from "./getUploadStatus.js";
|
|
6
6
|
import { prefix, fileDir, metaDir, uploadChunkDirectory, fetchTimeoutMs, } from "./index.js";
|
|
7
|
+
import { all } from "../file/utils/allowedExtensions.js";
|
|
7
8
|
import mimes from "../file/providers/mime/mimes.js";
|
|
8
9
|
import { startUpload as startUploadS3 } from "./s3.js";
|
|
9
|
-
import { BadRequestError, NotImplementedError } from "../../../errors.js";
|
|
10
|
+
import { BadRequestError, ForbiddenError, NotImplementedError, } from "../../../errors.js";
|
|
10
11
|
const { chunkSize = 5242880 } = config;
|
|
11
12
|
export default async function startUpload({ host, id, fileName, size, subdir, originalFilename = false, }) {
|
|
12
|
-
if (subdir &&
|
|
13
|
+
if (subdir &&
|
|
14
|
+
(typeof subdir !== "string" ||
|
|
15
|
+
subdir.replace(/%2e/g, ".").replace(/%2E/g, ".").includes(".."))) {
|
|
13
16
|
throw BadRequestError("invalid params: subdir");
|
|
14
17
|
}
|
|
15
18
|
if (originalFilename) {
|
|
16
19
|
throw NotImplementedError("currently not supported");
|
|
17
20
|
}
|
|
21
|
+
if (!fileName) {
|
|
22
|
+
throw BadRequestError("not enough params: fileName");
|
|
23
|
+
}
|
|
24
|
+
const extension = path.extname(fileName).substring(1);
|
|
25
|
+
if (!all.includes(extension)) {
|
|
26
|
+
throw ForbiddenError("file extension is not allowed");
|
|
27
|
+
}
|
|
18
28
|
if (!host) {
|
|
19
29
|
const id1 = id || randomUUID();
|
|
20
|
-
const extension = path.extname(fileName).substring(1);
|
|
21
30
|
const yearMonthDay = subdir ? "" : new Date().toISOString().split("T")[0];
|
|
22
31
|
const relativeDirpath = path
|
|
23
32
|
.join(uploadChunkDirectory, subdir || "", yearMonthDay || "")
|