free-be-account 0.0.14 → 0.0.16

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/index.js CHANGED
@@ -51,12 +51,13 @@ const __getServiceList = async (res, filter = { Enabled: true }) => {
51
51
  filter ? {} : {
52
52
  Scope: filter ? undefined: doc.Scope.map(sc => {
53
53
  const dso = res.app.getContainerContent('DataScope').find(ds => ds.Name === sc.Name);
54
- return {
55
- Label: dso ? dso.Label : '',
54
+ return dso ? {
55
+ Label: dso.Label || '',
56
56
  Field: `${sc.Name}`,
57
- Type: 'Select',
58
- Options: dso ? dso.Options : []
59
- }
57
+ Type: dso.Component || 'Select',
58
+ Options: dso.Options || [],
59
+ Multiple: dso.Multiple || false,
60
+ } : {};
60
61
  })
61
62
  })
62
63
  }
@@ -204,6 +205,10 @@ module.exports = (app) => ({
204
205
  accountDefaultPassword: '12345678',
205
206
  accountDefaultPasswordRandom: false,
206
207
  accountDefaultPasswordRandomLength: 6,
208
+
209
+ autoCreateNewUser: false,
210
+ recoverNoSamePwd: false,
211
+
207
212
  // accountDefaultPermissions: [
208
213
  // // could from system config
209
214
  // // {
@@ -226,6 +231,7 @@ module.exports = (app) => ({
226
231
 
227
232
  dataScopes: [],
228
233
  permissionControls: [],
234
+ smsFormat: '6n',
229
235
  captcha: {
230
236
  cache: 5 * 60 * 1000,
231
237
  login: false,
@@ -366,6 +372,7 @@ module.exports = (app) => ({
366
372
  Description: { type: 'String' },
367
373
  Index: { type: 'Number', required: true },
368
374
  IsVirtual: { type: 'Boolean', default: false },
375
+ Profile: { type: 'Object', default: {} },
369
376
 
370
377
  Permission: { type: 'Object', default: {} },
371
378
  },
@@ -895,9 +902,43 @@ module.exports = (app) => ({
895
902
  // Password: password,
896
903
  Enabled: true,
897
904
  Deleted: false,
898
- }).then((user) => {
905
+ }).then(async (user) => {
899
906
  if (!user) {
900
- return done(null, false);
907
+ // auto create new user
908
+ if (m.config.autoCreateNewUser) {
909
+ const valid_phone = (d) => {
910
+ return /^(0|86|17951)?(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])[0-9]{8}$/.test(d);
911
+ };
912
+ const valid_email = (d) => {
913
+ // eslint-disable-next-line no-useless-escape
914
+ return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(d);
915
+ }
916
+
917
+ const userPhoneEmail = {};
918
+ if (valid_phone(username)) {
919
+ userPhoneEmail.PhoneNumber = username;
920
+ } else if (valid_email(username)) {
921
+ userPhoneEmail['Profile'] = {
922
+ Email: username
923
+ };
924
+ }
925
+
926
+ const permission = Object.assign({}, m.config.accountDefaultPermissions);
927
+ clearPermission(permission);
928
+ const newU = await app.models['account'].create({
929
+ Saved: true,
930
+ UserName: username,
931
+ Password: '',
932
+ Status: m.config.accountRequireAudit ? AccountAuditStatus.Auditing : AccountAuditStatus.Passed,
933
+ Permission: permission,
934
+
935
+ // set phone number or email
936
+ ...userPhoneEmail,
937
+ });
938
+ return done(null, newU);
939
+ } else {
940
+ return done(null, false);
941
+ }
901
942
  }
902
943
 
903
944
  const pwdVerified = verifyPassword(password, user.Password, m.config.pwdEncryptMethod || 'md5');
@@ -971,49 +1012,56 @@ module.exports = (app) => ({
971
1012
  // permission control
972
1013
  app.use(async (req, res, next) => {
973
1014
  // permission control
974
- if (!await m.hasPermission(req, m)) {
975
- const whiteList = ((m.config && m.config['whiteList']) || []).concat([`${app.config['baseUrl'] || ''}/login`]);
976
- for (let i = 0; i < whiteList.length; i += 1) {
977
- const wl = whiteList[i];
978
-
979
- if (typeof wl === 'string' && wl.toLowerCase() === req.originalUrl.toLowerCase()) return next();
1015
+ let inWhiteList = false;
1016
+ const whiteList = ((m.config && m.config['whiteList']) || []).concat([`${app.config['baseUrl'] || ''}/login`]);
1017
+ for (let i = 0; i < whiteList.length; i += 1) {
1018
+ const wl = whiteList[i];
1019
+
1020
+ if (typeof wl === 'string' && wl.toLowerCase() === req.originalUrl.toLowerCase()) {
1021
+ inWhiteList = true;
1022
+ break;
1023
+ }
980
1024
 
981
- if (typeof wl === 'object' && new RegExp(wl).test(req.originalUrl)) return next();
1025
+ if (typeof wl === 'object' && new RegExp(wl).test(req.originalUrl)) {
1026
+ inWhiteList = true;
1027
+ break;
982
1028
  }
1029
+ }
983
1030
 
1031
+ if (inWhiteList) {
1032
+ await m.hasPermission(req, m)
1033
+ return next();
1034
+ }
1035
+
1036
+ if (!await m.hasPermission(req, m)) {
984
1037
  if (req.user && req.user.id) {
985
1038
  await res.endWithErr(400, 401);
986
1039
  }
987
1040
  else {
1041
+ res.clearCookie('token');
988
1042
  await res.endWithErr(401);
989
1043
  }
990
1044
 
991
1045
  return;
992
1046
  }
993
1047
 
994
- return next();
995
- });
1048
+ // update token in cookies
1049
+ const token = req.cookies.token;
1050
+ if (token) {
1051
+ res.cookie('token', token, { maxAge: app.config['cookieTimeout'] });
1052
+ }
996
1053
 
997
- // check for force reset pwd
998
- app.use(async (req, res, next) => {
1054
+ // check for force reset pwd
999
1055
  const resetP = m.config && m.config['forceResetPwd'];
1000
1056
 
1001
- if(resetP) {
1002
- if (req.user && req.user.id) {
1003
- const updateAt = req.user.PwdUpdatedAt || req.user.CreatedDate || req.user.LastUpdateDate;
1004
- const pastP = new Date() - updateAt;
1057
+ if(resetP && req.user && req.user.id) {
1058
+ const updateAt = req.user.PwdUpdatedAt || req.user.CreatedDate || req.user.LastUpdateDate;
1059
+ const pastP = new Date() - updateAt;
1005
1060
 
1006
- if(pastP > (resetP * 24 * 3600 * 1000)) {
1007
- await res.endWithErr(403, 'RSTPWD');
1008
- } else {
1009
- return next();
1010
- }
1011
- }
1012
- else {
1013
- await res.endWithErr(401);
1061
+ if(pastP > (resetP * 24 * 3600 * 1000)) {
1062
+ await res.makeError(403, 'RSTPWD');
1063
+ return next('route');
1014
1064
  }
1015
-
1016
- return;
1017
1065
  }
1018
1066
 
1019
1067
  return next();
@@ -1127,17 +1175,17 @@ module.exports = (app) => ({
1127
1175
  { 'Profile.Email': phone },
1128
1176
  ]});
1129
1177
 
1130
- if (req.body.exists && existsCount <= 0) {
1178
+ if (req.body.exists === true && existsCount <= 0) {
1131
1179
  res.makeError(409, 'User not exists!', m);
1132
1180
  return next('route');
1133
1181
  }
1134
- if (!req.body.exists && existsCount > 0) {
1182
+ if (req.body.exists === false && existsCount > 0) {
1135
1183
  res.makeError(410, 'User aleady exists!', m);
1136
1184
  return next('route');
1137
1185
  }
1138
1186
  }
1139
1187
 
1140
- const result = await m.sms.sendRandom(phone, undefined, true, req.body.smsTemp || 'register');
1188
+ const result = await m.sms.sendRandom(phone, m.config.smsFormat || undefined, true, req.body.smsTemp || 'register');
1141
1189
 
1142
1190
  if (!result) {
1143
1191
  res.makeError(500, 'Failed to send sms!', m);
@@ -1220,16 +1268,52 @@ module.exports = (app) => ({
1220
1268
  }
1221
1269
  }
1222
1270
 
1223
- const existPhone = await res.app.models.account.countDocuments({ PhoneNumber: phone });
1224
- if (existPhone) {
1225
- res.makeError(404, 'The phone number was used already!', m);
1226
- return next('route');
1271
+ const valid_phone = (d) => {
1272
+ return /^(0|86|17951)?(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])[0-9]{8}$/.test(d);
1273
+ };
1274
+ const valid_email = (d) => {
1275
+ // eslint-disable-next-line no-useless-escape
1276
+ return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(d);
1277
+ }
1278
+
1279
+ const userPhoneEmail = {};
1280
+ let isPhone = false;
1281
+ let isEmail = false;
1282
+
1283
+ if (valid_phone(phone)) {
1284
+ userPhoneEmail.PhoneNumber = phone;
1285
+ isPhone = true;
1286
+ } else if (valid_email(phone)) {
1287
+ isEmail = true;
1288
+ userPhoneEmail.UserName = phone;
1289
+ userPhoneEmail['Profile'] = {
1290
+ Email: phone
1291
+ };
1292
+ } else {
1293
+ userPhoneEmail.UserName = phone;
1294
+ }
1295
+
1296
+ if (isPhone) {
1297
+ const existPhone = await res.app.models.account.countDocuments({ PhoneNumber: phone });
1298
+ if (existPhone) {
1299
+ res.makeError(404, 'The phone number was used already!', m);
1300
+ return next('route');
1301
+ }
1302
+ }
1303
+
1304
+ if (isEmail) {
1305
+ const existPhone = await res.app.models.account.countDocuments({ 'Profile.Email': phone });
1306
+ if (existPhone) {
1307
+ res.makeError(405, 'The email address was used already!', m);
1308
+ return next('route');
1309
+ }
1227
1310
  }
1228
1311
 
1229
1312
  // only create with specified fields
1230
1313
  res.locals.body = {
1231
1314
  Saved: true,
1232
- PhoneNumber: phone,
1315
+ // PhoneNumber: phone,
1316
+ ...userPhoneEmail,
1233
1317
  Password: encryptPwd(password, m.config.pwdEncryptMethod || 'md5')
1234
1318
  }
1235
1319
 
@@ -1280,14 +1364,32 @@ module.exports = (app) => ({
1280
1364
  }
1281
1365
 
1282
1366
  // only create with specified fields
1283
- res.locals.body = {
1284
- Password: encryptPwd(password, m.config.pwdEncryptMethod || 'md5')
1367
+ if (m.config.recoverNoSamePwd) {
1368
+ let oldPwd = req.user && req.user.Password;
1369
+ if (!oldPwd) {
1370
+ const theUser = await res.app.models.account.findOne({$or: [
1371
+ { PhoneNumber: phone },
1372
+ { 'Profile.Email': phone },
1373
+ ]});
1374
+
1375
+ oldPwd = theUser && theUser.Password;
1376
+ }
1377
+
1378
+ if (oldPwd && verifyPassword(password, oldPwd, m.config.pwdEncryptMethod || 'md5')) {
1379
+ res.makeError(406, 'New password cannot be the same as the old one!', m);
1380
+ return next('route');
1381
+ }
1285
1382
  }
1286
1383
 
1287
- res.locals.filter = {
1288
- PhoneNumber: phone
1384
+ res.locals.body = {
1385
+ Password: encryptPwd(password, m.config.pwdEncryptMethod || 'md5'),
1289
1386
  }
1290
1387
 
1388
+ res.locals.filter = {$or: [
1389
+ { PhoneNumber: phone },
1390
+ { 'Profile.Email': phone },
1391
+ ]}
1392
+
1291
1393
  return next();
1292
1394
  },
1293
1395
  app.UpdateDocument('account', false, (req, res) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-be-account",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "main": "index.js",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -9,14 +9,14 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@alicloud/pop-core": "^1.7.13",
12
- "axios": "^1.4.0",
13
- "bcrypt": "^5.1.0",
14
- "crypto-js": "^4.1.1",
12
+ "axios": "^1.6.8",
13
+ "bcrypt": "^5.1.1",
14
+ "crypto-js": "^4.2.0",
15
15
  "js-md5": "^0.7.3",
16
- "nodemailer": "^6.9.2",
16
+ "nodemailer": "^6.9.13",
17
17
  "passport": "^0.6.0",
18
18
  "passport-local": "^1.0.0",
19
19
  "svg-captcha": "^1.4.0",
20
- "uuid": "^9.0.0"
20
+ "uuid": "^9.0.1"
21
21
  }
22
22
  }
@@ -4,26 +4,26 @@ const router = express.Router();
4
4
  const { AccountAuditStatus } = require('../../enum');
5
5
  const { clearPermission, encryptPwd, crypto } = require('../../utils');
6
6
 
7
- // TODO: i18n translate
8
7
  const accountFilters = [
8
+ {
9
+ Name: 'id',
10
+ Type: 'String',
11
+ Info: {
12
+ Separate: true,
13
+ },
14
+ },
9
15
  {
10
16
  Name: 'LastUpdateDate',
11
17
  Type: 'DateRange',
12
- Label: '更新日期',
13
- Placeholder: '请选择',
14
18
  },
15
19
  {
16
20
  Name: 'Enabled',
17
21
  Type: 'Select',
18
- Label: '激活状态',
19
- Placeholder: '请选择',
20
22
  Options: [
21
23
  {
22
- Label: '已激活',
23
24
  Value: true,
24
25
  },
25
26
  {
26
- Label: '未激活',
27
27
  Value: false,
28
28
  },
29
29
  ],
@@ -31,22 +31,18 @@ const accountFilters = [
31
31
  {
32
32
  Name: 'Profile.Name',
33
33
  Type: 'String',
34
- Label: '姓名',
35
34
  },
36
35
  {
37
36
  Name: 'Profile.Title',
38
37
  Type: 'String',
39
- Label: '职务',
40
38
  },
41
39
  {
42
40
  Name: 'PhoneNumber',
43
41
  Type: 'String',
44
- Label: '手机号',
45
42
  },
46
43
  {
47
44
  Name: 'UserName',
48
45
  Type: 'String',
49
- Label: '用户名',
50
46
  },
51
47
  ];
52
48
 
@@ -9,7 +9,8 @@ router.get('/',
9
9
  'Name',
10
10
  'Index',
11
11
  'IsVirtual',
12
- 'Permission'
12
+ 'Permission',
13
+ 'Profile',
13
14
  ];
14
15
  res.locals.filter = {
15
16
  Parent: req.query.Parent || {
@@ -29,6 +29,8 @@ router.get('/', (req, res, next) => {
29
29
  Status: user.Status,
30
30
 
31
31
  StepsDefinition,
32
+
33
+ ar: router.mdl.config.accountRequireAudit,
32
34
  });
33
35
 
34
36
  return next();
@@ -61,7 +63,15 @@ router.post('/edit', async (req, res, next) => {
61
63
  res.app.modules.account.utils.clearPermission(p);
62
64
 
63
65
  // TODO: should not use mongoose directly
64
- await res.app.models['account'].update({ id: req.user.id }, { $unset: { Status: 0 }, $set: { Permission: p } });
66
+ const setObj = {
67
+ $set: { Permission: p }
68
+ };
69
+
70
+ if (router.mdl.config.accountRequireAudit) {
71
+ Object.assign(setObj, { $unset: { Status: 0 } });
72
+ }
73
+
74
+ await res.app.models['account'].update({ id: req.user.id }, setObj);
65
75
 
66
76
  res.addData({});
67
77
 
@@ -79,14 +89,16 @@ router.post('/submit',
79
89
  res.locals.body.Profile = {...user.Profile, ...req.body.Profile};
80
90
  }
81
91
 
82
- res.locals.body.Status = res.app.modules.account.AccountAuditStatus.Auditing;
92
+ if (router.mdl.config.accountRequireAudit) {
93
+ res.locals.body.Status = router.mdl.AccountAuditStatus.Auditing;
94
+ }
83
95
 
84
96
  // set to default permission
85
- const p = res.app.modules.account.config.accountDefaultPermissions;
97
+ const p = router.mdl.config.accountDefaultPermissions;
86
98
  res.app.modules.account.utils.clearPermission(p);
87
99
  res.locals.body.Permission = p;
88
100
 
89
- res.locals.filters = { id: req.user.id };
101
+ res.locals.filter = { id: req.user.id };
90
102
  res.locals.fields = [
91
103
  'Profile',
92
104
  'Status',
@@ -63,7 +63,7 @@ router.put('/',
63
63
  res.locals.body.UserName = res.locals.body.PhoneNumber;
64
64
  }
65
65
 
66
- res.locals.filters = { id: req.user.id };
66
+ res.locals.filter = { id: req.user.id };
67
67
  res.locals.fields = [
68
68
  'PhoneNumber',
69
69
  'Password',
@@ -34,7 +34,7 @@ router.put('/',
34
34
  res.locals.body = {};
35
35
  res.locals.body.Password = res.app.modules.account.utils.encryptPwd(password, res.app.modules.account.config.pwdEncryptMethod || 'md5');
36
36
 
37
- res.locals.filters = { id: req.user.id };
37
+ res.locals.filter = { id: req.user.id };
38
38
  res.locals.fields = [
39
39
  'password',
40
40
  ];
package/sms/index.js CHANGED
@@ -129,7 +129,13 @@ module.exports = (app) => ({
129
129
  t = `${t}_mail`;
130
130
  }
131
131
 
132
- const keys = (global && global.sms && global.sms[t]) || app.modules.account.config.sms.keys[t] || app.modules.account.config.sms.keys;
132
+ let keys = app.modules.account.config.sms.keys[t] || app.modules.account.config.sms.keys;
133
+
134
+ if (!keys.platform) {
135
+ keys = (global && global.sms && global.sms[t]);
136
+ }
137
+
138
+ // const keys = (global && global.sms && global.sms[t]) || app.modules.account.config.sms.keys[t] || app.modules.account.config.sms.keys;
133
139
 
134
140
  if (keys.platform) {
135
141
  // should not send too frequent!
package/utils.js CHANGED
@@ -60,7 +60,7 @@ function clearPermission(perm) {
60
60
  return clearP(perm);
61
61
  }
62
62
 
63
- function verifyPassword(pwd, storedPwd, method = 'md5') {
63
+ function verifyPassword(pwd, storedPwd = '', method = 'md5') {
64
64
  let verified = false;
65
65
  let methods = [];
66
66
 
@@ -77,7 +77,7 @@ function verifyPassword(pwd, storedPwd, method = 'md5') {
77
77
  verified = verified || (crypto.MD5(pwd) === storedPwd);
78
78
  break;
79
79
  case 'sha1':
80
- verified = verified || (crypto.sha1(pwd, storedPwd.substr(0, EncryptOptions.saltLength), EncryptOptions.sha1Iteration).toString() === storedPwd.substr(EncryptOptions.saltLength));
80
+ verified = verified || (crypto.sha1(pwd, storedPwd.substring(0, EncryptOptions.saltLength), EncryptOptions.sha1Iteration).toString() === storedPwd.substr(EncryptOptions.saltLength));
81
81
  break;
82
82
  case 'bcrypt':
83
83
  verified = verified || crypto.bcryptVerify(pwd, storedPwd);
@@ -132,6 +132,12 @@ async function saveServiceList (app, clean=false) {
132
132
  for (let i = 0; i < Object.keys(perm).length; i += 1) {
133
133
  const p = Object.keys(perm)[i];
134
134
 
135
+ // in case the developer didn't provide title and description information
136
+ perm[p] = perm[p] || {
137
+ title: p,
138
+ description: p,
139
+ };
140
+
135
141
  // TODO: notify user if they are creating permission with these names
136
142
  if (['title', 'description', 'scope', 'label'].indexOf(p.toLowerCase()) >= 0) continue;
137
143