godprotocol 2.3.29 → 2.3.31
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/package.json
CHANGED
|
@@ -158,10 +158,28 @@ class Services {
|
|
|
158
158
|
};
|
|
159
159
|
|
|
160
160
|
version_db = async (ver) => {
|
|
161
|
+
let curr_ver = this.active_version;
|
|
161
162
|
let version = await this.get_version(ver);
|
|
162
|
-
if (!version)
|
|
163
|
+
if (!version) {
|
|
164
|
+
let vers = Object.keys(this.versions);
|
|
163
165
|
|
|
164
|
-
|
|
166
|
+
for (let v = 0; v < vers.length; v++) {
|
|
167
|
+
let vrr = vers[v];
|
|
168
|
+
|
|
169
|
+
if (vrr.startsWith(`${ver}:`)) {
|
|
170
|
+
version = this.get_version(vrr);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (!version) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let db = await this.platform_db();
|
|
179
|
+
|
|
180
|
+
this.get_version(curr_ver);
|
|
181
|
+
|
|
182
|
+
return db;
|
|
165
183
|
};
|
|
166
184
|
|
|
167
185
|
platform_db = async (name) => {
|
|
@@ -1,36 +1,134 @@
|
|
|
1
1
|
import Busboy from "busboy";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import crypto from "crypto";
|
|
5
|
+
|
|
6
|
+
const allowedExtensions = new Set([
|
|
7
|
+
".jpg",
|
|
8
|
+
".jpeg",
|
|
9
|
+
".png",
|
|
10
|
+
".gif",
|
|
11
|
+
".webp",
|
|
12
|
+
".pdf",
|
|
13
|
+
".doc",
|
|
14
|
+
".docx",
|
|
15
|
+
".xls",
|
|
16
|
+
".xlsx",
|
|
17
|
+
".csv",
|
|
18
|
+
".txt",
|
|
19
|
+
".zip",
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const allowedMimeTypes = new Set([
|
|
23
|
+
"image/jpeg",
|
|
24
|
+
"image/png",
|
|
25
|
+
"image/gif",
|
|
26
|
+
"image/webp",
|
|
27
|
+
"application/pdf",
|
|
28
|
+
"application/msword",
|
|
29
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
30
|
+
"application/vnd.ms-excel",
|
|
31
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
32
|
+
"text/plain",
|
|
33
|
+
"text/csv",
|
|
34
|
+
"application/zip",
|
|
35
|
+
"application/x-zip-compressed",
|
|
36
|
+
]);
|
|
4
37
|
|
|
5
38
|
const parseMultipart = (req, gp) => {
|
|
6
39
|
return new Promise((resolve, reject) => {
|
|
7
|
-
const busboy = Busboy({
|
|
40
|
+
const busboy = Busboy({
|
|
41
|
+
headers: req.headers,
|
|
42
|
+
});
|
|
8
43
|
|
|
9
44
|
const fields = {};
|
|
10
|
-
|
|
45
|
+
const files = {};
|
|
46
|
+
const writes = [];
|
|
47
|
+
|
|
48
|
+
const uploadDir = `.${gp.static_path}/uploads`;
|
|
11
49
|
|
|
12
|
-
const uploadDir = `./${gp.static_path.slice(1)}/uploads`;
|
|
13
50
|
if (!fs.existsSync(uploadDir)) {
|
|
14
51
|
fs.mkdirSync(uploadDir, { recursive: true });
|
|
15
52
|
}
|
|
16
53
|
|
|
17
|
-
busboy.on("file", (name, file, info) => {
|
|
18
|
-
const filename = `${Date.now()}-${info.filename}`;
|
|
19
|
-
filePath = path.join(uploadDir, filename);
|
|
20
|
-
|
|
21
|
-
const stream = fs.createWriteStream(filePath);
|
|
22
|
-
file.pipe(stream);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
54
|
busboy.on("field", (name, value) => {
|
|
26
55
|
fields[name] = value;
|
|
27
56
|
});
|
|
28
57
|
|
|
29
|
-
busboy.on("
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
58
|
+
busboy.on("file", (fieldName, file, info) => {
|
|
59
|
+
// -----------------------------
|
|
60
|
+
// Sanitise client filename
|
|
61
|
+
// -----------------------------
|
|
62
|
+
const originalName = path.basename(info.filename || "");
|
|
63
|
+
|
|
64
|
+
const extension = path.extname(originalName).toLowerCase();
|
|
65
|
+
|
|
66
|
+
if (
|
|
67
|
+
!allowedExtensions.has(extension) ||
|
|
68
|
+
!allowedMimeTypes.has(info.mimeType)
|
|
69
|
+
) {
|
|
70
|
+
file.resume();
|
|
71
|
+
|
|
72
|
+
return reject(
|
|
73
|
+
new Error(`Unsupported file type (${extension}, ${info.mimeType})`),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// -----------------------------
|
|
78
|
+
// Generate safe filename
|
|
79
|
+
// -----------------------------
|
|
80
|
+
const filename = `${Date.now()}-${crypto.randomUUID()}${extension}`;
|
|
81
|
+
|
|
82
|
+
const filepath = path.join(uploadDir, filename);
|
|
83
|
+
|
|
84
|
+
const stream = fs.createWriteStream(filepath);
|
|
85
|
+
|
|
86
|
+
let size = 0;
|
|
87
|
+
|
|
88
|
+
file.on("data", (chunk) => {
|
|
89
|
+
size += chunk.length;
|
|
33
90
|
});
|
|
91
|
+
|
|
92
|
+
const write = new Promise((resolveWrite, rejectWrite) => {
|
|
93
|
+
stream.on("finish", resolveWrite);
|
|
94
|
+
|
|
95
|
+
stream.on("error", rejectWrite);
|
|
96
|
+
|
|
97
|
+
file.on("error", rejectWrite);
|
|
98
|
+
|
|
99
|
+
file.pipe(stream);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
writes.push(write);
|
|
103
|
+
|
|
104
|
+
if (!files[fieldName]) {
|
|
105
|
+
files[fieldName] = [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
files[fieldName].push({
|
|
109
|
+
field: fieldName,
|
|
110
|
+
original_name: originalName,
|
|
111
|
+
filename,
|
|
112
|
+
mime_type: info.mimeType,
|
|
113
|
+
encoding: info.encoding,
|
|
114
|
+
extension,
|
|
115
|
+
size,
|
|
116
|
+
path: filepath,
|
|
117
|
+
url: `${gp.static_path}/uploads/${filename}`,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
busboy.on("finish", async () => {
|
|
122
|
+
try {
|
|
123
|
+
await Promise.all(writes);
|
|
124
|
+
|
|
125
|
+
resolve({
|
|
126
|
+
...fields,
|
|
127
|
+
files,
|
|
128
|
+
});
|
|
129
|
+
} catch (err) {
|
|
130
|
+
reject(err);
|
|
131
|
+
}
|
|
34
132
|
});
|
|
35
133
|
|
|
36
134
|
busboy.on("error", reject);
|
|
@@ -1,20 +1,66 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
|
|
4
|
+
const MIME_TYPES = {
|
|
5
|
+
".pdf": "application/pdf",
|
|
6
|
+
".docx":
|
|
7
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
8
|
+
".json": "application/json",
|
|
9
|
+
".txt": "text/plain",
|
|
10
|
+
".png": "image/png",
|
|
11
|
+
".jpg": "image/jpeg",
|
|
12
|
+
".jpeg": "image/jpeg",
|
|
13
|
+
".gif": "image/gif",
|
|
14
|
+
".svg": "image/svg+xml",
|
|
15
|
+
".webp": "image/webp",
|
|
16
|
+
".css": "text/css",
|
|
17
|
+
".js": "application/javascript",
|
|
18
|
+
".html": "text/html",
|
|
19
|
+
};
|
|
20
|
+
|
|
4
21
|
const serveStaticFile = (req, res) => {
|
|
5
22
|
try {
|
|
6
23
|
const parsedUrl = new URL(req.url, `http://${req.headers.host}`);
|
|
7
24
|
|
|
8
|
-
|
|
25
|
+
// Root static directory
|
|
26
|
+
const staticRoot = path.resolve(process.cwd(), `.${res.gp.static_path}`);
|
|
27
|
+
|
|
28
|
+
// Remove "/static" (or whatever your static path is)
|
|
29
|
+
let relativePath = parsedUrl.pathname.replace(res.gp.static_path, "");
|
|
30
|
+
|
|
31
|
+
// Decode URI
|
|
32
|
+
relativePath = decodeURIComponent(relativePath);
|
|
33
|
+
|
|
34
|
+
// Remove leading slashes
|
|
35
|
+
relativePath = relativePath.replace(/^[/\\]+/, "");
|
|
9
36
|
|
|
10
|
-
//
|
|
11
|
-
|
|
37
|
+
// Normalize path
|
|
38
|
+
relativePath = path.normalize(relativePath);
|
|
12
39
|
|
|
13
|
-
|
|
14
|
-
|
|
40
|
+
// Resolve final file
|
|
41
|
+
const fullPath = path.resolve(staticRoot, relativePath);
|
|
42
|
+
|
|
43
|
+
// Prevent path traversal
|
|
44
|
+
if (
|
|
45
|
+
!fullPath.startsWith(staticRoot + path.sep) &&
|
|
46
|
+
fullPath !== staticRoot
|
|
47
|
+
) {
|
|
48
|
+
res.statusCode = 403;
|
|
49
|
+
res.setHeader("Content-Type", "application/json");
|
|
50
|
+
|
|
51
|
+
return res.end(
|
|
52
|
+
JSON.stringify({
|
|
53
|
+
ok: false,
|
|
54
|
+
message: "Access denied",
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Must exist
|
|
15
60
|
if (!fs.existsSync(fullPath)) {
|
|
16
61
|
res.statusCode = 404;
|
|
17
62
|
res.setHeader("Content-Type", "application/json");
|
|
63
|
+
|
|
18
64
|
return res.end(
|
|
19
65
|
JSON.stringify({
|
|
20
66
|
ok: false,
|
|
@@ -23,30 +69,52 @@ const serveStaticFile = (req, res) => {
|
|
|
23
69
|
);
|
|
24
70
|
}
|
|
25
71
|
|
|
26
|
-
|
|
72
|
+
// Must be a file
|
|
73
|
+
const stat = fs.statSync(fullPath);
|
|
27
74
|
|
|
28
|
-
|
|
29
|
-
|
|
75
|
+
if (!stat.isFile()) {
|
|
76
|
+
res.statusCode = 404;
|
|
77
|
+
res.setHeader("Content-Type", "application/json");
|
|
78
|
+
|
|
79
|
+
return res.end(
|
|
80
|
+
JSON.stringify({
|
|
81
|
+
ok: false,
|
|
82
|
+
message: "File not found",
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
30
86
|
|
|
31
|
-
const
|
|
32
|
-
".pdf": "application/pdf",
|
|
33
|
-
".docx":
|
|
34
|
-
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
35
|
-
".json": "application/json",
|
|
36
|
-
".txt": "text/plain",
|
|
37
|
-
};
|
|
87
|
+
const ext = path.extname(fullPath).toLowerCase();
|
|
38
88
|
|
|
39
89
|
res.statusCode = 200;
|
|
40
|
-
res.setHeader(
|
|
90
|
+
res.setHeader(
|
|
91
|
+
"Content-Type",
|
|
92
|
+
MIME_TYPES[ext] || "application/octet-stream",
|
|
93
|
+
);
|
|
94
|
+
res.setHeader("Content-Length", stat.size);
|
|
95
|
+
|
|
96
|
+
const stream = fs.createReadStream(fullPath);
|
|
97
|
+
|
|
98
|
+
stream.on("error", () => {
|
|
99
|
+
if (!res.headersSent) {
|
|
100
|
+
res.statusCode = 500;
|
|
101
|
+
res.end();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
41
104
|
|
|
42
105
|
stream.pipe(res);
|
|
43
106
|
|
|
44
|
-
res.
|
|
107
|
+
res.on("finish", () => {
|
|
108
|
+
res.gp?.resource?.compute_response(res);
|
|
109
|
+
});
|
|
110
|
+
|
|
45
111
|
return true;
|
|
46
112
|
} catch (err) {
|
|
47
113
|
console.error("Static file error:", err);
|
|
48
114
|
|
|
49
115
|
res.statusCode = 500;
|
|
116
|
+
res.setHeader("Content-Type", "application/json");
|
|
117
|
+
|
|
50
118
|
res.end(
|
|
51
119
|
JSON.stringify({
|
|
52
120
|
ok: false,
|
|
@@ -117,14 +117,16 @@ const version_middleware = async (req, res, routers) => {
|
|
|
117
117
|
res.request_id = req.request_id;
|
|
118
118
|
|
|
119
119
|
// STATIC ROUTE DETECTION
|
|
120
|
-
if (routers.static_path && pathname.startsWith(routers.static_path)) {
|
|
121
|
-
return serveStaticFile(req, res);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
120
|
let version;
|
|
125
121
|
|
|
126
122
|
const versionMatch = pathname.match(/^\/api\/(v\d+)(\/|$)/i);
|
|
127
123
|
if (req.method === "GET") {
|
|
124
|
+
if (routers.static_path && pathname.startsWith(routers.static_path)) {
|
|
125
|
+
res.gp = routers.gp;
|
|
126
|
+
|
|
127
|
+
return serveStaticFile(req, res);
|
|
128
|
+
}
|
|
129
|
+
|
|
128
130
|
version = "__GET__";
|
|
129
131
|
} else if (versionMatch) {
|
|
130
132
|
version = versionMatch[1];
|
|
@@ -225,7 +227,7 @@ const version_middleware = async (req, res, routers) => {
|
|
|
225
227
|
|
|
226
228
|
// EXECUTE
|
|
227
229
|
error_stage = "Handler";
|
|
228
|
-
|
|
230
|
+
let payload = {
|
|
229
231
|
body,
|
|
230
232
|
route: name,
|
|
231
233
|
headers: req.headers,
|
|
@@ -234,7 +236,8 @@ const version_middleware = async (req, res, routers) => {
|
|
|
234
236
|
services: router.get_service,
|
|
235
237
|
method: req.method,
|
|
236
238
|
memory: router.gp.memory,
|
|
237
|
-
}
|
|
239
|
+
};
|
|
240
|
+
const result = await router.execute(name, payload);
|
|
238
241
|
|
|
239
242
|
// WEBHOOK AFTER
|
|
240
243
|
if (!isWebhook && version !== "*") {
|