@tiledesk/tiledesk-server 2.10.3 → 2.10.5

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@
5
5
  🚀 IN PRODUCTION 🚀
6
6
  (https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
7
7
 
8
+ # 2.10.5
9
+ - Fix bug on access chatbot route rules
10
+ - Fix bug update chatbot avatar
11
+
12
+ # 2.10.4
13
+ - Removed temporary conversation from default query to get all requests
14
+ - Removed draft conversation from requests count
15
+ - Improved security
16
+
8
17
  # 2.10.3
9
18
  - Added support for formatType in openai completions
10
19
 
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.3",
4
+ "version": "2.10.5",
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)