Completed
Push — master ( 78d2f9...949122 )
by greg
42s
created

utils.js ➔ isUserAllowedOnRoute   D

Complexity

Conditions 9
Paths 8

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
c 1
b 0
f 0
nc 8
dl 0
loc 29
rs 4.909
nop 2

1 Function

Rating   Name   Duplication   Size   Complexity  
A utils.js ➔ ... ➔ ??? 0 6 2
1
import redis from 'redis'
2
import Limiter from 'ratelimiter'
3
import owasp from 'owasp-password-strength-test'
4
import bcrypt from 'bcrypt-nodejs'
5
import Cookies from 'cookies'
6
import jwt from 'jwt-simple'
7
8
import {
9
  User
10
  ,config
11
  ,coreUtils
12
} from '../../cli'
13
14
export function checkSameEmail(data) {
15
  var emailAlreadyUsed = false
16
  var bdd = User.manager.instance.get()
17
  for (var i = 0, len = bdd.length; i < len; i++) {
18
    var user = bdd[i]
19
    if (user.email === data.email && parseInt(user.id) !== parseInt(data.id)) {
20
      emailAlreadyUsed = true
21
    }
22
  }
23
24
  if (emailAlreadyUsed === true) {
25
    return {
26
      success:0,
27
      message: 'Email adress already exist'
28
    }
29
  }else {
30
    return {
31
      success:1
32
    }
33
  }
34
}
35
36
export function getRole(data) {
37
  var roles = config.users.roles
38
  Array.prototype.forEach.call(roles, (role) => {
39
    if(role.name === data.role) {
40
      data.role = role
41
    }
42
  })
43
44
  return data
45
}
46
47
export function commonPassword(data) {
48
  var owaspConfig = config.users.owasp
49
  owasp.config(owaspConfig)
50
  var sameAsUser = (typeof owaspConfig.sameAsUser !== 'undefined' && owaspConfig.sameAsUser !== null) ? owaspConfig.sameAsUser : true
51
  var mostCommon = (typeof owaspConfig.mostCommon !== 'undefined' && owaspConfig.mostCommon !== null) ? owaspConfig.mostCommon : true
52
  var mostCommonPassword = config.users.mostCommonPassword
53
  owasp.tests.required.push(function(password) {
54
    if (mostCommon && coreUtils.array.contains(mostCommonPassword, password.toLowerCase())) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if mostCommon && coreUtils....password.toLowerCase()) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
55
      return 'the password used is too common.'
56
    }
57
  })
58
59
  var currentUserName = data.username
60
  owasp.tests.required.push(function(password) {
61
    var username = currentUserName
62
    var shouldTest = sameAsUser
63
64
    if(shouldTest) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if shouldTest is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
65
      if (password.toLowerCase() === username.toLowerCase()) {
66
        return 'username and password must be different.'
67
      }
68
      if (password.toLowerCase() === username.toLowerCase().split('').reverse().join('')) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if password.toLowerCase() =...("").reverse().join("") is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
69
        return 'username and password must be different, not just inverted.'
70
      }
71
    }
72
  })
73
74
  var res = owasp.test(data.password)
75
76
  if(typeof res.errors !== 'undefined' && res.errors !== null
77
      && res.errors.length > 0) {
78
    var message = ''
79
    Array.prototype.forEach.call(res.errors, (error) => {
80
      message += error + '<br />'
81
    })
82
    return {
83
      success:0,
84
      message: message
85
    }
86
  }else {
87
    return {
88
      success:1
89
    }
90
  }
