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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "godprotocol",
3
- "version": "2.3.29",
3
+ "version": "2.3.31",
4
4
  "description": "A distributed computing environment for Web 4.0 — integrating AI, decentralisation, and virtual computation.",
5
5
  "main": "Index.js",
6
6
  "type": "module",
@@ -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) return;
163
+ if (!version) {
164
+ let vers = Object.keys(this.versions);
163
165
 
164
- return await this.platform_db();
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({ headers: req.headers });
40
+ const busboy = Busboy({
41
+ headers: req.headers,
42
+ });
8
43
 
9
44
  const fields = {};
10
- let filePath = null;
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("finish", () => {
30
- resolve({
31
- ...fields,
32
- file_path: filePath,
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
- let filePath = decodeURIComponent(parsedUrl.pathname);
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
- // prevent path traversal attacks
11
- filePath = filePath.replace(/\.\./g, "");
37
+ // Normalize path
38
+ relativePath = path.normalize(relativePath);
12
39
 
13
- const fullPath = path.join(process.cwd(), filePath);
14
- console.log(fullPath);
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
- const stream = fs.createReadStream(fullPath);
72
+ // Must be a file
73
+ const stat = fs.statSync(fullPath);
27
74
 
28
- // basic content type handling
29
- const ext = path.extname(fullPath);
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 mimeTypes = {
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("Content-Type", mimeTypes[ext] || "application/octet-stream");
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.gp.compute_response(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
- const result = await router.execute(name, {
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 !== "*") {