@friggframework/core 2.0.0-next.43 → 2.0.0-next.45

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.
Files changed (38) hide show
  1. package/database/config.js +29 -1
  2. package/database/use-cases/test-encryption-use-case.js +6 -5
  3. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  4. package/handlers/WEBHOOKS.md +653 -0
  5. package/handlers/backend-utils.js +118 -3
  6. package/handlers/integration-event-dispatcher.test.js +68 -0
  7. package/handlers/routers/integration-webhook-routers.js +67 -0
  8. package/handlers/routers/integration-webhook-routers.test.js +126 -0
  9. package/handlers/webhook-flow.integration.test.js +356 -0
  10. package/handlers/workers/integration-defined-workers.test.js +184 -0
  11. package/index.js +16 -0
  12. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  13. package/integrations/integration-base.js +74 -3
  14. package/integrations/repositories/process-repository-factory.js +46 -0
  15. package/integrations/repositories/process-repository-interface.js +90 -0
  16. package/integrations/repositories/process-repository-mongo.js +190 -0
  17. package/integrations/repositories/process-repository-postgres.js +217 -0
  18. package/integrations/tests/doubles/dummy-integration-class.js +1 -8
  19. package/integrations/use-cases/create-process.js +128 -0
  20. package/integrations/use-cases/create-process.test.js +178 -0
  21. package/integrations/use-cases/get-process.js +87 -0
  22. package/integrations/use-cases/get-process.test.js +190 -0
  23. package/integrations/use-cases/index.js +8 -0
  24. package/integrations/use-cases/update-process-metrics.js +201 -0
  25. package/integrations/use-cases/update-process-metrics.test.js +308 -0
  26. package/integrations/use-cases/update-process-state.js +119 -0
  27. package/integrations/use-cases/update-process-state.test.js +256 -0
  28. package/package.json +5 -5
  29. package/prisma-mongodb/schema.prisma +44 -0
  30. package/prisma-postgresql/schema.prisma +45 -0
  31. package/queues/queuer-util.js +10 -0
  32. package/user/repositories/user-repository-mongo.js +53 -12
  33. package/user/repositories/user-repository-postgres.js +53 -14
  34. package/user/tests/use-cases/login-user.test.js +85 -5
  35. package/user/tests/user-password-encryption-isolation.test.js +237 -0
  36. package/user/tests/user-password-hashing.test.js +235 -0
  37. package/user/use-cases/login-user.js +1 -1
  38. package/user/user.js +2 -2
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Password Encryption Isolation Test
3
+ *
4
+ * Verifies that password hashing is completely isolated from the encryption system.
5
+ * Tests that passwords are bcrypt hashed regardless of encryption configuration.
6
+ *
7
+ * Key Tests:
8
+ * - With encryption ENABLED: passwords hashed (not encrypted)
9
+ * - With encryption DISABLED: passwords still hashed
10
+ * - Encryption schema does NOT include User.hashword
11
+ * - Side-by-side: tokens encrypted, passwords hashed
12
+ */
13
+
14
+ // Set default DATABASE_URL for testing if not already set
15
+ if (!process.env.DATABASE_URL) {
16
+ process.env.DATABASE_URL = 'mongodb://localhost:27017/frigg?replicaSet=rs0';
17
+ }
18
+
19
+ // Enable encryption for testing (bypass test stage check)
20
+ process.env.STAGE = 'integration-test';
21
+ process.env.AES_KEY_ID = 'test-key-id';
22
+ process.env.AES_KEY = 'test-aes-key-32-characters-long!';
23
+
24
+ jest.mock('../../database/config', () => ({
25
+ DB_TYPE: 'mongodb',
26
+ getDatabaseType: jest.fn(() => 'mongodb'),
27
+ PRISMA_LOG_LEVEL: 'error,warn',
28
+ PRISMA_QUERY_LOGGING: false,
29
+ }));
30
+
31
+ const bcrypt = require('bcryptjs');
32
+ const { createUserRepository } = require('../repositories/user-repository-factory');
33
+ const { prisma, connectPrisma, disconnectPrisma, getEncryptionConfig } = require('../../database/prisma');
34
+ const { getEncryptedFields, hasEncryptedFields } = require('../../database/encryption/encryption-schema-registry');
35
+ const { mongoose } = require('../../database/mongoose');
36
+
37
+ describe('Password Encryption Isolation', () => {
38
+ const dbType = process.env.DB_TYPE || 'mongodb';
39
+ let userRepository;
40
+ let testUserIds = [];
41
+ const TEST_PASSWORD = 'IsolationTestPassword123!';
42
+
43
+ beforeAll(async () => {
44
+ await connectPrisma();
45
+ // Connect mongoose for raw database queries
46
+ if (mongoose.connection.readyState === 0) {
47
+ await mongoose.connect(process.env.DATABASE_URL);
48
+ }
49
+ userRepository = createUserRepository();
50
+ }, 30000); // 30 second timeout for database connection
51
+
52
+ afterAll(async () => {
53
+ for (const userId of testUserIds) {
54
+ await userRepository.deleteUser(userId).catch(() => {});
55
+ }
56
+ await mongoose.disconnect();
57
+ await disconnectPrisma();
58
+ }, 30000); // 30 second timeout for cleanup
59
+
60
+ test('āœ… Encryption schema does NOT include User.hashword', () => {
61
+ const userEncryptedFields = getEncryptedFields('User');
62
+
63
+ console.log('\nšŸ“‹ User model encrypted fields:', userEncryptedFields);
64
+
65
+ expect(userEncryptedFields).toBeDefined();
66
+ expect(Array.isArray(userEncryptedFields)).toBe(true);
67
+ expect(userEncryptedFields).not.toContain('hashword');
68
+
69
+ if (userEncryptedFields.length > 0) {
70
+ console.log('āš ļø WARNING: User model has encrypted fields:', userEncryptedFields);
71
+ console.log(' Password field (hashword) should NOT be in this list');
72
+ } else {
73
+ console.log('āœ… User model has no encrypted fields (as expected)');
74
+ }
75
+ });
76
+
77
+ test('āœ… Password is bcrypt hashed regardless of encryption config', async () => {
78
+ const encryptionConfig = getEncryptionConfig();
79
+ console.log('\nšŸ”’ Current encryption config:', encryptionConfig);
80
+
81
+ const username = `isolation-test-${Date.now()}`;
82
+ const user = await userRepository.createIndividualUser({
83
+ username,
84
+ hashword: TEST_PASSWORD,
85
+ email: `${username}@test.com`,
86
+ });
87
+ testUserIds.push(user.id);
88
+
89
+ expect(user.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
90
+ expect(user.hashword).not.toBe(TEST_PASSWORD);
91
+ expect(user.hashword).not.toContain(':');
92
+
93
+ const isValid = await bcrypt.compare(TEST_PASSWORD, user.hashword);
94
+ expect(isValid).toBe(true);
95
+
96
+ console.log('āœ… Password correctly hashed with bcrypt');
97
+ console.log(' Encryption enabled:', encryptionConfig.enabled);
98
+ console.log(' Hashword format:', user.hashword.substring(0, 20) + '...');
99
+ });
100
+
101
+ test('šŸ“Š Field-level encryption status comparison', async () => {
102
+ const models = ['User', 'Credential', 'Token', 'IntegrationMapping'];
103
+
104
+ console.log('\nšŸ“Š ENCRYPTION SCHEMA ANALYSIS:');
105
+ console.log('='.repeat(60));
106
+
107
+ for (const model of models) {
108
+ const fields = getEncryptedFields(model);
109
+ const hasEncryption = hasEncryptedFields(model);
110
+
111
+ console.log(`\n${model}:`);
112
+ console.log(` Has encrypted fields: ${hasEncryption}`);
113
+ console.log(` Encrypted fields: ${fields.length > 0 ? fields.join(', ') : 'none'}`);
114
+
115
+ if (model === 'User') {
116
+ expect(fields).not.toContain('hashword');
117
+ console.log(' āœ… Password (hashword) correctly excluded from encryption');
118
+ } else if (model === 'Credential') {
119
+ expect(fields).toContain('data.access_token');
120
+ console.log(' āœ… API tokens correctly included in encryption');
121
+ }
122
+ }
123
+ });
124
+
125
+ test('šŸ“Š End-to-end: Create user + credential, verify isolation', async () => {
126
+ const username = `e2e-isolation-${Date.now()}`;
127
+ const secretToken = 'my-secret-api-token-xyz';
128
+
129
+ const user = await userRepository.createIndividualUser({
130
+ username,
131
+ hashword: TEST_PASSWORD,
132
+ email: `${username}@test.com`,
133
+ });
134
+ testUserIds.push(user.id);
135
+
136
+ const credential = await prisma.credential.create({
137
+ data: {
138
+ userId: dbType === 'postgresql' ? parseInt(user.id, 10) : user.id,
139
+ externalId: `cred-${Date.now()}`,
140
+ data: {
141
+ access_token: secretToken,
142
+ },
143
+ },
144
+ });
145
+
146
+ console.log('\nšŸ“Š END-TO-END ISOLATION TEST:');
147
+ console.log('='.repeat(60));
148
+
149
+ const fetchedUser = await userRepository.findIndividualUserById(user.id);
150
+ console.log('\nšŸ‘¤ User Password:');
151
+ console.log(' Format:', fetchedUser.hashword.substring(0, 30) + '...');
152
+ console.log(' Is bcrypt:', /^\$2[ab]\$\d{2}\$/.test(fetchedUser.hashword));
153
+ console.log(' Is encrypted (has :):', fetchedUser.hashword.includes(':'));
154
+
155
+ const fetchedCred = await prisma.credential.findUnique({
156
+ where: { id: credential.id },
157
+ });
158
+
159
+ console.log('\nšŸ”‘ Credential Token:');
160
+ const tokenValue = fetchedCred.data.access_token;
161
+ console.log(' Raw value:', tokenValue.substring(0, 50) + '...');
162
+ console.log(' Is encrypted (has :):', tokenValue.includes(':'));
163
+ console.log(' Equals plain text:', tokenValue === secretToken);
164
+
165
+ expect(fetchedUser.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
166
+ expect(fetchedUser.hashword).not.toContain(':');
167
+
168
+ const isPasswordValid = await bcrypt.compare(TEST_PASSWORD, fetchedUser.hashword);
169
+ expect(isPasswordValid).toBe(true);
170
+
171
+ console.log('\nāœ… Password: bcrypt hashed (NOT encrypted)');
172
+
173
+ const encryptionEnabled = tokenValue !== secretToken;
174
+ if (encryptionEnabled) {
175
+ console.log('āœ… Credential: properly encrypted');
176
+ expect(tokenValue).not.toBe(secretToken);
177
+ } else {
178
+ console.log('āš ļø Encryption disabled in this environment');
179
+ }
180
+
181
+ console.log('āœ… ISOLATION VERIFIED: Passwords use bcrypt, credentials use encryption');
182
+
183
+ await prisma.credential.delete({ where: { id: credential.id } });
184
+ });
185
+
186
+ test('šŸ” Bcrypt vs Encryption format analysis', () => {
187
+ const bcryptHash = '$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy';
188
+ const encryptedValue = 'kms:us-east-1:alias/app-key:AQICAHg...base64...';
189
+
190
+ console.log('\nšŸ” FORMAT COMPARISON:');
191
+ console.log('='.repeat(60));
192
+
193
+ console.log('\nBcrypt Hash Format:');
194
+ console.log(' Example:', bcryptHash);
195
+ console.log(' Pattern: $2[ab]$rounds$salt+hash');
196
+ console.log(' Length: ~60 chars');
197
+ console.log(' Colon count:', (bcryptHash.match(/:/g) || []).length);
198
+ console.log(' Dollar signs: 3');
199
+
200
+ console.log('\nEncryption Format:');
201
+ console.log(' Example:', encryptedValue.substring(0, 50) + '...');
202
+ console.log(' Pattern: method:region:keyId:base64Ciphertext');
203
+ console.log(' Colon separators: 3');
204
+ console.log(' Variable length');
205
+
206
+ console.log('\nāœ… Formats are clearly distinguishable');
207
+ console.log('āœ… Bcrypt never has colon separators between dollar signs');
208
+ console.log('āœ… Encryption always has exactly 3 colon separators');
209
+ });
210
+
211
+ test('āš ļø Verify password NOT double-processed', async () => {
212
+ const username = `double-process-test-${Date.now()}`;
213
+
214
+ const user = await userRepository.createIndividualUser({
215
+ username,
216
+ hashword: TEST_PASSWORD,
217
+ email: `${username}@test.com`,
218
+ });
219
+ testUserIds.push(user.id);
220
+
221
+ const hash1 = user.hashword;
222
+
223
+ const fetchedUser = await userRepository.findIndividualUserById(user.id);
224
+ const hash2 = fetchedUser.hashword;
225
+
226
+ console.log('\nāš ļø DOUBLE-PROCESSING CHECK:');
227
+ console.log('Hash after creation:', hash1.substring(0, 30) + '...');
228
+ console.log('Hash after fetch: ', hash2.substring(0, 30) + '...');
229
+ console.log('Hashes match:', hash1 === hash2);
230
+
231
+ expect(hash1).toBe(hash2);
232
+ expect(hash1).toMatch(/^\$2[ab]\$\d{2}\$/);
233
+ expect(hash2).toMatch(/^\$2[ab]\$\d{2}\$/);
234
+
235
+ console.log('āœ… No double-processing detected');
236
+ });
237
+ });
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Password Hashing Verification Test
3
+ *
4
+ * Verifies that passwords are correctly bcrypt hashed (NOT encrypted) throughout
5
+ * the user authentication flow. Tests both MongoDB and PostgreSQL.
6
+ *
7
+ * Expected Behavior:
8
+ * - Passwords hashed with bcrypt on creation (format: $2a$ or $2b$)
9
+ * - Password hashes stored as-is (NOT encrypted with KMS/AES)
10
+ * - bcrypt.compare() works correctly for authentication
11
+ * - Password updates also trigger bcrypt hashing
12
+ */
13
+
14
+ // Set default DATABASE_URL for testing if not already set
15
+ if (!process.env.DATABASE_URL) {
16
+ process.env.DATABASE_URL = 'mongodb://localhost:27017/frigg?replicaSet=rs0';
17
+ }
18
+
19
+ // Enable encryption for testing (bypass test stage check)
20
+ process.env.STAGE = 'integration-test';
21
+ process.env.AES_KEY_ID = 'test-key-id';
22
+ process.env.AES_KEY = 'test-aes-key-32-characters-long!';
23
+
24
+ jest.mock('../../database/config', () => ({
25
+ DB_TYPE: 'mongodb',
26
+ getDatabaseType: jest.fn(() => 'mongodb'),
27
+ PRISMA_LOG_LEVEL: 'error,warn',
28
+ PRISMA_QUERY_LOGGING: false,
29
+ }));
30
+
31
+ const bcrypt = require('bcryptjs');
32
+ const { LoginUser } = require('../use-cases/login-user');
33
+ const { createUserRepository } = require('../repositories/user-repository-factory');
34
+ const { prisma, connectPrisma, disconnectPrisma } = require('../../database/prisma');
35
+ const { mongoose } = require('../../database/mongoose');
36
+
37
+ describe('Password Hashing Verification - Both Databases', () => {
38
+ const dbType = process.env.DB_TYPE || 'mongodb';
39
+ let userRepository;
40
+ let testUserId;
41
+ const TEST_PASSWORD = 'MySecurePassword123!';
42
+ const TEST_USERNAME = `test-user-hash-${Date.now()}`;
43
+ const userConfig = {
44
+ usePassword: true,
45
+ individualUserRequired: true,
46
+ organizationUserRequired: false,
47
+ primary: 'individual',
48
+ };
49
+
50
+ beforeAll(async () => {
51
+ await connectPrisma();
52
+ // Connect mongoose for raw database queries
53
+ if (mongoose.connection.readyState === 0) {
54
+ await mongoose.connect(process.env.DATABASE_URL);
55
+ }
56
+ userRepository = createUserRepository();
57
+ }, 30000); // 30 second timeout for database connection
58
+
59
+ afterAll(async () => {
60
+ if (testUserId) {
61
+ await userRepository.deleteUser(testUserId).catch(() => {});
62
+ }
63
+ await mongoose.disconnect();
64
+ await disconnectPrisma();
65
+ }, 30000); // 30 second timeout for cleanup
66
+
67
+ describe(`${dbType.toUpperCase()} - Password Hashing`, () => {
68
+ test('āœ… Password is bcrypt hashed on user creation', async () => {
69
+ const user = await userRepository.createIndividualUser({
70
+ username: TEST_USERNAME,
71
+ hashword: TEST_PASSWORD,
72
+ email: `${TEST_USERNAME}@test.com`,
73
+ });
74
+ testUserId = user.id;
75
+
76
+ expect(user.hashword).toBeDefined();
77
+ expect(user.hashword).not.toBe(TEST_PASSWORD);
78
+ expect(user.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
79
+ expect(user.hashword.length).toBeGreaterThan(50);
80
+ expect(user.hashword).not.toContain(':');
81
+
82
+ console.log('āœ… Password hashed correctly:', user.hashword.substring(0, 20) + '...');
83
+ });
84
+
85
+ test('āœ… Stored hashword is bcrypt format, NOT encrypted', async () => {
86
+ const user = await userRepository.findIndividualUserByUsername(TEST_USERNAME);
87
+
88
+ expect(user.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
89
+ expect(user.hashword).not.toContain(':');
90
+ expect(user.hashword.split(':')).toHaveLength(1);
91
+
92
+ console.log('āœ… Stored password has bcrypt format (not encrypted)');
93
+ });
94
+
95
+ test('āœ… bcrypt.compare() verifies correct password', async () => {
96
+ const user = await userRepository.findIndividualUserByUsername(TEST_USERNAME);
97
+ const isValid = await bcrypt.compare(TEST_PASSWORD, user.hashword);
98
+
99
+ expect(isValid).toBe(true);
100
+ console.log('āœ… bcrypt.compare() successfully verified password');
101
+ });
102
+
103
+ test('āœ… bcrypt.compare() rejects incorrect password', async () => {
104
+ const user = await userRepository.findIndividualUserByUsername(TEST_USERNAME);
105
+ const isValid = await bcrypt.compare('WrongPassword', user.hashword);
106
+
107
+ expect(isValid).toBe(false);
108
+ console.log('āœ… bcrypt.compare() correctly rejected wrong password');
109
+ });
110
+
111
+ test('āœ… Login succeeds with correct password', async () => {
112
+ const loginUser = new LoginUser({ userRepository, userConfig });
113
+ const user = await loginUser.execute({
114
+ username: TEST_USERNAME,
115
+ password: TEST_PASSWORD,
116
+ });
117
+
118
+ expect(user).toBeDefined();
119
+ expect(user.getId()).toBe(testUserId);
120
+ console.log('āœ… Login successful with correct password');
121
+ });
122
+
123
+ test('āœ… Login fails with incorrect password', async () => {
124
+ const loginUser = new LoginUser({ userRepository, userConfig });
125
+
126
+ await expect(
127
+ loginUser.execute({
128
+ username: TEST_USERNAME,
129
+ password: 'WrongPassword123',
130
+ })
131
+ ).rejects.toThrow('Incorrect username or password');
132
+
133
+ console.log('āœ… Login correctly rejected incorrect password');
134
+ });
135
+
136
+ test('āœ… Password update also hashes the new password', async () => {
137
+ const newPassword = 'NewSecurePassword456!';
138
+
139
+ const updatedUser = await userRepository.updateIndividualUser(testUserId, {
140
+ hashword: newPassword,
141
+ });
142
+
143
+ expect(updatedUser.hashword).not.toBe(newPassword);
144
+ expect(updatedUser.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
145
+ expect(updatedUser.hashword).not.toContain(':');
146
+
147
+ const isNewPasswordValid = await bcrypt.compare(newPassword, updatedUser.hashword);
148
+ expect(isNewPasswordValid).toBe(true);
149
+
150
+ const isOldPasswordValid = await bcrypt.compare(TEST_PASSWORD, updatedUser.hashword);
151
+ expect(isOldPasswordValid).toBe(false);
152
+
153
+ console.log('āœ… Password update correctly hashed new password');
154
+ });
155
+
156
+ test('šŸ“Š Raw database check: bcrypt hash stored directly', async () => {
157
+ let rawUser;
158
+ if (dbType === 'postgresql') {
159
+ const userId = parseInt(testUserId, 10);
160
+ rawUser = await prisma.$queryRaw`
161
+ SELECT hashword FROM "User" WHERE id = ${userId}
162
+ `;
163
+ rawUser = rawUser[0];
164
+ } else {
165
+ rawUser = await prisma.$queryRawUnsafe(
166
+ `db.User.findOne({ _id: ObjectId("${testUserId}") })`
167
+ ).catch(() => {
168
+ return userRepository.findIndividualUserById(testUserId);
169
+ });
170
+ }
171
+
172
+ console.log('\nšŸ“Š RAW DATABASE HASHWORD:');
173
+ console.log('Format:', rawUser.hashword.substring(0, 30) + '...');
174
+ console.log('Length:', rawUser.hashword.length);
175
+
176
+ expect(rawUser.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
177
+ expect(rawUser.hashword).not.toContain(':');
178
+
179
+ console.log('āœ… Raw database stores bcrypt hash (not encrypted)');
180
+ });
181
+ });
182
+
183
+ describe(`${dbType.toUpperCase()} - Encryption Isolation`, () => {
184
+ test('šŸ“Š COMPARISON: Credential tokens encrypted, passwords hashed', async () => {
185
+ const credential = await prisma.credential.create({
186
+ data: {
187
+ userId: dbType === 'postgresql' ? parseInt(testUserId, 10) : testUserId,
188
+ externalId: `test-cred-${Date.now()}`,
189
+ data: {
190
+ access_token: 'secret-access-token-12345',
191
+ refresh_token: 'secret-refresh-token-67890',
192
+ },
193
+ },
194
+ });
195
+
196
+ const user = await userRepository.findIndividualUserById(testUserId);
197
+
198
+ let rawCred;
199
+ if (dbType === 'postgresql') {
200
+ rawCred = await prisma.$queryRaw`
201
+ SELECT data FROM "Credential" WHERE id = ${credential.id}
202
+ `;
203
+ rawCred = rawCred[0];
204
+ } else {
205
+ rawCred = await prisma.credential.findUnique({
206
+ where: { id: credential.id },
207
+ });
208
+ }
209
+
210
+ console.log('\nšŸ“Š ENCRYPTION COMPARISON:');
211
+ console.log('Credential token (should be encrypted):');
212
+ console.log(' Format:', rawCred.data.access_token.substring(0, 50) + '...');
213
+ console.log(' Has ":" separators:', rawCred.data.access_token.includes(':'));
214
+ console.log('\nUser password (should be bcrypt hashed):');
215
+ console.log(' Format:', user.hashword.substring(0, 30) + '...');
216
+ console.log(' Has ":" separators:', user.hashword.includes(':'));
217
+
218
+ const encryptionEnabled = rawCred.data.access_token !== 'secret-access-token-12345';
219
+
220
+ if (encryptionEnabled) {
221
+ expect(rawCred.data.access_token).toContain(':');
222
+ expect(rawCred.data.access_token.split(':')).toHaveLength(4);
223
+ console.log('āœ… Credential token is encrypted');
224
+ } else {
225
+ console.log('āš ļø Encryption disabled in this environment');
226
+ }
227
+
228
+ expect(user.hashword).toMatch(/^\$2[ab]\$\d{2}\$/);
229
+ expect(user.hashword).not.toContain(':');
230
+ console.log('āœ… Password is bcrypt hashed (NOT encrypted)');
231
+
232
+ await prisma.credential.delete({ where: { id: credential.id } });
233
+ });
234
+ });
235
+ });
@@ -65,7 +65,7 @@ class LoginUser {
65
65
  this.userConfig.organizationUserRequired
66
66
  );
67
67
 
68
- if (!individualUser.isPasswordValid(password)) {
68
+ if (!(await individualUser.isPasswordValid(password))) {
69
69
  throw Boom.unauthorized('Incorrect username or password');
70
70
  }
71
71
 
package/user/user.js CHANGED
@@ -41,12 +41,12 @@ class User {
41
41
  return this.usePassword;
42
42
  }
43
43
 
44
- isPasswordValid(password) {
44
+ async isPasswordValid(password) {
45
45
  if (!this.isPasswordRequired()) {
46
46
  return true;
47
47
  }
48
48
 
49
- return bcrypt.compareSync(password, this.getPrimaryUser().hashword);
49
+ return await bcrypt.compare(password, this.getPrimaryUser().hashword);
50
50
  }
51
51
 
52
52
  setIndividualUser(individualUser) {