Spaces:
Sleeping
Sleeping
Commit ·
210d827
1
Parent(s): 3ad0250
System Stability Patch: Fix trust proxy, chainable NeDB models, absolute upload paths, and sentinel stack safety
Browse files- backend/models/Announcement.js +7 -2
- backend/models/ChatSession.js +23 -8
- backend/models/Message.js +3 -0
- backend/routes/ai.js +3 -1
- backend/server.js +3 -0
- backend/services/sentinelService.js +5 -1
backend/models/Announcement.js
CHANGED
|
@@ -2,7 +2,8 @@ const { db } = require('../db');
|
|
| 2 |
|
| 3 |
class Announcement {
|
| 4 |
static findOne(query) {
|
| 5 |
-
|
|
|
|
| 6 |
sort: function(sortQuery) {
|
| 7 |
this._sort = sortQuery;
|
| 8 |
return this;
|
|
@@ -16,8 +17,12 @@ class Announcement {
|
|
| 16 |
else res(docs[0] || null);
|
| 17 |
});
|
| 18 |
}).then(resolve, reject);
|
|
|
|
|
|
|
|
|
|
| 19 |
}
|
| 20 |
};
|
|
|
|
| 21 |
}
|
| 22 |
|
| 23 |
static async create(annData) {
|
|
@@ -31,4 +36,4 @@ class Announcement {
|
|
| 31 |
}
|
| 32 |
}
|
| 33 |
|
| 34 |
-
module.exports = Announcement;
|
|
|
|
| 2 |
|
| 3 |
class Announcement {
|
| 4 |
static findOne(query) {
|
| 5 |
+
const chain = {
|
| 6 |
+
_sort: null,
|
| 7 |
sort: function(sortQuery) {
|
| 8 |
this._sort = sortQuery;
|
| 9 |
return this;
|
|
|
|
| 17 |
else res(docs[0] || null);
|
| 18 |
});
|
| 19 |
}).then(resolve, reject);
|
| 20 |
+
},
|
| 21 |
+
catch: function(reject) {
|
| 22 |
+
return this.then(null, reject);
|
| 23 |
}
|
| 24 |
};
|
| 25 |
+
return chain;
|
| 26 |
}
|
| 27 |
|
| 28 |
static async create(annData) {
|
|
|
|
| 36 |
}
|
| 37 |
}
|
| 38 |
|
| 39 |
+
module.exports = Announcement;
|
backend/models/ChatSession.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
| 1 |
const { db } = require('../db');
|
| 2 |
|
| 3 |
class ChatSession {
|
| 4 |
-
static
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
}
|
| 12 |
|
| 13 |
static async findById(id) {
|
|
@@ -40,4 +55,4 @@ class ChatSession {
|
|
| 40 |
}
|
| 41 |
}
|
| 42 |
|
| 43 |
-
module.exports = ChatSession;
|
|
|
|
| 1 |
const { db } = require('../db');
|
| 2 |
|
| 3 |
class ChatSession {
|
| 4 |
+
static find(query) {
|
| 5 |
+
const chain = {
|
| 6 |
+
_sort: null,
|
| 7 |
+
sort: function(sortQuery) {
|
| 8 |
+
this._sort = sortQuery;
|
| 9 |
+
return this;
|
| 10 |
+
},
|
| 11 |
+
then: function(resolve, reject) {
|
| 12 |
+
return new Promise((res, rej) => {
|
| 13 |
+
let q = db.sessions.find(query);
|
| 14 |
+
if (this._sort) q = q.sort(this._sort);
|
| 15 |
+
q.exec((err, docs) => {
|
| 16 |
+
if (err) rej(err);
|
| 17 |
+
else res(docs);
|
| 18 |
+
});
|
| 19 |
+
}).then(resolve, reject);
|
| 20 |
+
},
|
| 21 |
+
catch: function(reject) {
|
| 22 |
+
return this.then(null, reject);
|
| 23 |
+
}
|
| 24 |
+
};
|
| 25 |
+
return chain;
|
| 26 |
}
|
| 27 |
|
| 28 |
static async findById(id) {
|
|
|
|
| 55 |
}
|
| 56 |
}
|
| 57 |
|
| 58 |
+
module.exports = ChatSession;
|
backend/models/Message.js
CHANGED
|
@@ -21,6 +21,9 @@ class Message {
|
|
| 21 |
else res(docs);
|
| 22 |
});
|
| 23 |
}).then(resolve, reject);
|
|
|
|
|
|
|
|
|
|
| 24 |
}
|
| 25 |
};
|
| 26 |
return chain;
|
|
|
|
| 21 |
else res(docs);
|
| 22 |
});
|
| 23 |
}).then(resolve, reject);
|
| 24 |
+
},
|
| 25 |
+
catch: function(reject) {
|
| 26 |
+
return this.then(null, reject);
|
| 27 |
}
|
| 28 |
};
|
| 29 |
return chain;
|
backend/routes/ai.js
CHANGED
|
@@ -9,7 +9,9 @@ const router = express.Router();
|
|
| 9 |
// Setup Multer for file uploads
|
| 10 |
const storage = multer.diskStorage({
|
| 11 |
destination: function (req, file, cb) {
|
| 12 |
-
|
|
|
|
|
|
|
| 13 |
},
|
| 14 |
filename: function (req, file, cb) {
|
| 15 |
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
|
|
|
|
| 9 |
// Setup Multer for file uploads
|
| 10 |
const storage = multer.diskStorage({
|
| 11 |
destination: function (req, file, cb) {
|
| 12 |
+
const uploadPath = path.join(__dirname, '../uploads');
|
| 13 |
+
if (!fs.existsSync(uploadPath)) fs.mkdirSync(uploadPath, { recursive: true });
|
| 14 |
+
cb(null, uploadPath)
|
| 15 |
},
|
| 16 |
filename: function (req, file, cb) {
|
| 17 |
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
|
backend/server.js
CHANGED
|
@@ -38,6 +38,9 @@ const users = require('./routes/users');
|
|
| 38 |
|
| 39 |
const app = express();
|
| 40 |
|
|
|
|
|
|
|
|
|
|
| 41 |
// --- SENTINEL PRIORITY INTERCEPTOR ---
|
| 42 |
app.use((req, res, next) => {
|
| 43 |
const originalSend = res.send;
|
|
|
|
| 38 |
|
| 39 |
const app = express();
|
| 40 |
|
| 41 |
+
// Trust first proxy (Hugging Face / Cloudflare)
|
| 42 |
+
app.set('trust proxy', 1);
|
| 43 |
+
|
| 44 |
// --- SENTINEL PRIORITY INTERCEPTOR ---
|
| 45 |
app.use((req, res, next) => {
|
| 46 |
const originalSend = res.send;
|
backend/services/sentinelService.js
CHANGED
|
@@ -61,7 +61,11 @@ exports.performSurgery = async (errorStack, originalUrl) => {
|
|
| 61 |
addLog(`Breach detected in Node: ${originalUrl}`, "error");
|
| 62 |
|
| 63 |
// Identify the likely file from the error stack
|
| 64 |
-
const stackLines = errorStack.split('\n');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
const fileMatch = stackLines[1].match(/at (.*):(\d+):(\d+)/) || stackLines[1].match(/\((.*):(\d+):(\d+)\)/);
|
| 66 |
|
| 67 |
if (!fileMatch) {
|
|
|
|
| 61 |
addLog(`Breach detected in Node: ${originalUrl}`, "error");
|
| 62 |
|
| 63 |
// Identify the likely file from the error stack
|
| 64 |
+
const stackLines = errorStack ? errorStack.split('\n') : [];
|
| 65 |
+
if (stackLines.length < 2) {
|
| 66 |
+
addLog("Stack trace too short to identify faulty module.", "warning");
|
| 67 |
+
return;
|
| 68 |
+
}
|
| 69 |
const fileMatch = stackLines[1].match(/at (.*):(\d+):(\d+)/) || stackLines[1].match(/\((.*):(\d+):(\d+)\)/);
|
| 70 |
|
| 71 |
if (!fileMatch) {
|