@tiledesk/tiledesk-server 2.10.2 → 2.10.4

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 CHANGED
@@ -5,6 +5,14 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.10.4
9
+ - Removed temporary conversation from default query to get all requests
10
+ - Removed draft conversation from requests count
11
+ - Improved security
12
+
13
+ # 2.10.3
14
+ - Added support for formatType in openai completions
15
+
8
16
  # 2.10.2
9
17
  - Updated tybot-connector to 0.2.113
10
18
 
package/app.js CHANGED
@@ -558,8 +558,8 @@ app.use('/:projectid/intents', [passport.authenticate(['basic', 'jwt'], { sessio
558
558
  app.use('/:projectid/faqpub', faqpub);
559
559
 
560
560
  //deprecated
561
- app.use('/:projectid/faq_kb', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], faq_kb);
562
- app.use('/:projectid/bots', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], faq_kb);
561
+ app.use('/:projectid/faq_kb', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken], faq_kb);
562
+ app.use('/:projectid/bots', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken], faq_kb);
563
563
 
564
564
 
565
565
 
@@ -603,7 +603,7 @@ app.use('/:projectid/segments',[passport.authenticate(['basic', 'jwt'], { sessio
603
603
  app.use('/:projectid/openai', openai);
604
604
  app.use('/:projectid/quotes', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], quotes)
605
605
 
606
- app.use('/:projectid/integration', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], integration )
606
+ app.use('/:projectid/integration', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], integration )
607
607
 
608
608
  app.use('/:projectid/kbsettings', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('agent', ['bot','subscription'])], kbsettings);
609
609
  app.use('/:projectid/kb', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRoleOrTypes('admin', ['bot','subscription'])], kb);
