@tiledesk/tiledesk-server 2.14.18 → 2.14.20
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/CHANGELOG.md +4 -0
- package/app.js +2 -0
- package/middleware/file-type.js +50 -0
- package/models/analyticResult.js +1 -3
- package/package.json +3 -2
- package/routes/files.js +75 -18
- package/routes/filesp.js +545 -0
- package/routes/llm.js +1 -1
- package/services/fileGridFsService.js +195 -6
- package/test/fileFilter.test.js +194 -0
- package/test/filepRoute.js +561 -0
- package/test/fixtures/avatar.jpg +0 -0
- package/test/fixtures/fake.pdf +8 -0
- package/test/fixtures/sample.xyz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
|
7
7
|
|
|
8
|
+
# 2.14.20
|
|
9
|
+
- Updated whatsapp-connector to 1.0.19
|
|
10
|
+
- Added new endpoint for files uploading
|
|
11
|
+
|
|
8
12
|
# 2.14.18
|
|
9
13
|
- Bug fix already existing email when login from google
|
|
10
14
|
|
package/app.js
CHANGED
|
@@ -139,6 +139,7 @@ var cacheUtil = require("./utils/cacheUtil");
|
|
|
139
139
|
var orgUtil = require("./utils/orgUtil");
|
|
140
140
|
var images = require('./routes/images');
|
|
141
141
|
var files = require('./routes/files');
|
|
142
|
+
let filesp = require('./routes/filesp');
|
|
142
143
|
var campaigns = require('./routes/campaigns');
|
|
143
144
|
var logs = require('./routes/logs');
|
|
144
145
|
var requestUtilRoot = require('./routes/requestUtilRoot');
|
|
@@ -645,6 +646,7 @@ app.use('/:projectid/logs', [passport.authenticate(['basic', 'jwt'], { session:
|
|
|
645
646
|
app.use('/:projectid/webhooks', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('admin')], webhooks);
|
|
646
647
|
app.use('/:projectid/copilot', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], copilot);
|
|
647
648
|
|
|
649
|
+
app.use('/:projectid/files', filesp);
|
|
648
650
|
|
|
649
651
|
if (pubModulesManager) {
|
|
650
652
|
pubModulesManager.useUnderProjects(app);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const FileType = require('file-type');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
// List of text-based MIME types that FileType cannot detect (they don't have binary signatures)
|
|
5
|
+
const TEXT_MIME_TYPES = [
|
|
6
|
+
'text/plain',
|
|
7
|
+
'text/csv'
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
async function verifyFileContent(buffer, mimetype) {
|
|
11
|
+
if (!buffer) throw new Error("No file provided");
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const fileType = await FileType.fromBuffer(buffer);
|
|
15
|
+
|
|
16
|
+
// If FileType couldn't detect the file type (returns null/undefined)
|
|
17
|
+
if (!fileType) {
|
|
18
|
+
// For text-based MIME types, accept the declared mimetype since FileType can't detect them
|
|
19
|
+
if (mimetype && TEXT_MIME_TYPES.includes(mimetype)) {
|
|
20
|
+
// Optionally verify that the content is valid UTF-8 text
|
|
21
|
+
try {
|
|
22
|
+
buffer.toString('utf8');
|
|
23
|
+
return true;
|
|
24
|
+
} catch (e) {
|
|
25
|
+
const err = new Error(`File content is not valid text for mimetype: ${mimetype}`);
|
|
26
|
+
err.source = "FileContentVerification";
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
// For non-text files, FileType should be able to detect them
|
|
31
|
+
const err = new Error(`File content does not match mimetype. Detected: unknown, provided: ${mimetype}`);
|
|
32
|
+
err.source = "FileContentVerification";
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If FileType detected a type, it must match the declared mimetype
|
|
38
|
+
if (mimetype && fileType.mime !== mimetype) {
|
|
39
|
+
const err = new Error(`File content does not match mimetype. Detected: ${fileType.mime}, provided: ${mimetype}`);
|
|
40
|
+
err.source = "FileContentVerification";
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return true;
|
|
45
|
+
} catch (err) {
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = verifyFileContent;
|
package/models/analyticResult.js
CHANGED
|
@@ -2,16 +2,14 @@ var mongoose = require('mongoose');
|
|
|
2
2
|
var Schema = mongoose.Schema;
|
|
3
3
|
// mongoose.set('debug', true);
|
|
4
4
|
var winston = require('../config/winston');
|
|
5
|
-
|
|
6
5
|
let config = require('../config/database');
|
|
7
6
|
|
|
8
|
-
|
|
9
7
|
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI || config.database;
|
|
10
8
|
|
|
11
9
|
var readPreference = process.env.ANALYTICS_READ_PREFERENCE || "primary";
|
|
12
10
|
winston.info("Annalytics readPreference: " + readPreference);
|
|
13
11
|
|
|
14
|
-
var conn
|
|
12
|
+
var conn = mongoose.createConnection(databaseUri, { "autoIndex": true, readPreference: readPreference});
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
var AnalyticResultSchema = new Schema({
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiledesk/tiledesk-server",
|
|
3
3
|
"description": "The Tiledesk server module",
|
|
4
|
-
"version": "2.14.
|
|
4
|
+
"version": "2.14.20",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"start": "node ./bin/www",
|
|
7
7
|
"pretest": "mongodb-runner start",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@tiledesk/tiledesk-tybot-connector": "^2.0.43",
|
|
53
53
|
"@tiledesk/tiledesk-voice-twilio-connector": "^0.1.28",
|
|
54
54
|
"@tiledesk/tiledesk-vxml-connector": "^0.1.89",
|
|
55
|
-
"@tiledesk/tiledesk-whatsapp-connector": "1.0.
|
|
55
|
+
"@tiledesk/tiledesk-whatsapp-connector": "1.0.19",
|
|
56
56
|
"@tiledesk/tiledesk-whatsapp-jobworker": "^0.0.13",
|
|
57
57
|
"amqplib": "^0.5.5",
|
|
58
58
|
"app-root-path": "^3.0.0",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"express-session": "^1.17.3",
|
|
75
75
|
"express-validator": "^6.14.2",
|
|
76
76
|
"fast-csv": "^4.3.6",
|
|
77
|
+
"file-type": "^14.7.1",
|
|
77
78
|
"geoip-lite": "^1.4.5",
|
|
78
79
|
"handlebars": "^4.7.7",
|
|
79
80
|
"handlebars-dateformat": "^1.1.3",
|
package/routes/files.js
CHANGED
|
@@ -15,6 +15,7 @@ const FileGridFsService = require('../services/fileGridFsService.js');
|
|
|
15
15
|
const { path } = require('../models/tag');
|
|
16
16
|
|
|
17
17
|
const fileService = new FileGridFsService("files");
|
|
18
|
+
const fallbackFileService = new FileGridFsService("images");
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
|
|
@@ -67,33 +68,89 @@ router.post('/public', upload.single('file'), (req, res, next) => {
|
|
|
67
68
|
|
|
68
69
|
|
|
69
70
|
|
|
70
|
-
router.get("/", (req, res) => {
|
|
71
|
+
router.get("/", async (req, res) => {
|
|
71
72
|
winston.debug('path', req.query.path);
|
|
72
|
-
|
|
73
|
-
fileService
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
|
|
74
|
+
let fService = fileService;
|
|
75
|
+
try {
|
|
76
|
+
let file = await fileService.find(req.query.path);
|
|
77
|
+
res.set({ "Content-Length": file.length});
|
|
78
|
+
res.set({ "Content-Type": file.contentType});
|
|
79
|
+
} catch (e) {
|
|
80
|
+
if (e.code == "ENOENT") {
|
|
81
|
+
winston.debug(`File ${req.query.path} not found on primary file service. Fallback to secondary.`)
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
let file = await fallbackFileService.find(req.query.path)
|
|
85
|
+
res.set({ "Content-Length": file.length });
|
|
86
|
+
res.set({ "Content-Type": file.contentType });
|
|
87
|
+
fService = fallbackFileService;
|
|
88
|
+
} catch (e) {
|
|
89
|
+
if (e.code == "ENOENT") {
|
|
90
|
+
winston.debug(`File ${req.query.path} not found on secondary file service.`)
|
|
91
|
+
return res.status(404).send({ success: false, error: 'File not found.' });
|
|
92
|
+
} else {
|
|
93
|
+
winston.error('Error getting file: ', e);
|
|
94
|
+
return res.status(500).send({success: false, error: 'Error getting file.'});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
winston.error('Error getting file', e);
|
|
99
|
+
return res.status(500).send({success: false, error: 'Error getting file.'});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fService.getFileDataAsStream(req.query.path).on('error', (e)=> {
|
|
104
|
+
if (e.code == "ENOENT") {
|
|
105
|
+
winston.debug('File not found: '+req.query.path);
|
|
106
|
+
return res.status(404).send({success: false, error: 'File not found.'});
|
|
107
|
+
} else {
|
|
108
|
+
winston.error('Error getting the file', e);
|
|
109
|
+
return res.status(500).send({success: false, error: 'Error getting file.'});
|
|
110
|
+
}
|
|
111
|
+
}).pipe(res);
|
|
86
112
|
});
|
|
87
113
|
|
|
88
114
|
|
|
89
|
-
router.get("/download", (req, res) => {
|
|
115
|
+
router.get("/download", async (req, res) => {
|
|
90
116
|
winston.debug('path', req.query.path);
|
|
91
|
-
// if (path.indexOf("/users/"))
|
|
92
117
|
let filename = pathlib.basename(req.query.path);
|
|
93
118
|
winston.debug("filename:"+filename);
|
|
94
119
|
|
|
120
|
+
let fService = fileService;
|
|
121
|
+
try {
|
|
122
|
+
await fileService.find(req.query.path);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
if (e.code == "ENOENT") {
|
|
125
|
+
winston.debug(`File ${req.query.path} not found on primary file service. Fallback to secondary.`)
|
|
126
|
+
try {
|
|
127
|
+
await fallbackFileService.find(req.query.path);
|
|
128
|
+
fService = fallbackFileService;
|
|
129
|
+
} catch (e) {
|
|
130
|
+
if (e.code == "ENOENT") {
|
|
131
|
+
winston.debug(`File ${req.query.path} not found on secondary file service.`)
|
|
132
|
+
return res.status(404).send({ success: false, error: 'File not found.' });
|
|
133
|
+
} else {
|
|
134
|
+
winston.error('Error getting file: ', e);
|
|
135
|
+
return res.status(500).send({success: false, error: 'Error getting file.'});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
winston.error('Error getting file', e);
|
|
140
|
+
return res.status(500).send({success: false, error: 'Error getting file.'});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
95
144
|
res.attachment(filename);
|
|
96
|
-
|
|
145
|
+
fService.getFileDataAsStream(req.query.path).on('error', (e)=> {
|
|
146
|
+
if (e.code == "ENOENT") {
|
|
147
|
+
winston.debug('File not found: '+req.query.path);
|
|
148
|
+
return res.status(404).send({success: false, error: 'File not found.'});
|
|
149
|
+
} else {
|
|
150
|
+
winston.error('Error getting the file', e);
|
|
151
|
+
return res.status(500).send({success: false, error: 'Error getting file.'});
|
|
152
|
+
}
|
|
153
|
+
}).pipe(res);
|
|
97
154
|
});
|
|
98
155
|
|
|
99
156
|
|