@bitfinex/bfx-facs-auth-google 1.2.3 → 2.0.0

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.
@@ -0,0 +1,160 @@
1
+ /* eslint-env mocha */
2
+
3
+ 'use strict'
4
+
5
+ const assert = require('assert')
6
+ const { promisify } = require('util')
7
+ const { pick } = require('@bitfinex/lib-js-util-base')
8
+
9
+ const conf = require('./config/facs/auth-google.config')
10
+ const AuthGoogle = require('../')
11
+ const PrivilegeRepository = require('../src/privilege-repo')
12
+
13
+ const ctx = { root: './test' }
14
+ const caller = { ctx }
15
+ const authGoogle = new AuthGoogle(caller, { conf, db: ':memory:' }, ctx)
16
+
17
+ const testAdminEmail = 'testForms@admin.com'
18
+ const testPrivilege = 'sample-privilege:view'
19
+ const adminPayload = {
20
+ email: testAdminEmail,
21
+ password: 'test123',
22
+ level: 0
23
+ }
24
+
25
+ describe('Admin Privileges', () => {
26
+ beforeEach(async () => {
27
+ await new Promise((resolve) => authGoogle.start(resolve))
28
+ })
29
+
30
+ afterEach(async () => {
31
+ await new Promise((resolve) => authGoogle.stop(resolve))
32
+ })
33
+
34
+ it('should add privilege', async () => {
35
+ const res = await authGoogle.addPrivilege(testPrivilege)
36
+ assert.strictEqual(res.name, testPrivilege)
37
+
38
+ await new Promise((resolve) => authGoogle.db.get('SELECT * FROM privileges WHERE name=?', [testPrivilege], (err, row) => {
39
+ if (err) throw err
40
+ assert.strictEqual(typeof row.id, 'number')
41
+ assert.equal(row.name, testPrivilege)
42
+ resolve()
43
+ }))
44
+ })
45
+
46
+ it('should get all privileges', async () => {
47
+ await authGoogle.addPrivilege(testPrivilege)
48
+ const res = await authGoogle.getAllPrivileges()
49
+ assert.strictEqual(res.length, 1)
50
+ assert.deepStrictEqual(res, [{ id: 1, name: testPrivilege }])
51
+ })
52
+
53
+ it('should assign privilege to admin', async () => {
54
+ await authGoogle.addPrivilege(testPrivilege)
55
+ const savedAdmin = await authGoogle.addAdmin(adminPayload)
56
+
57
+ const [privilege] = await authGoogle.getAllPrivileges()
58
+
59
+ const res = await authGoogle.assignAdminPrivilege(adminPayload.email, privilege.id)
60
+ assert.deepStrictEqual(res, {
61
+ admin: savedAdmin.email,
62
+ privilege: privilege.name
63
+ })
64
+ })
65
+
66
+ it('should unassign privilege from admin', async () => {
67
+ await authGoogle.addPrivilege(testPrivilege)
68
+ const savedAdmin = await authGoogle.addAdmin(adminPayload)
69
+
70
+ const [privilege] = await authGoogle.getAllPrivileges()
71
+
72
+ const assigned = await authGoogle.assignAdminPrivilege(adminPayload.email, privilege.id)
73
+ assert.deepStrictEqual(assigned, {
74
+ admin: savedAdmin.email,
75
+ privilege: privilege.name
76
+ })
77
+
78
+ const unassigned = await authGoogle.unAssignAdminPrivilege(adminPayload.email, privilege.id)
79
+ assert.deepStrictEqual(unassigned, {
80
+ admin: savedAdmin.email,
81
+ privilege: privilege.name
82
+ })
83
+ })
84
+
85
+ it('should throw error when assigning privilege if admin does not exist', async () => {
86
+ await authGoogle.addPrivilege(testPrivilege)
87
+
88
+ const [privilege] = await authGoogle.getAllPrivileges()
89
+
90
+ try {
91
+ await authGoogle.assignAdminPrivilege(adminPayload.email, privilege.id)
92
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
93
+ } catch (err) {
94
+ assert.strictEqual(err.message, 'INVALID_ADMIN')
95
+ }
96
+ })
97
+
98
+ it('should throw error when assigning privilege if privilege does not exist', async () => {
99
+ await authGoogle.addAdmin(adminPayload)
100
+
101
+ try {
102
+ await authGoogle.assignAdminPrivilege(adminPayload.email, 1)
103
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
104
+ } catch (err) {
105
+ assert.strictEqual(err.message, 'INVALID_PRIVILEGE_ID')
106
+ }
107
+ })
108
+
109
+ it('should return an admin with their associated privileges', async () => {
110
+ await authGoogle.addPrivilege(testPrivilege)
111
+ await authGoogle.addAdmin(adminPayload)
112
+
113
+ const [privilege] = await authGoogle.getAllPrivileges()
114
+
115
+ await authGoogle.assignAdminPrivilege(adminPayload.email, privilege.id)
116
+
117
+ const res = await authGoogle.getAdminWithPrivileges(adminPayload.email)
118
+ assert.deepStrictEqual(pick(res, ['email', 'level', 'active', 'privileges']), {
119
+ email: adminPayload.email,
120
+ level: adminPayload.level,
121
+ active: 1,
122
+ privileges: [{ id: 1, name: testPrivilege }]
123
+ })
124
+ })
125
+
126
+ it('should check if an admin has a required privilege', async () => {
127
+ await authGoogle.addPrivilege(testPrivilege)
128
+ await authGoogle.addAdmin(adminPayload)
129
+
130
+ const [privilege] = await authGoogle.getAllPrivileges()
131
+
132
+ await authGoogle.assignAdminPrivilege(adminPayload.email, privilege.id)
133
+
134
+ const hasPrivilege = await authGoogle.checkAdminHasRequiredPrivilege(adminPayload.email, privilege.name)
135
+ assert.deepStrictEqual(hasPrivilege, true)
136
+
137
+ const missingPrivilege = await authGoogle.checkAdminHasRequiredPrivilege(adminPayload.email, 'INVALID:PRIVILEGE')
138
+ assert.deepStrictEqual(missingPrivilege, false)
139
+ })
140
+
141
+ it('deleting a privilege should cascade and unassign the associated assigned privileges', async () => {
142
+ await authGoogle.addPrivilege(testPrivilege)
143
+ await authGoogle.addAdmin(adminPayload)
144
+
145
+ const [privilege] = await authGoogle.getAllPrivileges()
146
+
147
+ await authGoogle.assignAdminPrivilege(adminPayload.email, privilege.id)
148
+
149
+ const hasPrivilege = await authGoogle.checkAdminHasRequiredPrivilege(adminPayload.email, privilege.name)
150
+ assert.deepStrictEqual(hasPrivilege, true)
151
+
152
+ const runSqlFn = promisify(authGoogle.db.run.bind(authGoogle.db))
153
+ await runSqlFn(`DELETE FROM ${PrivilegeRepository.tableName} WHERE id=?`, [privilege.id])
154
+
155
+ {
156
+ const hasPrivilege = await authGoogle.checkAdminHasRequiredPrivilege(adminPayload.email, privilege.name)
157
+ assert.deepStrictEqual(hasPrivilege, false)
158
+ }
159
+ })
160
+ })
package/test/unit.js CHANGED
@@ -9,11 +9,20 @@ const path = require('path')
9
9
  const conf = require('./config/facs/auth-google.config')