package/errorCodes.js ADDED
@@ -0,0 +1,32 @@
1
+ const errorCodes = {
2
+ AUTH: {
3
+ BASE_CODE: 10000,
4
+ ERRORS: {
5
+ USER_NOT_FOUND: 10001,
6
+ //AUTH_FAILED: 10002,
7
+ //PERMISSION_DENIED: 10003,
8
+ MISSING_VERIFICATION_CODE: 10004,
9
+ VERIFICATION_CODE_EXPIRED: 10005,
10
+ VERIFICATION_CODE_OTHER_USER: 10006
11
+ },
12
+ },
13
+ USER: {
14
+ BASE_CODE: 10000,
15
+ ERRORS: {
16
+ USER_NOT_FOUND: 10001,
17
+ AUTH_FAILED: 10002,
18
+ PERMISSION_DENIED: 10003,
19
+ },
20
+ },
21
+ PROJECT: {
22
+ BASE_CODE: 11000,
23
+ ERRORS: {
24
+ PROJECT_NOT_FOUND: 11001,
25
+ CREATE_FAILED: 11002,
26
+ ACCESS_DENIED: 11003,
27
+ },
28
+ },
29
+ // Aggiungi altre route
30
+ };
31
+
32
+ module.exports = errorCodes;
@@ -105,10 +105,11 @@ class RoleChecker {
105
105
 
106
106
  // same route doesnt contains projectid so you can't use that
107
107
  // winston.debug("req.params.projectid: " + req.params.projectid);
108
- if (!req.params.projectid) {
108
+ if (!req.params.projectid && !req.projectid) {
109
109
  return res.status(400).send({success: false, msg: 'req.params.projectid is not defined.'});
110
110
  }
111
111
 
112
+ let projectid = req.params.projectid || req.projectid;
112
113
 
113
114
  // winston.info("req.user._id: " + req.user._id);
114
115
 
@@ -137,12 +138,12 @@ class RoleChecker {
137
138
  // project_user_qui_importante
138
139
 
139
140
  // JWT_HERE
140
- var query = { id_project: req.params.projectid, id_user: req.user._id, status: "active"};
141
- let cache_key = req.params.projectid+":project_users:iduser:"+req.user._id
141
+ var query = { id_project: projectid, id_user: req.user._id, status: "active"};
142
+ let cache_key = projectid+":project_users:iduser:"+req.user._id
142
143
 
143
144
  if (req.user.sub && (req.user.sub=="userexternal" || req.user.sub=="guest")) {
144
- query = { id_project: req.params.projectid, uuid_user: req.user._id, status: "active"};
145
- cache_key = req.params.projectid+":project_users:uuid_user:"+req.user._id
145
+ query = { id_project: projectid, uuid_user: req.user._id, status: "active"};
146
+ cache_key = projectid+":project_users:uuid_user:"+req.user._id
146
147
  }
147
148
  winston.debug("hasRoleOrType query " + JSON.stringify(query));
148
149
 
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.10.2",
4
+ "version": "2.10.4",
5
5
  "scripts": {
6
6
  "start": "node ./bin/www",
7
7
  "pretest": "mongodb-runner start",
@@ -36,7 +36,7 @@
36
36
  "@tiledesk-ent/tiledesk-server-visitorcounter": "^1.1.1"
37
37
  },
38
38
  "dependencies": {
39
- "@tiledesk/tiledesk-apps": "^1.0.22",
39
+ "@tiledesk/tiledesk-apps": "^1.0.25",
40
40
  "@tiledesk/tiledesk-chat21-app": "^1.1.8",
41
41
  "@tiledesk/tiledesk-chatbot-templates": "^0.1.2",
42
42
  "@tiledesk/tiledesk-chatbot-util": "^0.8.33",
@@ -2,6 +2,7 @@ var express = require('express');
2
2
  var router = express.Router();
3
3
  var CannedResponse = require("./cannedResponse");
4
4
  var winston = require('../../config/winston');
5
+ const RoleConstants = require('../../models/roleConstants');
5
6
  // const CannedResponseEvent = require('../event/CannedResponseEvent');
6
7
 
7
8
 
@@ -35,8 +36,11 @@ router.post('/', function (req, res) {
35
36
  });
36
37
  });
37
38
 
38
- router.put('/:cannedResponseid', function (req, res) {
39
+ router.put('/:cannedResponseid', async function (req, res) {
39
40
  winston.debug(req.body);
41
+ let canned_id = req.params.cannedResponseid;
42
+ let user_role = req.projectuser.role;
43
+
40
44
  var update = {};
41
45
 
42
46
  if (req.body.title!=undefined) {
@@ -48,23 +52,86 @@ router.put('/:cannedResponseid', function (req, res) {
48
52
  if (req.body.attributes!=undefined) {
49
53
  update.attributes = req.body.attributes;
50
54
  }
55
+
56
+ let canned = await CannedResponse.findById(canned_id).catch((err) => {
57
+ winston.error("Error finding canned response: ", err);
58
+ return res.status(500).send({ success: false, error: "General error: cannot find the canned response with id " + canned_id })
59
+ })
60
+
61
+ if (!canned) {
62
+ winston.verbose("Canned response with id " + canned_id + " not found.");
63
+ return res.status(404).send({ success: false, error: "Canned response with id " + canned_id + " not found." })
64
+ }
65
+
66
+ /**
67
+ * Change type from mongoose object to javascript standard object.
68
+ * Otherwise hasOwnProperty wouldn't works.
69
+ */
70
+ canned = canned.toObject();
71
+
72
+ if (user_role === RoleConstants.AGENT) {
73
+ if (canned.createdBy !== req.user.id) {
74
+ winston.warn("Not allowed. User " + req.user.id + " can't modify a canned response of user " + canned.createdBy);
75
+ return res.status(403).send({ success: false, error: "You are not allowed to modify a canned response that is not yours."})
76
+ }
77
+ }
78
+ else if (user_role === RoleConstants.OWNER || user_role === RoleConstants.ADMIN) {
79
+ if (canned.hasOwnProperty('shared') && canned.shared === false) {
80
+ winston.warn("Not allowed. User " + req.user.id + " can't modify a canned response of user " + canned.createdBy);
81
+ return res.status(403).send({ success: false, error: "Not allowed to modify a non administration canned response"})
82
+ }
83
+ } else {
84
+ winston.warn("User " + req.user.id + "trying to modify canned with role " + user_role);
85
+ return res.status(401).send({ success: false, error: "Unauthorized"})
86
+ }
51
87
 
52
-
53
- CannedResponse.findByIdAndUpdate(req.params.cannedResponseid, update, { new: true, upsert: true }, function (err, updatedCannedResponse) {
88
+ CannedResponse.findByIdAndUpdate(canned_id, update, { new: true, upsert: true }, function (err, updatedCannedResponse) {
54
89
  if (err) {
55
90
  winston.error('--- > ERROR ', err);
56
91
  return res.status(500).send({ success: false, msg: 'Error updating object.' });
57
92
  }
58
93
 
59
-
60
-
61
94
  // CannedResponseEvent.emit('CannedResponse.update', updatedCannedResponse);
62
95
  res.json(updatedCannedResponse);
63
96
  });
64
97
  });
65
98
 
66
- router.delete('/:cannedResponseid', function (req, res) {
99
+ router.delete('/:cannedResponseid', async function (req, res) {
67
100
  winston.debug(req.body);
101
+ let canned_id = req.params.cannedResponseid;
102
+ let user_role = req.projectuser.role;
103
+
104
+ let canned = await CannedResponse.findById(canned_id).catch((err) => {
105
+ winston.error("Error finding canned response: ", err);
106
+ return res.status(500).send({ success: false, error: "General error: cannot find the canned response with id " + canned_id })
107
+ })
108
+
109
+ if (!canned) {
110
+ winston.verbose("Canned response with id " + canned_id + " not found.");
111
+ return res.status(404).send({ success: false, error: "Canned response with id " + canned_id + " not found." })
112
+ }
113
+
114
+ /**
115
+ * Change type from mongoose object to javascript standard object.
116
+ * Otherwise hasOwnProperty wouldn't works.
117
+ */
118
+ canned = canned.toObject();
119
+
120
+ if (user_role === RoleConstants.AGENT) {
121
+ if (canned.createdBy !== req.user.id) {
122
+ winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
123
+ return res.status(403).send({ success: false, error: "You are not allowed to delete a canned response that is not yours."})
124
+ }
125
+ }
126
+ else if (user_role === RoleConstants.OWNER || user_role === RoleConstants.ADMIN) {
127
+ if (canned.hasOwnProperty('shared') && canned.shared === false) {
128
+ winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
129
+ return res.status(403).send({ success: false, error: "Not allowed to delete a non administration canned response"})
130
+ }
131
+ } else {
132
+ winston.warn("User " + req.user.id + "trying to delete canned with role " + user_role);
133
+ return res.status(401).send({ success: false, error: "Unauthorized"})
134
+ }
68
135
 
69
136
  CannedResponse.findByIdAndUpdate(req.params.cannedResponseid, {status: 1000}, { new: true, upsert: true }, function (err, updatedCannedResponse) {
70
137
  if (err) {
@@ -72,15 +139,46 @@ router.delete('/:cannedResponseid', function (req, res) {
72
139
  return res.status(500).send({ success: false, msg: 'Error updating object.' });
73
140
  }
74
141
 
75
-
76
-
77
142
  // CannedResponseEvent.emit('CannedResponse.delete', updatedCannedResponse);
78
143
  res.json(updatedCannedResponse);
79
144
  });
80
145
  });
81
146
 
82
- router.delete('/:cannedResponseid/physical', function (req, res) {
147
+ router.delete('/:cannedResponseid/physical', async function (req, res) {
83
148
  winston.debug(req.body);
149
+ let canned_id = req.params.cannedResponseid;
150
+
151
+ let canned = await CannedResponse.findById(canned_id).catch((err) => {
152
+ winston.error("Error finding canned response: ", err);
153
+ return res.status(500).send({ success: false, error: "General error: cannot find the canned response with id " + canned_id })
154
+ })
155
+
156
+ if (!canned) {
157
+ winston.verbose("Canned response with id " + canned_id + " not found.");
158
+ return res.status(404).send({ success: false, error: "Canned response with id " + canned_id + " not found." })
159
+ }
160
+
161
+ /**
162
+ * Change type from mongoose object to javascript standard object.
163
+ * Otherwise hasOwnProperty wouldn't works.
164
+ */
165
+ canned = canned.toObject();
166
+
167
+ if (user_role === RoleConstants.AGENT) {
168
+ if (canned.createdBy !== req.user.id) {
169
+ winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
170
+ return res.status(403).send({ success: false, error: "You are not allowed to delete a canned response that is not yours."})
171
+ }
172
+ }
173
+ else if (user_role === RoleConstants.OWNER || user_role === RoleConstants.ADMIN) {
174
+ if (canned.hasOwnProperty('shared') && canned.shared === false) {
175
+ winston.warn("Not allowed. User " + req.user.id + " can't delete a canned response of user " + canned.createdBy);
176
+ return res.status(403).send({ success: false, error: "Not allowed to delete a non administration canned response"})
177
+ }
178
+ } else {
179
+ winston.warn("User " + req.user.id + "trying to delete canned with role " + user_role);
180
+ return res.status(401).send({ success: false, error: "Unauthorized"})
181
+ }
84
182
 
85
183
  CannedResponse.remove({ _id: req.params.cannedResponseid }, function (err, cannedResponse) {
86
184
  if (err) {
@@ -88,15 +186,15 @@ router.delete('/:cannedResponseid/physical', function (req, res) {
88
186
  return res.status(500).send({ success: false, msg: 'Error deleting object.' });
89
187
  }
90
188
 
91
-
92
189
  // CannedResponseEvent.emit('CannedResponse.delete', CannedResponse);
93
-
94
190
  res.json(cannedResponse);
95
191
  });
96
192
  });
97
193
 
98
194
  router.get('/:cannedResponseid', function (req, res) {
99
195
  winston.debug(req.body);
196
+ let user_id = req.user.id;
197
+ console.log("[Canned] user_id: ", user_id);
100
198
 
101
199
  CannedResponse.findById(req.params.cannedResponseid, function (err, cannedResponse) {
102
200
  if (err) {
@@ -105,6 +203,11 @@ router.get('/:cannedResponseid', function (req, res) {
105
203
  if (!cannedResponse) {
106
204
  return res.status(404).send({ success: false, msg: 'Object not found.' });
107
205
  }
206
+
207
+ if (cannedResponse.createdBy !== user_id) {
208
+ return res.status(403).send({ success: false, msg: 'You are not allowed to get a canned response that is not yours.'})
209
+ }
210
+
108
211
  res.json(cannedResponse);
109
212
  });
110
213
  });
@@ -117,6 +220,8 @@ router.get('/', function (req, res) {
117
220
  page = req.query.page;
118
221
  }
119
222
 
223
+ console.log("req.user._id: ", req.user._id)
224
+ console.log("req.user.id: ", req.user.id)
120
225
  var skip = page * limit;
121
226
  winston.debug('CannedResponse ROUTE - SKIP PAGE ', skip);
122
227
 
@@ -147,7 +147,7 @@ class PubModulesManager {
147
147
  }
148
148
 
149
149
  if (this.analyticsRoute) {
150
- app.use('/:projectid/analytics', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('agent')], this.analyticsRoute);
150
+ app.use('/:projectid/analytics', [passport.authenticate(['basic', 'jwt'], { session: false }), validtoken, roleChecker.hasRole('admin')], this.analyticsRoute);
151
151
  winston.info("ModulesManager analytics controller loaded");
152
152
  }
153
153
 
package/routes/auth.js CHANGED
@@ -40,6 +40,7 @@ if (pubKey) {
40
40
  }
41
41
 
42
42
  var recaptcha = require('../middleware/recaptcha');
43
+ const errorCodes = require('../errorCodes');
43
44
 
44
45
 
45
46
 
@@ -76,6 +77,14 @@ router.post('/signup',
76
77
  winston.error("Signup validation error. Email or password is missing", {email: req.body.email, password: req.body.password});
77
78
  return res.json({ success: false, msg: 'Please pass email and password.' });
78
79
  } else {
80
+
81
+ // TODO: move the regex control inside signup method of UserService.
82
+ // Warning: the pwd used in every test must be changed!
83
+ const regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,}$/);
84
+ if (!regex.test(req.body.password)) {
85
+ return res.status(403).send({ success: false, message: "The password does not meet the minimum vulnerability requirements"})
86
+ }
87
+
79
88
  return userService.signup(req.body.email, req.body.password, req.body.firstname, req.body.lastname, false)
80
89
  .then( async function (savedUser) {
81
90
 
@@ -96,7 +105,16 @@ router.post('/signup',
96
105
 
97
106
  if (!req.body.disableEmail){
98
107
  if (!skipVerificationEmail) {
99
- emailService.sendVerifyEmailAddress(savedUser.email, savedUser);
108
+
109
+ let verify_email_code = uniqid();
110
+ console.log("(Auth) verify_email_code: ", verify_email_code);
111
+
112
+ let redis_client = req.app.get('redis_client');
113
+ let key = "emailverify:verify-" + verify_email_code;
114
+ let obj = { _id: savedUser._id, email: savedUser.email}
115
+ let value = JSON.stringify(obj);
116
+ redis_client.set(key, value, { EX: 900} )
117
+ emailService.sendVerifyEmailAddress(savedUser.email, savedUser, verify_email_code);
100
118
  }
101
119
  }
102
120
 
@@ -129,16 +147,16 @@ router.post('/signup',
129
147
 
130
148
  res.json({ success: true, msg: 'Successfully created new user.', user: userJson });
131
149
  }).catch(function (err) {
132
-
133
-
134
150
 
151
+ winston.error('Error registering new user', err);
135
152
  authEvent.emit("user.signup.error", {req: req, err:err});
136
153
 
137
-
138
-
154
+ if (err.code === 11000) {
155
+ res.status(403).send({ success: false, message: "Email already registered" });
156
+ } else {
157
+ res.status(500).send({ success: false, message: "Registration cannot be completed" });
158
+ }
139
159
 
140
- winston.error('Error registering new user', err);
141
- res.send(err);
142
160
  });
143
161
  }
144
162
  });
@@ -759,11 +777,32 @@ router.get("/google/callback", passport.authenticate("google", { session: false
759
777
  // });
760
778
 
761
779
  // VERIFY EMAIL
762
- router.put('/verifyemail/:userid', function (req, res) {
780
+ router.put('/verifyemail/:userid/:code', async function (req, res) {
781
+
763
782
 
764
783
  winston.debug('VERIFY EMAIL - REQ BODY ', req.body);
765
- // controlla
766
- User.findByIdAndUpdate(req.params.userid, req.body, { new: true, upsert: true }, function (err, findUser) {
784
+
785
+ let user_id = req.params.userid;
786
+ let verify_email_code = req.params.code;
787
+
788
+ if (!verify_email_code) {
789
+ return res.status(401).send({ success: false, error: "Unable to verify email: missing verification code.", error_code: errorCodes.AUTH.ERRORS.MISSING_VERIFICATION_CODE})
790
+ }
791
+
792
+ let redis_client = req.app.get('redis_client');
793
+ let key = "emailverify:verify-" + verify_email_code;
794
+ let value = await redis_client.get(key);
795
+ console.log("(Auth) verify value: ", value);
796
+ if (!value) {
797
+ return res.status(401).send({ success: false, error: "Unable to verify email: the verification code is expired or invalid.", error_code: errorCodes.AUTH.ERRORS.VERIFICATION_CODE_EXPIRED})
798
+ }
799
+
800
+ let basic_user = JSON.parse(value);
801
+ if (user_id !== basic_user._id) {
802
+ return res.status(401).send({ success: false, error: "Trying to use a verification code from another user.", error_code: errorCodes.AUTH.ERRORS.VERIFICATION_CODE_OTHER_USER})
803
+ }
804
+
805
+ User.findByIdAndUpdate(user_id, req.body, { new: true, upsert: true }, function (err, findUser) {
767
806
  if (err) {
768
807
  winston.error(err);
769
808
  return res.status(500).send({ success: false, msg: err });
@@ -771,7 +810,7 @@ router.put('/verifyemail/:userid', function (req, res) {
771
810
  winston.debug(findUser);
772
811
  if (!findUser) {
773
812
  winston.warn('User not found for verifyemail' );
774
- return res.status(404).send({ success: false, msg: 'User not found' });
813
+ return res.status(404).send({ success: false, msg: 'User not found', error_code: errorCodes.AUTH.ERRORS.USER_NOT_FOUND});
775
814
  }
776
815
  winston.debug('VERIFY EMAIL - RETURNED USER ', findUser);
777
816
 
@@ -857,13 +896,16 @@ router.put('/requestresetpsw', function (req, res) {
857
896
 
858
897
  // TODO emit user.update?
859
898
  authEvent.emit('user.requestresetpassword', {updatedUser:updatedUser, req:req});
860
-
861
899
 
862
-
863
900
  let userWithoutResetPassword = updatedUser.toJSON();
864
901
  delete userWithoutResetPassword.resetpswrequestid;
902
+ delete userWithoutResetPassword._id;
903
+ delete userWithoutResetPassword.createdAt;
904
+ delete userWithoutResetPassword.updatedAt;
905
+ delete userWithoutResetPassword.__v;
865
906
 
866
- return res.json({ success: true, user: userWithoutResetPassword });
907
+ // return res.json({ success: true, user: userWithoutResetPassword });
908
+ return res.json({ success: true, message: "An email has been sent to reset your password" });
867
909
  // }
868
910
  // catch (err) {
869
911
  // winston.debug('PSW RESET REQUEST - SEND EMAIL ERR ', err)