@bitfinex/bfx-facs-auth-google 1.2.3
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/LICENSE +202 -0
- package/README.md +49 -0
- package/auth-google.config.json.example +40 -0
- package/errors.js +13 -0
- package/index.js +896 -0
- package/migrations.js +63 -0
- package/package.json +58 -0
- package/test/config/facs/auth-google.config.json +49 -0
- package/test/unit.js +200 -0
- package/upstream-merge.sh +2 -0
package/migrations.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const tableName = 'admin_users'
|
|
4
|
+
|
|
5
|
+
const migrations = [
|
|
6
|
+
(_this, cb) => {
|
|
7
|
+
_this.db.all(`PRAGMA table_info(${tableName})`, [], (err, rows) => {
|
|
8
|
+
if (err) return cb(err)
|
|
9
|
+
if (rows?.find(row => row.name === 'manageAdminsPrivilege')) return cb()
|
|
10
|
+
|
|
11
|
+
_this.db.run(`
|
|
12
|
+
ALTER TABLE ${tableName}
|
|
13
|
+
ADD manageAdminsPrivilege TINYINTEGER
|
|
14
|
+
`, cb)
|
|
15
|
+
})
|
|
16
|
+
},
|
|
17
|
+
(_this, cb) => {
|
|
18
|
+
_this.db.all(`PRAGMA table_info(${tableName})`, [], (err, rows) => {
|
|
19
|
+
if (err) return cb(err)
|
|
20
|
+
if (rows?.find(row => row.name === 'forms')) return cb()
|
|
21
|
+
|
|
22
|
+
_this.db.run(`
|
|
23
|
+
ALTER TABLE ${tableName}
|
|
24
|
+
ADD forms TEXT
|
|
25
|
+
`, cb)
|
|
26
|
+
})
|
|
27
|
+
},
|
|
28
|
+
(_this, cb) => {
|
|
29
|
+
_this.db.all(`PRAGMA table_info(${tableName})`, [], (err, rows) => {
|
|
30
|
+
if (err) return cb(err)
|
|
31
|
+
if (rows?.find(row => row.name === 'passwordResetSentAt')) return cb()
|
|
32
|
+
|
|
33
|
+
_this.db.run(`
|
|
34
|
+
ALTER TABLE ${tableName}
|
|
35
|
+
ADD passwordResetSentAt DATETIME
|
|
36
|
+
`, cb)
|
|
37
|
+
})
|
|
38
|
+
},
|
|
39
|
+
(_this, cb) => {
|
|
40
|
+
_this.db.all(`PRAGMA table_info(${tableName})`, [], (err, rows) => {
|
|
41
|
+
if (err) return cb(err)
|
|
42
|
+
if (rows?.find(row => row.name === 'passwordResetToken')) return cb()
|
|
43
|
+
|
|
44
|
+
_this.db.run(`
|
|
45
|
+
ALTER TABLE ${tableName}
|
|
46
|
+
ADD passwordResetToken TEXT
|
|
47
|
+
`, cb)
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
(_this, cb) => {
|
|
51
|
+
_this.db.all(`PRAGMA table_info(${tableName})`, [], (err, rows) => {
|
|
52
|
+
if (err) return cb(err)
|
|
53
|
+
if (rows?.find(row => row.name === 'fetchMotivationsPrivilege')) return cb()
|
|
54
|
+
|
|
55
|
+
_this.db.run(`
|
|
56
|
+
ALTER TABLE ${tableName}
|
|
57
|
+
ADD fetchMotivationsPrivilege BOOLEAN
|
|
58
|
+
`, cb)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
module.exports = migrations
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bitfinex/bfx-facs-auth-google",
|
|
3
|
+
"version": "1.2.3",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Bitfinex Google Oauth Facility",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "face",
|
|
8
|
+
"email": "rama@bitfinex.com"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"bitfinex",
|
|
12
|
+
"oath"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@bitfinex/bfx-facs-base": "git+https://github.com/bitfinexcom/bfx-facs-base.git",
|
|
16
|
+
"@bitfinex/bfx-facs-db-sqlite": "git+https://github.com/bitfinexcom/bfx-facs-db-sqlite.git",
|
|
17
|
+
"@bitfinexcom/lib-js-util-base": "git+https://github.com/bitfinexcom/lib-js-util-base.git",
|
|
18
|
+
"async": "^2.6.4",
|
|
19
|
+
"googleapis": "^68.0.0",
|
|
20
|
+
"lodash": "^4.17.21",
|
|
21
|
+
"uuid": "^3.2.1"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=16.0"
|
|
25
|
+
},
|
|
26
|
+
"main": "index.js",
|
|
27
|
+
"license": "Apache-2.0",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/bitfinexcom/bfx-facs-auth-google.git"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/bitfinexcom/bfx-facs-auth-google",
|
|
33
|
+
"maintainers": [
|
|
34
|
+
{
|
|
35
|
+
"name": "face",
|
|
36
|
+
"email": "<rama@bitfinex.com>"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "Ezequiel Wernicke",
|
|
40
|
+
"email": "<ezequiel.wernicke@bitfinex.com>"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "prdn",
|
|
44
|
+
"email": "paolo@bitfinex.com"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"test": "npm run lint && npm run unit",
|
|
49
|
+
"unit": "mocha",
|
|
50
|
+
"lint": "standard",
|
|
51
|
+
"lintFix": "standard --fix index.js",
|
|
52
|
+
"startSimulatedEnviroment": "node test/simulate/simulate-enviroment.js"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"mocha": "^10.2.0",
|
|
56
|
+
"standard": "^17.1.0"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"google" : {
|
|
3
|
+
"clientId": "test-client-id",
|
|
4
|
+
"clientSecret": "test-client-secret"
|
|
5
|
+
},
|
|
6
|
+
"ADM_USERS" : [
|
|
7
|
+
{
|
|
8
|
+
"email": "adm1@bitfinex.com",
|
|
9
|
+
"password": "example123",
|
|
10
|
+
"level": 0
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"email": "adm2@bitfinex.com",
|
|
14
|
+
"password": "example123",
|
|
15
|
+
"level": 0
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"email": "adm3@bitfinex.com",
|
|
19
|
+
"password": "example123",
|
|
20
|
+
"level": 0
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"email": "adm4@bitfinex.com",
|
|
24
|
+
"password": "example123",
|
|
25
|
+
"level": 0
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"email": "admL0@bitfinex.com",
|
|
29
|
+
"password": "example123",
|
|
30
|
+
"level": 0
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"email": "admL1@bitfinex.com",
|
|
34
|
+
"password": "example123",
|
|
35
|
+
"level": 1
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"email": "admL2@bitfinex.com",
|
|
39
|
+
"password": "example123",
|
|
40
|
+
"level": 2
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"email": "google@bitfinex.com",
|
|
44
|
+
"password": false,
|
|
45
|
+
"level": 0
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"useDB": true
|
|
49
|
+
}
|
package/test/unit.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
'use strict'
|
|
4
|
+
|
|
5
|
+
const assert = require('assert')
|
|
6
|
+
const fs = require('fs')
|
|
7
|
+
const path = require('path')
|
|
8
|
+
|
|
9
|
+
const conf = require('./config/facs/auth-google.config')
|
|
10
|
+
|
|
11
|
+
const AuthGoogle = require('../')
|
|
12
|
+
const { omit } = require('@bitfinexcom/lib-js-util-base')
|
|
13
|
+
|
|
14
|
+
const dbPath = path.join(__dirname, './db/')
|
|
15
|
+
const ctx = { root: './test' }
|
|
16
|
+
const caller = { ctx }
|
|
17
|
+
const authGoogle = new AuthGoogle(caller, { conf }, ctx)
|
|
18
|
+
|
|
19
|
+
const cleanup = () => {
|
|
20
|
+
if (fs.existsSync(dbPath)) {
|
|
21
|
+
fs.rmSync(dbPath, { recursive: true, force: true })
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const testForms = ['passport', 'bank_statement', 'merchant']
|
|
26
|
+
const testAdminEmail = 'testForms@admin.com'
|
|
27
|
+
const testAdminWithForms = {
|
|
28
|
+
email: testAdminEmail,
|
|
29
|
+
password: 'test123',
|
|
30
|
+
level: 0,
|
|
31
|
+
forms: testForms
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('forms field', () => {
|
|
35
|
+
beforeEach(async () => {
|
|
36
|
+
cleanup()
|
|
37
|
+
await new Promise((resolve) => authGoogle.start(resolve))
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
afterEach(async () => {
|
|
41
|
+
await new Promise((resolve) => authGoogle.stop(resolve))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should add admin and stringify forms field', async () => {
|
|
45
|
+
await authGoogle.addAdmin(testAdminWithForms)
|
|
46
|
+
|
|
47
|
+
await new Promise((resolve) => authGoogle.db.get('SELECT * FROM admin_users WHERE email=?', [testAdminEmail], (err, row) => {
|
|
48
|
+
if (err) throw err
|
|
49
|
+
assert.equal(row.forms, JSON.stringify(testForms))
|
|
50
|
+
resolve()
|
|
51
|
+
}))
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should return admin and with parsed form fields', async () => {
|
|
55
|
+
await authGoogle.addAdmin(testAdminWithForms)
|
|
56
|
+
|
|
57
|
+
const res = await authGoogle.getAdmin(testAdminEmail)
|
|
58
|
+
|
|
59
|
+
assert.deepEqual(res.forms, testForms)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
describe('getAdmin', () => {
|
|
63
|
+
const adminPayload = {
|
|
64
|
+
email: testAdminEmail,
|
|
65
|
+
password: 'test123',
|
|
66
|
+
level: 0
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const hasJustBeenCreated = payload => assert.ok(Date.now() - new Date(payload.timestamp) < 1000)
|
|
70
|
+
|
|
71
|
+
const assertions = (getAdminResult, expectedActive = true) => {
|
|
72
|
+
assert.equal(getAdminResult.email, adminPayload.email)
|
|
73
|
+
assert.equal(getAdminResult.level, adminPayload.level)
|
|
74
|
+
assert.equal(getAdminResult.active, expectedActive)
|
|
75
|
+
hasJustBeenCreated(getAdminResult)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
it('should get active admin', async () => {
|
|
79
|
+
await authGoogle.addAdmin(adminPayload)
|
|
80
|
+
|
|
81
|
+
const getAdminResult = await authGoogle.getAdmin(adminPayload.email)
|
|
82
|
+
|
|
83
|
+
assertions(getAdminResult)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should not get inactive admin', async () => {
|
|
87
|
+
await authGoogle.addAdmin(adminPayload)
|
|
88
|
+
await authGoogle.updateAdmin(adminPayload.email, { active: false })
|
|
89
|
+
|
|
90
|
+
const getAdminResult = await authGoogle.getAdmin(adminPayload.email)
|
|
91
|
+
|
|
92
|
+
assert.equal(getAdminResult, undefined)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should get inactive admin', async () => {
|
|
96
|
+
await authGoogle.addAdmin(adminPayload)
|
|
97
|
+
await authGoogle.updateAdmin(adminPayload.email, { active: false })
|
|
98
|
+
|
|
99
|
+
const getAdminResult = await authGoogle.getAdmin(adminPayload.email, false)
|
|
100
|
+
|
|
101
|
+
assertions(getAdminResult, false)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should get admin using uppercased email', async () => {
|
|
105
|
+
await authGoogle.addAdmin(adminPayload)
|
|
106
|
+
|
|
107
|
+
const getAdminResult = await authGoogle.getAdmin(adminPayload.email.toUpperCase())
|
|
108
|
+
|
|
109
|
+
assertions(getAdminResult)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('should get admin using id', async () => {
|
|
113
|
+
const adminCreationResult = await authGoogle.addAdmin(adminPayload)
|
|
114
|
+
|
|
115
|
+
const getAdminResult = await authGoogle.getAdmin(adminCreationResult.id, true, true)
|
|
116
|
+
|
|
117
|
+
assertions(getAdminResult)
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
describe('fetchMotivationsPrivilege permission', () => {
|
|
122
|
+
it('should add admin successfully with fetchMotivationsPrivilege', async () => {
|
|
123
|
+
await authGoogle.addAdmin({
|
|
124
|
+
...testAdminWithForms,
|
|
125
|
+
fetchMotivationsPrivilege: true
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const res = await authGoogle.getAdmin(testAdminEmail)
|
|
129
|
+
|
|
130
|
+
assert.strictEqual(res.fetchMotivationsPrivilege, 1)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('should throw error when adding admin with fetchMotivationsPrivilege not being boolean', async () => {
|
|
134
|
+
try {
|
|
135
|
+
await authGoogle.addAdmin({
|
|
136
|
+
...testAdminWithForms,
|
|
137
|
+
fetchMotivationsPrivilege: 'not boolean'
|
|
138
|
+
})
|
|
139
|
+
throw new Error('SHOULD_NOT_REACH_HERE')
|
|
140
|
+
} catch (e) {
|
|
141
|
+
assert.ok(e instanceof assert.AssertionError)
|
|
142
|
+
assert.strictEqual(e.message, 'fetchMotivationsPrivilege should be a boolean')
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should edit admin successfully with fetchMotivationsPrivilege', async () => {
|
|
147
|
+
await authGoogle.addAdmin(testAdminWithForms)
|
|
148
|
+
const adminBeforeUpdate = await authGoogle.getAdmin(testAdminEmail)
|
|
149
|
+
assert.ok(!adminBeforeUpdate.fetchMotivationsPrivilege)
|
|
150
|
+
|
|
151
|
+
await authGoogle.updateAdmin(testAdminEmail, {
|
|
152
|
+
...omit(testAdminWithForms, ['email', 'password', 'forms']),
|
|
153
|
+
fetchMotivationsPrivilege: true
|
|
154
|
+
})
|
|
155
|
+
const adminAfterUpdate = await authGoogle.getAdmin(testAdminEmail)
|
|
156
|
+
assert.strictEqual(adminAfterUpdate.fetchMotivationsPrivilege, 1)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should throw error when editing admin with fetchMotivationsPrivilege not being boolean', async () => {
|
|
160
|
+
await authGoogle.addAdmin(testAdminWithForms)
|
|
161
|
+
const adminBeforeUpdate = await authGoogle.getAdmin(testAdminEmail)
|
|
162
|
+
assert.ok(!adminBeforeUpdate.fetchMotivationsPrivilege)
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await authGoogle.updateAdmin(testAdminEmail, {
|
|
166
|
+
...omit(testAdminWithForms, ['email', 'password', 'forms']),
|
|
167
|
+
fetchMotivationsPrivilege: 'not boolean'
|
|
168
|
+
})
|
|
169
|
+
throw new Error('SHOULD_NOT_REACH_HERE')
|
|
170
|
+
} catch (e) {
|
|
171
|
+
assert.ok(e instanceof assert.AssertionError)
|
|
172
|
+
assert.strictEqual(e.message, 'fetchMotivationsPrivilege should be a boolean')
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('should return true when admin has fetch motivations privilege', async () => {
|
|
177
|
+
await authGoogle.addAdmin({
|
|
178
|
+
...testAdminWithForms,
|
|
179
|
+
level: 1,
|
|
180
|
+
fetchMotivationsPrivilege: true
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const res = await authGoogle.checkAdmHasFetchMotivationsPrivilege(testAdminEmail)
|
|
184
|
+
|
|
185
|
+
assert.ok(res)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should return false when admin does not have fetch motivations privilege', async () => {
|
|
189
|
+
await authGoogle.addAdmin({
|
|
190
|
+
...testAdminWithForms,
|
|
191
|
+
level: 1,
|
|
192
|
+
fetchMotivationsPrivilege: false
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
const res = await authGoogle.checkAdmHasFetchMotivationsPrivilege(testAdminEmail)
|
|
196
|
+
|
|
197
|
+
assert.ok(!res)
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
})
|