91
}
92
93
export function encryptPassword(numb, password) {
94
  var salt = bcrypt.genSaltSync(numb)
95
  return bcrypt.hashSync(password, salt)
96
}
97
98
export function getUserRoutes(workflow) {
99
  var routes = config.users.routes
100
  var userRoles = []
101
  Array.prototype.forEach.call(Object.keys(routes), (role) => {
102
    if(role === workflow) {
103
      userRoles = routes[role]
104
    }
105
  })
106
107
  return userRoles
108
}
109
110
111
export function findSync(id) {
112
  var bdd = User.manager.instance.get()
113
  for (var i = 0, len = bdd.length; i < len; i++) {
114
    var user = bdd[i]
115
    if (parseInt(user.id) === parseInt(id)) {
116
      return user
117
    }
118
  }
119
  return null
120
}
121
122
export function find(id, done) {
123
  var bdd = User.manager.instance.get()
124
  for (var i = 0, len = bdd.length; i < len; i++) {
125
    var user = bdd[i]
126
    if (parseInt(user.id) === parseInt(id)) {
127
      return done(null, user)
128
    }
129
  }
130
  return done(null, null)
131
}
132
133
export function findByUsername(username, done) {
134
  var bdd = User.manager.instance.get()
135
  for (var i = 0, len = bdd.length; i < len; i++) {
136
    var user = bdd[i]
137
    if (user.username === username) {
138
      return done(null, user)
139
    }
140
  }
141
  return done(null, null)
142
}
143
144
export function findByEmail(email, done) {
145
  var bdd = User.manager.instance.get()
146
  for (var i = 0, len = bdd.length; i < len; i++) {
147
    var user = bdd[i]
148
    if (user.email === email) {
149
      return done(null, user)
150
    }
151
  }
152
  return done(null, null)
153
}
154
155
export function findByResetPasswordToken(resetPasswordToken, done) {
156
  var bdd = User.manager.instance.get()
157
  for (var i = 0, len = bdd.length; i < len; i++) {
158
    var user = bdd[i]
159
    if (user.resetPasswordToken === resetPasswordToken) {
160
      return done(null, user)
161
    }
162
  }
163
  return done(null, null)
164
}
165
166
export function isValid(user, password) {
167
  if(user.actif === 1) {
168
    if(bcrypt.compareSync(password, user.password)) {
169
      return true
170
    }
171
  }
172
  return false
173
}
174
175
export function decodeUser(req, res) {
176
  var decoded = {}
177
  var token = User.utils.getTokenFromCookies(req, res)
178
  if(typeof token !== 'undefined' && token !== null && token !== '') {
179
    try {
180
      var secret = config.users.secret
181
      decoded = jwt.decode(token, secret)
182
    } catch (err) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
183
  }
184
185
  return decoded
186
}
187
188
export function getTokenFromCookies(req, res) {
189
  var cookies = new Cookies(req, res, {
190
    secure: config.cookie.secure
191
  })
192
  return cookies.get('x-access-token')
193
}
194
195
export function isAbeRestrictedUrl(currentRoute) {
196
  if( currentRoute.indexOf('/abe/users/forgot') > -1
197
    || currentRoute.indexOf('/abe/users/login') > -1
198
    || currentRoute.indexOf('/abe/users/reset') > -1
199
    || !/^\/abe/.test(currentRoute)) {
200
    return false
201
  }
202
203
  return true
204
}
205
206
export function isUserAllowedOnRoute(workflow, currentRoute) {
207
  var isAllowed = false
208
209
  if (config.users.enable) {
210
    if( currentRoute.indexOf('/abe/users/forgot') > -1 || currentRoute.indexOf('/abe/users/login') > -1 || !/^\/abe/.test(currentRoute)) {
211
      return true
212
    }
213
214
    if (currentRoute.indexOf('abe/') === -1) {
215
      isAllowed = true
216
    }
217
218
    if (workflow != null) {
219
      var routes = config.users.routes
220
      if(typeof routes[workflow] !== 'undefined' && routes[workflow] !== null) {
221
        Array.prototype.forEach.call(routes[workflow], (route) => {
222
          var reg = new RegExp(route)
223
          if(reg.test(currentRoute)) {
224
            isAllowed = true
225
          }
226
        })
227
      }
228
    }
229
  }else {
230
    isAllowed = true
231
  }
232
  
233
  return isAllowed
234
}
235
236
export function getAll() {
237
  return User.manager.instance.get()
238
}
239
240
export function getUserWorkflow(status, role) {
0 ignored issues
show
Unused Code introduced by
The parameter role is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
241
  var flows = []
242
243
  function addFlow (flow, type, action) {
244
    type = (type != null) ? type : flow
245
    return {
246
      status: flow,
247
      url: `/abe/save/${type}/${action}`
248
    }
249
  }
250
251
  if (config.users.enable) {
252
    var before = null
253
    var found = false
254
    Array.prototype.forEach.call(config.users.workflow, (flow) => {
255
      if (found) {
256
        flows.push(addFlow(flow, flow, "submit"))
257
        found = false
258
      }
259
      if (status == flow) {
260
        found = true
261
        if (before != null) {
262
          if (flow == "publish") {
263
            flows.push(addFlow("edit", "draft", "submit"))
264
          }else {
265
            flows.push(addFlow("reject", before, "reject"))
266
          }
267
        }
268
        flows.push(addFlow(flow, flow, "edit"))
269
      }
270
      before = flow
271
    })
272
  }else {
273
    flows = [addFlow("draft", "draft", "submit"), addFlow("publish", "publish", "submit")]
274
  }
275
  return flows
276
}
277
278
export function loginLimitTry(username) {
279
  var p = new Promise((resolve) => {
280
    var isNexted = false
281
    try {
282
      var limiterConfig = config.users.limiter
283
284
      var client = redis.createClient()
285
      client.on('error', function() {
286
        if (!isNexted) {
287
          isNexted = true
288
          resolve()
289
        }
290
      })
291
292
      var limit = new Limiter({
293
        id: username,
294
        db: client,
295
        duration: limiterConfig.duration,
296
        max: limiterConfig.max
297
      })
298
299
      limit.get(function(err, limit) {
300
        if (err) {
301
          resolve()
302
        }else {
303
          resolve(limit)
304
        }
305
      })
306
    }catch(e) {
307
      resolve()
308
    }
309
  })
310
311
  return p
312
}