10
10
 
11
11
  const AuthGoogle = require('../')
12
- const { omit } = require('@bitfinexcom/lib-js-util-base')
12
+ const { omit } = require('@bitfinex/lib-js-util-base')
13
13
 
14
14
  const dbPath = path.join(__dirname, './db/')
15
15
  const ctx = { root: './test' }
16
- const caller = { ctx }
16
+
17
+ const mongoFac = {
18
+ db: {
19
+ collection: () => ({
20
+ insertOne: (query, cb) => cb(null, query)
21
+ })
22
+ }
23
+ }
24
+
25
+ const caller = { ctx, dbMongo_m0: mongoFac }
17
26
  const authGoogle = new AuthGoogle(caller, { conf }, ctx)
18
27
 
19
28
  const cleanup = () => {
@@ -24,14 +33,17 @@ const cleanup = () => {
24
33
 
25
34
  const testForms = ['passport', 'bank_statement', 'merchant']
26
35
  const testAdminEmail = 'testForms@admin.com'
27
- const testAdminWithForms = {
36
+ const adminPayload = {
28
37
  email: testAdminEmail,
29
38
  password: 'test123',
30
- level: 0,
39
+ level: 0
40
+ }
41
+ const testAdminWithForms = {
42
+ ...adminPayload,
31
43
  forms: testForms
32
44
  }
33
45
 
34
- describe('forms field', () => {
46
+ describe('Admin Users', () => {
35
47
  beforeEach(async () => {
36
48
  cleanup()
37
49
  await new Promise((resolve) => authGoogle.start(resolve))
@@ -42,7 +54,8 @@ describe('forms field', () => {
42
54
  })
43
55
 
44
56
  it('should add admin and stringify forms field', async () => {
45
- await authGoogle.addAdmin(testAdminWithForms)
57
+ const admin = await authGoogle.addAdmin(testAdminWithForms)
58
+ assert.strictEqual(typeof admin.id, 'number', 'admin id should be defined')
46
59
 
47
60
  await new Promise((resolve) => authGoogle.db.get('SELECT * FROM admin_users WHERE email=?', [testAdminEmail], (err, row) => {
48
61
  if (err) throw err
@@ -59,14 +72,54 @@ describe('forms field', () => {
59
72
  assert.deepEqual(res.forms, testForms)
60
73
  })
61
74
 
62
- describe('getAdmin', () => {
63
- const adminPayload = {
64
- email: testAdminEmail,
65
- password: 'test123',
66
- level: 0
75
+ describe('loginAdmin', () => {
76
+ it('should pass error AUTH_FAC_ACCOUNT_IS_NOT_VALID to callback when internal validation of google auth credentials throws an exception', async () => {
77
+ let errMsg = null
78
+ const args = { google: { credential: 'invalid credential' } }
79
+ const cb = (e) => {
80
+ errMsg = e.message
81
+ }
82
+ await authGoogle.loginAdmin(args, cb)
83
+ assert.strictEqual(errMsg, 'AUTH_FAC_ACCOUNT_IS_NOT_VALID')
84
+ }).timeout(5000)
85
+ })
86
+
87
+ it('updateAdmin should validate passwordResetToken', async () => {
88
+ await authGoogle.addAdmin(adminPayload)
89
+ try {
90
+ await authGoogle.updateAdmin(adminPayload.email, { passwordResetToken: 40 })
91
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
92
+ } catch (err) {
93
+ assert.strictEqual(err.message, 'passwordResetToken should be a string')
94
+ }
95
+
96
+ try {
97
+ await authGoogle.updateAdmin(adminPayload.email, { passwordResetToken: false })
98
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
99
+ } catch (err) {
100
+ assert.strictEqual(err.message, 'passwordResetToken should be a string')
101
+ }
102
+
103
+ const update = await authGoogle.updateAdmin(adminPayload.email, { passwordResetToken: 'sample_token' })
104
+ assert.strictEqual(update.passwordResetToken, 'sample_token')
105
+ })
106
+
107
+ it('updateAdmin should validate passwordResetSentAt', async () => {
108
+ await authGoogle.addAdmin(adminPayload)
109
+ try {
110
+ await authGoogle.updateAdmin(adminPayload.email, { passwordResetSentAt: 'invalid date' })
111
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
112
+ } catch (err) {
113
+ assert.strictEqual(err.message, 'passwordResetSentAt should be a valid date')
67
114
  }
68
115
 
69
- const hasJustBeenCreated = payload => assert.ok(Date.now() - new Date(payload.timestamp) < 1000)
116
+ const now = new Date().toISOString()
117
+ const update = await authGoogle.updateAdmin(adminPayload.email, { passwordResetSentAt: now })
118
+ assert.strictEqual(update.passwordResetSentAt, now)
119
+ })
120
+
121
+ describe('getAdmin', () => {
122
+ const hasJustBeenCreated = payload => assert.ok(Date.now() - new Date(payload.timestamp + 'Z').getTime() < 1000)
70
123
 
71
124
  const assertions = (getAdminResult, expectedActive = true) => {
72
125
  assert.equal(getAdminResult.email, adminPayload.email)
@@ -197,4 +250,230 @@ describe('forms field', () => {
197
250
  assert.ok(!res)
198
251
  })
199
252
  })
253
+
254
+ describe('whitelistedIps field', () => {
255
+ const ips = ['192.168.1.1', '10.0.0.5']
256
+ const adminWithIps = {
257
+ email: testAdminEmail,
258
+ password: 'test123',
259
+ level: 0,
260
+ whitelistedIps: ips
261
+ }
262
+
263
+ it('should add admin and stringify whitelistedIps in the DB', async () => {
264
+ await authGoogle.addAdmin(adminWithIps)
265
+
266
+ await new Promise((resolve) => authGoogle.db.get('SELECT * FROM admin_users WHERE email=?', [testAdminEmail], (err, row) => {
267
+ if (err) throw err
268
+ assert.equal(row.whitelistedIps, JSON.stringify(ips))
269
+ resolve()
270
+ }))
271
+ })
272
+
273
+ it('should return whitelistedIps as a parsed array from getAdmin', async () => {
274
+ await authGoogle.addAdmin(adminWithIps)
275
+
276
+ const res = await authGoogle.getAdmin(testAdminEmail)
277
+
278
+ assert.deepEqual(res.whitelistedIps, ips)
279
+ })
280
+
281
+ it('should return undefined whitelistedIps when not set on admin', async () => {
282
+ await authGoogle.addAdmin({ email: testAdminEmail, password: 'test123', level: 0 })
283
+
284
+ const res = await authGoogle.getAdmin(testAdminEmail)
285
+
286
+ assert.equal(res.whitelistedIps, undefined)
287
+ })
288
+
289
+ it('should throw when adding admin with whitelistedIps not being an array', async () => {
290
+ try {
291
+ await authGoogle.addAdmin({ ...adminWithIps, whitelistedIps: '192.168.1.1' })
292
+ throw new Error('SHOULD_NOT_REACH_HERE')
293
+ } catch (e) {
294
+ assert.ok(e instanceof assert.AssertionError)
295
+ assert.strictEqual(e.message, 'whitelistedIps should be an array')
296
+ }
297
+ })
298
+
299
+ it('should update whitelistedIps and return the new list from getAdmin', async () => {
300
+ await authGoogle.addAdmin(adminWithIps)
301
+ const adminBeforeUpdate = await authGoogle.getAdmin(testAdminEmail)
302
+ assert.deepEqual(adminBeforeUpdate.whitelistedIps, ips)
303
+
304
+ const updatedIps = ['203.0.113.10']
305
+ await authGoogle.updateAdmin(testAdminEmail, { whitelistedIps: updatedIps })
306
+
307
+ const adminAfterUpdate = await authGoogle.getAdmin(testAdminEmail)
308
+ assert.deepEqual(adminAfterUpdate.whitelistedIps, updatedIps)
309
+ })
310
+ })
311
+
312
+ it('updateAdminPassword should change the user password if the old password is valid', async () => {
313
+ await authGoogle.addAdmin({ ...adminPayload })
314
+
315
+ let resp
316
+ const cb = (_, res) => {
317
+ resp = res
318
+ }
319
+ await authGoogle.loginAdmin({
320
+ user: {
321
+ username: adminPayload.email,
322
+ password: adminPayload.password
323
+ }
324
+ }, cb)
325
+ assert.strictEqual(resp.username, adminPayload.email)
326
+ assert.strictEqual(typeof resp.token, 'string')
327
+ assert.strictEqual(typeof resp.password, 'undefined')
328
+ assert.strictEqual(typeof resp.id, 'number')
329
+ assert.ok(resp.active)
330
+ assert.ok(Array.isArray(resp.privileges))
331
+
332
+ const passwordResetToken = 'sample_token'
333
+ const newPassword = 'newPassword'
334
+ assert.ok(adminPayload.password !== newPassword)
335
+ const successful = await authGoogle.updateAdminPassword(adminPayload.email, newPassword, adminPayload.password)
336
+ assert.strictEqual(successful, true)
337
+
338
+ await authGoogle.loginAdmin({
339
+ user: {
340
+ username: adminPayload.email,
341
+ password: newPassword
342
+ }
343
+ }, cb)
344
+ assert.strictEqual(resp.username, adminPayload.email)
345
+ assert.strictEqual(typeof resp.token, 'string')
346
+ assert.strictEqual(typeof resp.password, 'undefined')
347
+ assert.strictEqual(typeof resp.id, 'number')
348
+ assert.ok(resp.active)
349
+ assert.ok(Array.isArray(resp.privileges))
350
+ })
351
+
352
+ it('updateAdminPassword should validate the params', async () => {
353
+ try {
354
+ await authGoogle.updateAdminPassword(1)
355
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
356
+ } catch (err) {
357
+ assert.strictEqual(err.message, 'Email is required')
358
+ }
359
+
360
+ try {
361
+ await authGoogle.updateAdminPassword(adminPayload.email)
362
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
363
+ } catch (err) {
364
+ assert.strictEqual(err.message, 'New Password is required')
365
+ }
366
+
367
+ try {
368
+ await authGoogle.updateAdminPassword(adminPayload.email, 'newPassword')
369
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
370
+ } catch (err) {
371
+ assert.strictEqual(err.message, 'Old Password is required')
372
+ }
373
+
374
+ try {
375
+ await authGoogle.updateAdminPassword(adminPayload.email, 'newPassword', adminPayload.password)
376
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
377
+ } catch (err) {
378
+ assert.strictEqual(err.message, 'ADMIN_ACCOUNT_DOES_NOT_EXIST_OR_IS_NOT_ACTIVE')
379
+ }
380
+
381
+ await authGoogle.addAdmin({ ...adminPayload })
382
+
383
+ try {
384
+ await authGoogle.updateAdminPassword(adminPayload.email, 'newPassword', 'wrongPassword')
385
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
386
+ } catch (err) {
387
+ assert.strictEqual(err.message, 'INVALID_PASSWORD')
388
+ }
389
+ })
390
+
391
+ it('resetPassword should reset the user password if the token is valid', async () => {
392
+ await authGoogle.addAdmin({ ...adminPayload })
393
+
394
+ let resp
395
+ const cb = (_, res) => {
396
+ resp = res
397
+ }
398
+ await authGoogle.loginAdmin({
399
+ user: {
400
+ username: adminPayload.email,
401
+ password: adminPayload.password
402
+ }
403
+ }, cb)
404
+ assert.strictEqual(resp.username, adminPayload.email)
405
+ assert.strictEqual(typeof resp.token, 'string')
406
+ assert.strictEqual(typeof resp.password, 'undefined')
407
+ assert.strictEqual(typeof resp.id, 'number')
408
+ assert.ok(resp.active)
409
+ assert.ok(Array.isArray(resp.privileges))
410
+
411
+ const passwordResetToken = 'sample_token'
412
+ const update = await authGoogle.updateAdmin(adminPayload.email, { passwordResetToken, passwordResetSentAt: new Date().toISOString() })
413
+ assert.strictEqual(update.passwordResetToken, 'sample_token')
414
+
415
+ const newPassword = 'newPassword'
416
+ assert.ok(adminPayload.password !== newPassword)
417
+ const successful = await authGoogle.resetAdminPassword(adminPayload.email, newPassword, passwordResetToken)
418
+ assert.strictEqual(successful, true)
419
+
420
+ await authGoogle.loginAdmin({
421
+ user: {
422
+ username: adminPayload.email,
423
+ password: newPassword
424
+ }
425
+ }, cb)
426
+ assert.strictEqual(resp.username, adminPayload.email)
427
+ assert.strictEqual(typeof resp.token, 'string')
428
+ assert.strictEqual(typeof resp.password, 'undefined')
429
+ assert.strictEqual(typeof resp.id, 'number')
430
+ assert.ok(resp.active)
431
+ assert.ok(Array.isArray(resp.privileges))
432
+ })
433
+
434
+ it('resetPassword should validate the params', async () => {
435
+ try {
436
+ await authGoogle.resetAdminPassword(1)
437
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
438
+ } catch (err) {
439
+ assert.strictEqual(err.message, 'Email is required')
440
+ }
441
+
442
+ try {
443
+ await authGoogle.resetAdminPassword(adminPayload.email)
444
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
445
+ } catch (err) {
446
+ assert.strictEqual(err.message, 'New Password is required')
447
+ }
448
+
449
+ const passwordResetToken = 'sample_token'
450
+ try {
451
+ await authGoogle.resetAdminPassword(adminPayload.email, 'newPassword', passwordResetToken)
452
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
453
+ } catch (err) {
454
+ assert.strictEqual(err.message, 'ADMIN_ACCOUNT_DOES_NOT_EXIST_OR_IS_NOT_ACTIVE')
455
+ }
456
+
457
+ await authGoogle.addAdmin({ ...adminPayload })
458
+
459
+ try {
460
+ await authGoogle.resetAdminPassword(adminPayload.email, 'newPassword', passwordResetToken)
461
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
462
+ } catch (err) {
463
+ assert.strictEqual(err.message, 'INVALID_passwordResetToken')
464
+ }
465
+
466
+ const update = await authGoogle.updateAdmin(adminPayload.email, {
467
+ passwordResetToken,
468
+ passwordResetSentAt: new Date(2020, 1, 1).toISOString() // expired date
469
+ })
470
+ assert.strictEqual(update.passwordResetToken, 'sample_token')
471
+
472
+ try {
473
+ await authGoogle.resetAdminPassword(adminPayload.email, 'newPassword', passwordResetToken)
474
+ throw new Error('SHOULD_NOT_REACH_THIS_POINT')
475
+ } catch (err) {
476
+ assert.strictEqual(err.message, 'RESET_LINK_EXPIRED')
477
+ }
478
+ })
200
479
  })