@friggframework/core 2.0.0--canary.503.d72d514.0 → 2.0.0--canary.503.ce72072.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.
- package/credential/repositories/credential-repository-documentdb.js +80 -104
- package/credential/repositories/credential-repository-mongo.js +16 -54
- package/credential/repositories/credential-repository-postgres.js +14 -41
- package/credential/use-cases/get-credential-for-user.js +7 -3
- package/errors/fetch-error.js +2 -1
- package/integrations/integration-router.js +6 -6
- package/integrations/repositories/integration-mapping-repository-documentdb.js +99 -74
- package/integrations/repositories/process-repository-documentdb.js +0 -5
- package/package.json +5 -5
|
@@ -10,7 +10,9 @@ const {
|
|
|
10
10
|
const {
|
|
11
11
|
CredentialRepositoryInterface,
|
|
12
12
|
} = require('./credential-repository-interface');
|
|
13
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
DocumentDBEncryptionService,
|
|
15
|
+
} = require('../../database/documentdb-encryption-service');
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Credential repository for DocumentDB.
|
|
@@ -39,8 +41,10 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
39
41
|
const doc = await findOne(this.prisma, 'Credential', { _id: objectId });
|
|
40
42
|
if (!doc) return null;
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
const decryptedCredential = await this.encryptionService.decryptFields(
|
|
45
|
+
'Credential',
|
|
46
|
+
doc
|
|
47
|
+
);
|
|
44
48
|
return this._mapCredentialById(decryptedCredential);
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -62,16 +66,19 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
62
66
|
async deleteCredentialById(credentialId) {
|
|
63
67
|
const objectId = toObjectId(credentialId);
|
|
64
68
|
if (!objectId) return { acknowledged: true, deletedCount: 0 };
|
|
65
|
-
const result = await deleteOne(this.prisma, 'Credential', {
|
|
69
|
+
const result = await deleteOne(this.prisma, 'Credential', {
|
|
70
|
+
_id: objectId,
|
|
71
|
+
});
|
|
66
72
|
const deleted = result?.n ?? 0;
|
|
67
73
|
return { acknowledged: true, deletedCount: deleted };
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
async upsertCredential(credentialDetails) {
|
|
71
77
|
const { identifiers, details } = credentialDetails;
|
|
72
|
-
if (!identifiers)
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
if (!identifiers)
|
|
79
|
+
throw new Error('identifiers required to upsert credential');
|
|
80
|
+
if (!identifiers.userId) {
|
|
81
|
+
throw new Error('userId required in identifiers');
|
|
75
82
|
}
|
|
76
83
|
if (!identifiers.externalId) {
|
|
77
84
|
throw new Error(
|
|
@@ -81,32 +88,29 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
81
88
|
|
|
82
89
|
const filter = this._buildIdentifierFilter(identifiers);
|
|
83
90
|
const existing = await findOne(this.prisma, 'Credential', filter);
|
|
84
|
-
|
|
85
|
-
const {
|
|
86
|
-
user,
|
|
87
|
-
userId,
|
|
88
|
-
authIsValid,
|
|
89
|
-
externalId,
|
|
90
|
-
...oauthData
|
|
91
|
-
} = details || {};
|
|
92
|
-
|
|
93
91
|
const now = new Date();
|
|
94
92
|
|
|
93
|
+
const { authIsValid, ...oauthData } = details || {};
|
|
94
|
+
|
|
95
95
|
if (existing) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
const decryptedExisting =
|
|
97
|
+
await this.encryptionService.decryptFields(
|
|
98
|
+
'Credential',
|
|
99
|
+
existing
|
|
100
|
+
);
|
|
101
|
+
const mergedData = {
|
|
102
|
+
...(decryptedExisting.data || {}),
|
|
103
|
+
...oauthData,
|
|
104
|
+
};
|
|
99
105
|
|
|
100
|
-
// Build update document
|
|
101
106
|
const updateDocument = {
|
|
102
|
-
userId:
|
|
103
|
-
externalId:
|
|
104
|
-
authIsValid: authIsValid
|
|
107
|
+
userId: existing.userId,
|
|
108
|
+
externalId: existing.externalId,
|
|
109
|
+
authIsValid: authIsValid,
|
|
105
110
|
data: mergedData,
|
|
106
111
|
updatedAt: now,
|
|
107
112
|
};
|
|
108
113
|
|
|
109
|
-
// Encrypt before storing
|
|
110
114
|
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
111
115
|
'Credential',
|
|
112
116
|
{ data: updateDocument.data }
|
|
@@ -127,53 +131,44 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
127
131
|
}
|
|
128
132
|
);
|
|
129
133
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
throw new Error(
|
|
138
|
-
'Failed to update credential: Document not found after update. ' +
|
|
139
|
-
'This indicates a database consistency issue.'
|
|
134
|
+
const updated = await findOne(this.prisma, 'Credential', {
|
|
135
|
+
_id: existing._id,
|
|
136
|
+
});
|
|
137
|
+
const decryptedCredential =
|
|
138
|
+
await this.encryptionService.decryptFields(
|
|
139
|
+
'Credential',
|
|
140
|
+
updated
|
|
140
141
|
);
|
|
141
|
-
}
|
|
142
|
-
const decryptedCredential = await this.encryptionService.decryptFields('Credential', updated);
|
|
143
142
|
return this._mapCredential(decryptedCredential);
|
|
144
143
|
}
|
|
145
144
|
|
|
146
|
-
// Build plain text document
|
|
147
145
|
const plainDocument = {
|
|
148
|
-
userId:
|
|
149
|
-
externalId:
|
|
150
|
-
authIsValid: authIsValid
|
|
151
|
-
data: oauthData,
|
|
146
|
+
userId: identifiers.userId,
|
|
147
|
+
externalId: identifiers.externalId,
|
|
148
|
+
authIsValid: details.authIsValid,
|
|
149
|
+
data: { ...oauthData },
|
|
152
150
|
createdAt: now,
|
|
153
151
|
updatedAt: now,
|
|
154
152
|
};
|
|
155
153
|
|
|
156
|
-
// Encrypt before storing
|
|
157
154
|
const encryptedDocument = await this.encryptionService.encryptFields(
|
|
158
155
|
'Credential',
|
|
159
156
|
plainDocument
|
|
160
157
|
);
|
|
161
158
|
|
|
162
|
-
const insertedId = await insertOne(
|
|
159
|
+
const insertedId = await insertOne(
|
|
160
|
+
this.prisma,
|
|
161
|
+
'Credential',
|
|
162
|
+
encryptedDocument
|
|
163
|
+
);
|
|
163
164
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
throw new Error(
|
|
172
|
-
'Failed to create credential: Document not found after insert. ' +
|
|
173
|
-
'This indicates a database consistency issue.'
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
const decryptedCredential = await this.encryptionService.decryptFields('Credential', created);
|
|
165
|
+
const created = await findOne(this.prisma, 'Credential', {
|
|
166
|
+
_id: insertedId,
|
|
167
|
+
});
|
|
168
|
+
const decryptedCredential = await this.encryptionService.decryptFields(
|
|
169
|
+
'Credential',
|
|
170
|
+
created
|
|
171
|
+
);
|
|
177
172
|
return this._mapCredential(decryptedCredential);
|
|
178
173
|
}
|
|
179
174
|
|
|
@@ -182,39 +177,37 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
182
177
|
const credential = await findOne(this.prisma, 'Credential', query);
|
|
183
178
|
if (!credential) return null;
|
|
184
179
|
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
const decryptedCredential = await this.encryptionService.decryptFields(
|
|
181
|
+
'Credential',
|
|
182
|
+
credential
|
|
183
|
+
);
|
|
187
184
|
return this._mapCredential(decryptedCredential);
|
|
188
185
|
}
|
|
189
186
|
|
|
190
187
|
async updateCredential(credentialId, updates) {
|
|
191
188
|
const objectId = toObjectId(credentialId);
|
|
192
189
|
if (!objectId) return null;
|
|
193
|
-
const existing = await findOne(this.prisma, 'Credential', {
|
|
190
|
+
const existing = await findOne(this.prisma, 'Credential', {
|
|
191
|
+
_id: objectId,
|
|
192
|
+
});
|
|
194
193
|
if (!existing) return null;
|
|
195
194
|
|
|
196
|
-
const {
|
|
197
|
-
user,
|
|
198
|
-
userId,
|
|
199
|
-
authIsValid,
|
|
200
|
-
externalId,
|
|
201
|
-
...oauthData
|
|
202
|
-
} = updates || {};
|
|
195
|
+
const { authIsValid, ...oauthData } = updates || {};
|
|
203
196
|
|
|
204
|
-
|
|
205
|
-
|
|
197
|
+
const decryptedExisting = await this.encryptionService.decryptFields(
|
|
198
|
+
'Credential',
|
|
199
|
+
existing
|
|
200
|
+
);
|
|
206
201
|
const mergedData = { ...(decryptedExisting.data || {}), ...oauthData };
|
|
207
202
|
|
|
208
|
-
// Build update document
|
|
209
203
|
const updateDocument = {
|
|
210
|
-
userId:
|
|
211
|
-
externalId:
|
|
212
|
-
authIsValid: authIsValid
|
|
204
|
+
userId: existing.userId,
|
|
205
|
+
externalId: existing.externalId,
|
|
206
|
+
authIsValid: authIsValid,
|
|
213
207
|
data: mergedData,
|
|
214
208
|
updatedAt: new Date(),
|
|
215
209
|
};
|
|
216
210
|
|
|
217
|
-
// Encrypt before storing
|
|
218
211
|
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
219
212
|
'Credential',
|
|
220
213
|
{ data: updateDocument.data }
|
|
@@ -235,18 +228,13 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
235
228
|
}
|
|
236
229
|
);
|
|
237
230
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
'Failed to update credential: Document not found after update. ' +
|
|
246
|
-
'This indicates a database consistency issue.'
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
const decryptedCredential = await this.encryptionService.decryptFields('Credential', updated);
|
|
231
|
+
const updated = await findOne(this.prisma, 'Credential', {
|
|
232
|
+
_id: objectId,
|
|
233
|
+
});
|
|
234
|
+
const decryptedCredential = await this.encryptionService.decryptFields(
|
|
235
|
+
'Credential',
|
|
236
|
+
updated
|
|
237
|
+
);
|
|
250
238
|
return this._mapCredential(decryptedCredential);
|
|
251
239
|
}
|
|
252
240
|
|
|
@@ -256,9 +244,8 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
256
244
|
const idObj = toObjectId(identifiers._id || identifiers.id);
|
|
257
245
|
if (idObj) filter._id = idObj;
|
|
258
246
|
}
|
|
259
|
-
if (identifiers.
|
|
260
|
-
|
|
261
|
-
if (userObj) filter.userId = userObj;
|
|
247
|
+
if (identifiers.userId) {
|
|
248
|
+
filter.userId = identifiers.userId;
|
|
262
249
|
}
|
|
263
250
|
if (identifiers.externalId !== undefined) {
|
|
264
251
|
filter.externalId = identifiers.externalId;
|
|
@@ -273,9 +260,8 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
273
260
|
const idObj = toObjectId(filter.credentialId || filter.id);
|
|
274
261
|
if (idObj) query._id = idObj;
|
|
275
262
|
}
|
|
276
|
-
if (filter.
|
|
277
|
-
|
|
278
|
-
if (userObj) query.userId = userObj;
|
|
263
|
+
if (filter.userId !== undefined) {
|
|
264
|
+
query.userId = filter.userId;
|
|
279
265
|
}
|
|
280
266
|
if (filter.externalId !== undefined) {
|
|
281
267
|
query.externalId = filter.externalId;
|
|
@@ -284,15 +270,14 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
284
270
|
}
|
|
285
271
|
|
|
286
272
|
/**
|
|
287
|
-
* Map credential document to application format
|
|
288
|
-
* Used by findCredential, upsertCredential, updateCredential
|
|
273
|
+
* Map credential document to application format
|
|
289
274
|
* Matches MongoDB repository format
|
|
290
275
|
* @private
|
|
291
276
|
*/
|
|
292
277
|
_mapCredential(doc) {
|
|
293
278
|
const data = doc?.data || {};
|
|
294
279
|
const id = fromObjectId(doc?._id);
|
|
295
|
-
const userId =
|
|
280
|
+
const userId = doc?.userId;
|
|
296
281
|
return {
|
|
297
282
|
id,
|
|
298
283
|
userId,
|
|
@@ -302,20 +287,12 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
302
287
|
};
|
|
303
288
|
}
|
|
304
289
|
|
|
305
|
-
/**
|
|
306
|
-
* Map credential document with legacy fields for findCredentialById
|
|
307
|
-
* Includes _id and user fields for backward compatibility
|
|
308
|
-
* Matches MongoDB repository format
|
|
309
|
-
* @private
|
|
310
|
-
*/
|
|
311
290
|
_mapCredentialById(doc) {
|
|
312
291
|
const data = doc?.data || {};
|
|
313
292
|
const id = fromObjectId(doc?._id);
|
|
314
|
-
const userId =
|
|
293
|
+
const userId = doc?.userId;
|
|
315
294
|
return {
|
|
316
|
-
_id: id,
|
|
317
295
|
id,
|
|
318
|
-
user: userId,
|
|
319
296
|
userId,
|
|
320
297
|
externalId: doc?.externalId ?? null,
|
|
321
298
|
authIsValid: doc?.authIsValid ?? null,
|
|
@@ -325,4 +302,3 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
325
302
|
}
|
|
326
303
|
|
|
327
304
|
module.exports = { CredentialRepositoryDocumentDB };
|
|
328
|
-
|
|
@@ -38,9 +38,7 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
38
38
|
const data = credential.data || {};
|
|
39
39
|
|
|
40
40
|
return {
|
|
41
|
-
_id: credential.id,
|
|
42
41
|
id: credential.id,
|
|
43
|
-
user: credential.userId,
|
|
44
42
|
userId: credential.userId,
|
|
45
43
|
externalId: credential.externalId,
|
|
46
44
|
authIsValid: credential.authIsValid,
|
|
@@ -80,7 +78,6 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
80
78
|
return { acknowledged: true, deletedCount: 1 };
|
|
81
79
|
} catch (error) {
|
|
82
80
|
if (error.code === 'P2025') {
|
|
83
|
-
// Record not found
|
|
84
81
|
return { acknowledged: true, deletedCount: 0 };
|
|
85
82
|
}
|
|
86
83
|
throw error;
|
|
@@ -99,49 +96,32 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
99
96
|
if (!identifiers)
|
|
100
97
|
throw new Error('identifiers required to upsert credential');
|
|
101
98
|
|
|
102
|
-
if (!identifiers.
|
|
103
|
-
throw new Error('
|
|
99
|
+
if (!identifiers.userId) {
|
|
100
|
+
throw new Error('userId required in identifiers');
|
|
104
101
|
}
|
|
105
102
|
if (!identifiers.externalId) {
|
|
106
103
|
throw new Error(
|
|
107
104
|
'externalId required in identifiers to prevent credential collision. ' +
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
'When multiple credentials exist for the same user, both userId and externalId ' +
|
|
106
|
+
'are needed to uniquely identify which credential to update.'
|
|
110
107
|
);
|
|
111
108
|
}
|
|
112
109
|
|
|
113
|
-
// Build where clause from identifiers
|
|
114
110
|
const where = this._convertIdentifiersToWhere(identifiers);
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
user,
|
|
119
|
-
userId,
|
|
120
|
-
externalId,
|
|
121
|
-
authIsValid,
|
|
122
|
-
|
|
123
|
-
...oauthData
|
|
124
|
-
} = details;
|
|
125
|
-
|
|
126
|
-
// Find existing credential
|
|
112
|
+
const { authIsValid, ...oauthData } = details;
|
|
113
|
+
|
|
127
114
|
const existing = await this.prisma.credential.findFirst({ where });
|
|
128
115
|
|
|
129
116
|
if (existing) {
|
|
130
|
-
// Update existing - merge OAuth data into existing data JSON
|
|
131
117
|
const mergedData = { ...(existing.data || {}), ...oauthData };
|
|
132
118
|
|
|
133
119
|
const updated = await this.prisma.credential.update({
|
|
134
120
|
where: { id: existing.id },
|
|
135
121
|
data: {
|
|
136
|
-
userId:
|
|
137
|
-
externalId:
|
|
138
|
-
|
|
139
|
-
? externalId
|
|
140
|
-
: existing.externalId,
|
|
141
|
-
authIsValid:
|
|
142
|
-
authIsValid !== undefined
|
|
143
|
-
? authIsValid
|
|
144
|
-
: existing.authIsValid,
|
|
122
|
+
userId: existing.userId,
|
|
123
|
+
externalId: existing.externalId,
|
|
124
|
+
authIsValid: authIsValid,
|
|
145
125
|
data: mergedData,
|
|
146
126
|
},
|
|
147
127
|
});
|
|
@@ -155,13 +135,11 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
155
135
|
};
|
|
156
136
|
}
|
|
157
137
|
|
|
158
|
-
// Create new credential
|
|
159
138
|
const created = await this.prisma.credential.create({
|
|
160
139
|
data: {
|
|
161
|
-
userId: userId
|
|
162
|
-
externalId,
|
|
140
|
+
userId: identifiers.userId,
|
|
141
|
+
externalId: identifiers.externalId,
|
|
163
142
|
authIsValid: authIsValid,
|
|
164
|
-
|
|
165
143
|
data: oauthData,
|
|
166
144
|
},
|
|
167
145
|
});
|
|
@@ -205,7 +183,6 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
205
183
|
authIsValid: credential.authIsValid,
|
|
206
184
|
access_token: data.access_token,
|
|
207
185
|
refresh_token: data.refresh_token,
|
|
208
|
-
domain: data.domain,
|
|
209
186
|
...data,
|
|
210
187
|
};
|
|
211
188
|
}
|
|
@@ -219,7 +196,6 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
219
196
|
* @returns {Promise<Object|null>} Updated credential object or null if not found
|
|
220
197
|
*/
|
|
221
198
|
async updateCredential(credentialId, updates) {
|
|
222
|
-
// Get existing credential to merge OAuth data
|
|
223
199
|
const existing = await this.prisma.credential.findUnique({
|
|
224
200
|
where: { id: credentialId },
|
|
225
201
|
});
|
|
@@ -228,27 +204,16 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
228
204
|
return null;
|
|
229
205
|
}
|
|
230
206
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
user,
|
|
234
|
-
userId,
|
|
235
|
-
externalId,
|
|
236
|
-
authIsValid,
|
|
237
|
-
|
|
238
|
-
...oauthData
|
|
239
|
-
} = updates;
|
|
240
|
-
|
|
241
|
-
// Merge OAuth data with existing
|
|
207
|
+
const { authIsValid, ...oauthData } = updates;
|
|
208
|
+
|
|
242
209
|
const mergedData = { ...(existing.data || {}), ...oauthData };
|
|
243
210
|
|
|
244
211
|
const updated = await this.prisma.credential.update({
|
|
245
212
|
where: { id: credentialId },
|
|
246
213
|
data: {
|
|
247
|
-
userId:
|
|
248
|
-
externalId:
|
|
249
|
-
|
|
250
|
-
authIsValid:
|
|
251
|
-
authIsValid !== undefined ? authIsValid : existing.authIsValid,
|
|
214
|
+
userId: existing.userId,
|
|
215
|
+
externalId: existing.externalId,
|
|
216
|
+
authIsValid: authIsValid,
|
|
252
217
|
data: mergedData,
|
|
253
218
|
},
|
|
254
219
|
});
|
|
@@ -262,7 +227,6 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
262
227
|
authIsValid: updated.authIsValid,
|
|
263
228
|
access_token: data.access_token,
|
|
264
229
|
refresh_token: data.refresh_token,
|
|
265
|
-
domain: data.domain,
|
|
266
230
|
...data,
|
|
267
231
|
};
|
|
268
232
|
}
|
|
@@ -278,7 +242,6 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
278
242
|
|
|
279
243
|
if (identifiers._id) where.id = identifiers._id;
|
|
280
244
|
if (identifiers.id) where.id = identifiers.id;
|
|
281
|
-
if (identifiers.user) where.userId = identifiers.user;
|
|
282
245
|
if (identifiers.userId) where.userId = identifiers.userId;
|
|
283
246
|
if (identifiers.externalId) where.externalId = identifiers.externalId;
|
|
284
247
|
|
|
@@ -296,7 +259,6 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
|
|
|
296
259
|
|
|
297
260
|
if (filter.credentialId) where.id = filter.credentialId;
|
|
298
261
|
if (filter.id) where.id = filter.id;
|
|
299
|
-
if (filter.user) where.userId = filter.user;
|
|
300
262
|
if (filter.userId) where.userId = filter.userId;
|
|
301
263
|
if (filter.externalId) where.externalId = filter.externalId;
|
|
302
264
|
|
|
@@ -36,7 +36,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Find credential by ID
|
|
39
|
-
* Replaces: Credential.findById(id)
|
|
40
39
|
*
|
|
41
40
|
* @param {string} id - Credential ID (string from application layer)
|
|
42
41
|
* @returns {Promise<Object|null>} Credential object with string IDs or null
|
|
@@ -51,14 +50,11 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
51
50
|
return null;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
// Extract data from JSON field
|
|
55
53
|
const data = credential.data || {};
|
|
56
54
|
|
|
57
55
|
return {
|
|
58
|
-
_id: credential.id.toString(),
|
|
59
56
|
id: credential.id.toString(),
|
|
60
|
-
|
|
61
|
-
userId: credential.userId?.toString(),
|
|
57
|
+
userId: credential.userId.toString(),
|
|
62
58
|
externalId: credential.externalId,
|
|
63
59
|
authIsValid: credential.authIsValid,
|
|
64
60
|
...data, // Spread OAuth tokens from JSON field
|
|
@@ -67,7 +63,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
67
63
|
|
|
68
64
|
/**
|
|
69
65
|
* Update authentication status
|
|
70
|
-
* Replaces: Credential.updateOne({ _id: credentialId }, { $set: { authIsValid } })
|
|
71
66
|
*
|
|
72
67
|
* @param {string} credentialId - Credential ID (string from application layer)
|
|
73
68
|
* @param {boolean} authIsValid - Authentication validity status
|
|
@@ -85,7 +80,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
85
80
|
|
|
86
81
|
/**
|
|
87
82
|
* Permanently remove a credential document
|
|
88
|
-
* Replaces: Credential.deleteOne({ _id: credentialId })
|
|
89
83
|
*
|
|
90
84
|
* @param {string} credentialId - Credential ID (string from application layer)
|
|
91
85
|
* @returns {Promise<Object>} Deletion result
|
|
@@ -108,7 +102,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
108
102
|
|
|
109
103
|
/**
|
|
110
104
|
* Create or update credential matching identifiers
|
|
111
|
-
* Replaces: Credential.findOneAndUpdate(query, update, { upsert: true })
|
|
112
105
|
*
|
|
113
106
|
* @param {{identifiers: Object, details: Object}} credentialDetails
|
|
114
107
|
* @returns {Promise<Object>} The persisted credential with string IDs
|
|
@@ -118,22 +111,21 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
118
111
|
if (!identifiers)
|
|
119
112
|
throw new Error('identifiers required to upsert credential');
|
|
120
113
|
|
|
121
|
-
if (!identifiers.
|
|
122
|
-
throw new Error('
|
|
114
|
+
if (!identifiers.userId) {
|
|
115
|
+
throw new Error('userId required in identifiers');
|
|
123
116
|
}
|
|
124
117
|
if (!identifiers.externalId) {
|
|
125
118
|
throw new Error(
|
|
126
119
|
'externalId required in identifiers to prevent credential collision. ' +
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
'When multiple credentials exist for the same user, both userId and externalId ' +
|
|
121
|
+
'are needed to uniquely identify which credential to update.'
|
|
129
122
|
);
|
|
130
123
|
}
|
|
131
124
|
|
|
132
125
|
const where = this._convertIdentifiersToWhere(identifiers);
|
|
133
126
|
|
|
134
|
-
const {
|
|
127
|
+
const { externalId } = identifiers;
|
|
135
128
|
|
|
136
|
-
// Separate schema fields from dynamic OAuth data
|
|
137
129
|
const { authIsValid, ...oauthData } = details;
|
|
138
130
|
|
|
139
131
|
const existing = await this.prisma.credential.findFirst({ where });
|
|
@@ -144,15 +136,9 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
144
136
|
const updated = await this.prisma.credential.update({
|
|
145
137
|
where: { id: existing.id },
|
|
146
138
|
data: {
|
|
147
|
-
userId: this._convertId(
|
|
148
|
-
externalId:
|
|
149
|
-
|
|
150
|
-
? externalId
|
|
151
|
-
: existing.externalId,
|
|
152
|
-
authIsValid:
|
|
153
|
-
authIsValid !== undefined
|
|
154
|
-
? authIsValid
|
|
155
|
-
: existing.authIsValid,
|
|
139
|
+
userId: this._convertId(existing.userId),
|
|
140
|
+
externalId: existing.externalId,
|
|
141
|
+
authIsValid: authIsValid,
|
|
156
142
|
data: mergedData,
|
|
157
143
|
},
|
|
158
144
|
});
|
|
@@ -168,10 +154,9 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
168
154
|
|
|
169
155
|
const created = await this.prisma.credential.create({
|
|
170
156
|
data: {
|
|
171
|
-
userId: this._convertId(
|
|
157
|
+
userId: this._convertId(identifiers.userId),
|
|
172
158
|
externalId,
|
|
173
159
|
authIsValid: authIsValid,
|
|
174
|
-
|
|
175
160
|
data: oauthData,
|
|
176
161
|
},
|
|
177
162
|
});
|
|
@@ -187,7 +172,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
187
172
|
|
|
188
173
|
/**
|
|
189
174
|
* Find a credential by filter criteria
|
|
190
|
-
* Replaces: Credential.findOne(query)
|
|
191
175
|
*
|
|
192
176
|
* @param {Object} filter
|
|
193
177
|
* @param {string} [filter.userId] - User ID (string from application layer)
|
|
@@ -215,21 +199,18 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
215
199
|
authIsValid: credential.authIsValid,
|
|
216
200
|
access_token: data.access_token,
|
|
217
201
|
refresh_token: data.refresh_token,
|
|
218
|
-
domain: data.domain,
|
|
219
202
|
...data,
|
|
220
203
|
};
|
|
221
204
|
}
|
|
222
205
|
|
|
223
206
|
/**
|
|
224
207
|
* Update a credential by ID
|
|
225
|
-
* Replaces: Credential.findByIdAndUpdate(credentialId, { $set: updates })
|
|
226
208
|
*
|
|
227
209
|
* @param {string} credentialId - Credential ID (string from application layer)
|
|
228
210
|
* @param {Object} updates - Fields to update
|
|
229
211
|
* @returns {Promise<Object|null>} Updated credential object with string IDs or null if not found
|
|
230
212
|
*/
|
|
231
213
|
async updateCredential(credentialId, updates) {
|
|
232
|
-
// Get existing credential to merge OAuth data
|
|
233
214
|
const intId = this._convertId(credentialId);
|
|
234
215
|
const existing = await this.prisma.credential.findUnique({
|
|
235
216
|
where: { id: intId },
|
|
@@ -239,21 +220,16 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
239
220
|
return null;
|
|
240
221
|
}
|
|
241
222
|
|
|
242
|
-
|
|
243
|
-
const { user, authIsValid, ...oauthData } =
|
|
244
|
-
updates;
|
|
223
|
+
const { authIsValid, ...oauthData } = updates;
|
|
245
224
|
|
|
246
|
-
// Merge OAuth data with existing
|
|
247
225
|
const mergedData = { ...(existing.data || {}), ...oauthData };
|
|
248
226
|
|
|
249
227
|
const updated = await this.prisma.credential.update({
|
|
250
228
|
where: { id: intId },
|
|
251
229
|
data: {
|
|
252
|
-
userId: this._convertId(
|
|
253
|
-
externalId:
|
|
254
|
-
|
|
255
|
-
authIsValid:
|
|
256
|
-
authIsValid !== undefined ? authIsValid : existing.authIsValid,
|
|
230
|
+
userId: this._convertId(existing.userId),
|
|
231
|
+
externalId: existing.externalId,
|
|
232
|
+
authIsValid: authIsValid,
|
|
257
233
|
data: mergedData,
|
|
258
234
|
},
|
|
259
235
|
});
|
|
@@ -267,7 +243,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
267
243
|
authIsValid: updated.authIsValid,
|
|
268
244
|
access_token: data.access_token,
|
|
269
245
|
refresh_token: data.refresh_token,
|
|
270
|
-
domain: data.domain,
|
|
271
246
|
...data,
|
|
272
247
|
};
|
|
273
248
|
}
|
|
@@ -282,7 +257,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
282
257
|
const where = {};
|
|
283
258
|
|
|
284
259
|
if (identifiers.id) where.id = this._convertId(identifiers.id);
|
|
285
|
-
if (identifiers.user) where.userId = this._convertId(identifiers.user);
|
|
286
260
|
if (identifiers.userId)
|
|
287
261
|
where.userId = this._convertId(identifiers.userId);
|
|
288
262
|
if (identifiers.externalId) where.externalId = identifiers.externalId;
|
|
@@ -302,7 +276,6 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
|
|
|
302
276
|
if (filter.credentialId)
|
|
303
277
|
where.id = this._convertId(filter.credentialId);
|
|
304
278
|
if (filter.id) where.id = this._convertId(filter.id);
|
|
305
|
-
if (filter.user) where.userId = this._convertId(filter.user);
|
|
306
279
|
if (filter.userId) where.userId = this._convertId(filter.userId);
|
|
307
280
|
if (filter.externalId) where.externalId = filter.externalId;
|
|
308
281
|
|
|
@@ -4,14 +4,18 @@ class GetCredentialForUser {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
async execute(credentialId, userId) {
|
|
7
|
-
const credential = await this.credentialRepository.findCredentialById(
|
|
7
|
+
const credential = await this.credentialRepository.findCredentialById(
|
|
8
|
+
credentialId
|
|
9
|
+
);
|
|
8
10
|
|
|
9
11
|
if (!credential) {
|
|
10
12
|
throw new Error(`Credential with id ${credentialId} not found`);
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
if (credential.
|
|
14
|
-
throw new Error(
|
|
15
|
+
if (credential.userId.toString() !== userId.toString()) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`Credential ${credentialId} does not belong to user ${userId}`
|
|
18
|
+
);
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
return credential;
|
package/errors/fetch-error.js
CHANGED
|
@@ -65,9 +65,7 @@ const {
|
|
|
65
65
|
const {
|
|
66
66
|
AuthenticateWithSharedSecret,
|
|
67
67
|
} = require('../user/use-cases/authenticate-with-shared-secret');
|
|
68
|
-
const {
|
|
69
|
-
AuthenticateUser,
|
|
70
|
-
} = require('../user/use-cases/authenticate-user');
|
|
68
|
+
const { AuthenticateUser } = require('../user/use-cases/authenticate-user');
|
|
71
69
|
const {
|
|
72
70
|
ProcessAuthorizationCallback,
|
|
73
71
|
} = require('../modules/use-cases/process-authorization-callback');
|
|
@@ -234,8 +232,10 @@ function checkRequiredParams(params, requiredKeys) {
|
|
|
234
232
|
|
|
235
233
|
if (missingKeys.length > 0) {
|
|
236
234
|
throw Boom.badRequest(
|
|
237
|
-
`Missing Parameter${
|
|
238
|
-
|
|
235
|
+
`Missing Parameter${
|
|
236
|
+
missingKeys.length === 1 ? '' : 's'
|
|
237
|
+
}: ${missingKeys.join(', ')} ${
|
|
238
|
+
missingKeys.length === 1 ? 'is' : 'are'
|
|
239
239
|
} required.`
|
|
240
240
|
);
|
|
241
241
|
}
|
|
@@ -584,7 +584,7 @@ function setEntityRoutes(router, authenticateUser, useCases) {
|
|
|
584
584
|
req.params.credentialId,
|
|
585
585
|
userId
|
|
586
586
|
);
|
|
587
|
-
if (credential.
|
|
587
|
+
if (credential.userId.toString() !== userId) {
|
|
588
588
|
throw Boom.forbidden('Credential does not belong to user');
|
|
589
589
|
}
|
|
590
590
|
|
|
@@ -12,28 +12,9 @@ const {
|
|
|
12
12
|
const {
|
|
13
13
|
IntegrationMappingRepositoryInterface,
|
|
14
14
|
} = require('./integration-mapping-repository-interface');
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* IntegrationMapping repository for DocumentDB.
|
|
19
|
-
* Uses DocumentDBEncryptionService for field-level encryption.
|
|
20
|
-
*
|
|
21
|
-
* Encrypted fields:
|
|
22
|
-
* - IntegrationMapping.mapping
|
|
23
|
-
*
|
|
24
|
-
* SECURITY CRITICAL: Mapping data may contain API keys, secrets, and sensitive configuration.
|
|
25
|
-
*
|
|
26
|
-
* DEFENSIVE CHECK PATTERN:
|
|
27
|
-
* Methods that return documents (upsertMapping, updateMapping) include defensive checks
|
|
28
|
-
* to verify the document exists after write operations. This catches:
|
|
29
|
-
* - Race conditions (document deleted between write and read)
|
|
30
|
-
* - Silent write failures due to permissions or storage issues
|
|
31
|
-
* - DocumentDB replication consistency issues
|
|
32
|
-
*
|
|
33
|
-
* @see credential-repository-documentdb.js for the same pattern
|
|
34
|
-
* @see DocumentDBEncryptionService
|
|
35
|
-
* @see encryption-schema-registry.js
|
|
36
|
-
*/
|
|
15
|
+
const {
|
|
16
|
+
DocumentDBEncryptionService,
|
|
17
|
+
} = require('../../database/documentdb-encryption-service');
|
|
37
18
|
class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositoryInterface {
|
|
38
19
|
constructor() {
|
|
39
20
|
super();
|
|
@@ -46,27 +27,34 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
46
27
|
const doc = await findOne(this.prisma, 'IntegrationMapping', filter);
|
|
47
28
|
if (!doc) return null;
|
|
48
29
|
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
31
|
+
'IntegrationMapping',
|
|
32
|
+
doc
|
|
33
|
+
);
|
|
51
34
|
return this._mapMapping(decryptedMapping);
|
|
52
35
|
}
|
|
53
36
|
|
|
54
37
|
async upsertMapping(integrationId, sourceId, mapping) {
|
|
55
38
|
const filter = this._compositeFilter(integrationId, sourceId);
|
|
56
|
-
const existing = await findOne(
|
|
39
|
+
const existing = await findOne(
|
|
40
|
+
this.prisma,
|
|
41
|
+
'IntegrationMapping',
|
|
42
|
+
filter
|
|
43
|
+
);
|
|
57
44
|
const now = new Date();
|
|
58
45
|
|
|
59
46
|
if (existing) {
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
const decryptedExisting =
|
|
48
|
+
await this.encryptionService.decryptFields(
|
|
49
|
+
'IntegrationMapping',
|
|
50
|
+
existing
|
|
51
|
+
);
|
|
62
52
|
|
|
63
|
-
// Build update document
|
|
64
53
|
const updateDocument = {
|
|
65
|
-
mapping,
|
|
54
|
+
mapping,
|
|
66
55
|
updatedAt: now,
|
|
67
56
|
};
|
|
68
57
|
|
|
69
|
-
// Encrypt before storing
|
|
70
58
|
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
71
59
|
'IntegrationMapping',
|
|
72
60
|
{ mapping: updateDocument.mapping }
|
|
@@ -84,54 +72,73 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
84
72
|
}
|
|
85
73
|
);
|
|
86
74
|
|
|
87
|
-
|
|
88
|
-
|
|
75
|
+
const updated = await findOne(this.prisma, 'IntegrationMapping', {
|
|
76
|
+
_id: existing._id,
|
|
77
|
+
});
|
|
89
78
|
if (!updated) {
|
|
90
|
-
console.error(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
console.error(
|
|
80
|
+
'[IntegrationMappingRepositoryDocumentDB] Mapping not found after update',
|
|
81
|
+
{
|
|
82
|
+
mappingId: fromObjectId(existing._id),
|
|
83
|
+
integrationId,
|
|
84
|
+
sourceId,
|
|
85
|
+
}
|
|
86
|
+
);
|
|
95
87
|
throw new Error(
|
|
96
88
|
'Failed to update mapping: Document not found after update. ' +
|
|
97
|
-
|
|
89
|
+
'This indicates a database consistency issue.'
|
|
98
90
|
);
|
|
99
91
|
}
|
|
100
|
-
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
92
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
93
|
+
'IntegrationMapping',
|
|
94
|
+
updated
|
|
95
|
+
);
|
|
101
96
|
return this._mapMapping(decryptedMapping);
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
// Build plain text document
|
|
105
99
|
const plainDocument = {
|
|
106
100
|
integrationId: toObjectId(integrationId),
|
|
107
|
-
sourceId:
|
|
101
|
+
sourceId:
|
|
102
|
+
sourceId === null || sourceId === undefined
|
|
103
|
+
? null
|
|
104
|
+
: String(sourceId),
|
|
108
105
|
mapping,
|
|
109
106
|
createdAt: now,
|
|
110
107
|
updatedAt: now,
|
|
111
108
|
};
|
|
112
109
|
|
|
113
|
-
// Encrypt before storing
|
|
114
110
|
const encryptedDocument = await this.encryptionService.encryptFields(
|
|
115
111
|
'IntegrationMapping',
|
|
116
112
|
plainDocument
|
|
117
113
|
);
|
|
118
114
|
|
|
119
|
-
const insertedId = await insertOne(
|
|
115
|
+
const insertedId = await insertOne(
|
|
116
|
+
this.prisma,
|
|
117
|
+
'IntegrationMapping',
|
|
118
|
+
encryptedDocument
|
|
119
|
+
);
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const created = await findOne(this.prisma, 'IntegrationMapping', {
|
|
122
|
+
_id: insertedId,
|
|
123
|
+
});
|
|
123
124
|
if (!created) {
|
|
124
|
-
console.error(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
console.error(
|
|
126
|
+
'[IntegrationMappingRepositoryDocumentDB] Mapping not found after insert',
|
|
127
|
+
{
|
|
128
|
+
insertedId: fromObjectId(insertedId),
|
|
129
|
+
integrationId,
|
|
130
|
+
sourceId,
|
|
131
|
+
}
|
|
132
|
+
);
|
|
129
133
|
throw new Error(
|
|
130
134
|
'Failed to create mapping: Document not found after insert. ' +
|
|
131
|
-
|
|
135
|
+
'This indicates a database consistency issue.'
|
|
132
136
|
);
|
|
133
137
|
}
|
|
134
|
-
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
138
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
139
|
+
'IntegrationMapping',
|
|
140
|
+
created
|
|
141
|
+
);
|
|
135
142
|
return this._mapMapping(decryptedMapping);
|
|
136
143
|
}
|
|
137
144
|
|
|
@@ -141,9 +148,10 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
141
148
|
if (integrationObjectId) filter.integrationId = integrationObjectId;
|
|
142
149
|
const docs = await findMany(this.prisma, 'IntegrationMapping', filter);
|
|
143
150
|
|
|
144
|
-
// Decrypt sensitive fields for each document
|
|
145
151
|
const decryptedDocs = await Promise.all(
|
|
146
|
-
docs.map(doc =>
|
|
152
|
+
docs.map((doc) =>
|
|
153
|
+
this.encryptionService.decryptFields('IntegrationMapping', doc)
|
|
154
|
+
)
|
|
147
155
|
);
|
|
148
156
|
|
|
149
157
|
return decryptedDocs.map((doc) => this._mapMapping(doc));
|
|
@@ -151,7 +159,11 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
151
159
|
|
|
152
160
|
async deleteMapping(integrationId, sourceId) {
|
|
153
161
|
const filter = this._compositeFilter(integrationId, sourceId);
|
|
154
|
-
const result = await deleteOne(
|
|
162
|
+
const result = await deleteOne(
|
|
163
|
+
this.prisma,
|
|
164
|
+
'IntegrationMapping',
|
|
165
|
+
filter
|
|
166
|
+
);
|
|
155
167
|
const deleted = result?.n ?? 0;
|
|
156
168
|
return { acknowledged: true, deletedCount: deleted };
|
|
157
169
|
}
|
|
@@ -171,11 +183,15 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
171
183
|
async findMappingById(id) {
|
|
172
184
|
const objectId = toObjectId(id);
|
|
173
185
|
if (!objectId) return null;
|
|
174
|
-
const doc = await findOne(this.prisma, 'IntegrationMapping', {
|
|
186
|
+
const doc = await findOne(this.prisma, 'IntegrationMapping', {
|
|
187
|
+
_id: objectId,
|
|
188
|
+
});
|
|
175
189
|
if (!doc) return null;
|
|
176
190
|
|
|
177
|
-
|
|
178
|
-
|
|
191
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
192
|
+
'IntegrationMapping',
|
|
193
|
+
doc
|
|
194
|
+
);
|
|
179
195
|
return this._mapMapping(decryptedMapping);
|
|
180
196
|
}
|
|
181
197
|
|
|
@@ -183,22 +199,26 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
183
199
|
const objectId = toObjectId(id);
|
|
184
200
|
if (!objectId) return null;
|
|
185
201
|
|
|
186
|
-
const existing = await findOne(this.prisma, 'IntegrationMapping', {
|
|
202
|
+
const existing = await findOne(this.prisma, 'IntegrationMapping', {
|
|
203
|
+
_id: objectId,
|
|
204
|
+
});
|
|
187
205
|
if (!existing) return null;
|
|
188
206
|
|
|
189
|
-
|
|
190
|
-
|
|
207
|
+
const decryptedExisting = await this.encryptionService.decryptFields(
|
|
208
|
+
'IntegrationMapping',
|
|
209
|
+
existing
|
|
210
|
+
);
|
|
191
211
|
|
|
192
|
-
|
|
193
|
-
|
|
212
|
+
const mergedMapping =
|
|
213
|
+
updates.mapping !== undefined
|
|
214
|
+
? updates.mapping
|
|
215
|
+
: decryptedExisting.mapping;
|
|
194
216
|
|
|
195
|
-
// Build update with other fields
|
|
196
217
|
const updateDocument = {
|
|
197
218
|
...updates,
|
|
198
219
|
updatedAt: new Date(),
|
|
199
220
|
};
|
|
200
221
|
|
|
201
|
-
// Encrypt mapping before storing
|
|
202
222
|
if (mergedMapping !== undefined) {
|
|
203
223
|
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
204
224
|
'IntegrationMapping',
|
|
@@ -216,18 +236,25 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
216
236
|
}
|
|
217
237
|
);
|
|
218
238
|
|
|
219
|
-
|
|
220
|
-
|
|
239
|
+
const updated = await findOne(this.prisma, 'IntegrationMapping', {
|
|
240
|
+
_id: objectId,
|
|
241
|
+
});
|
|
221
242
|
if (!updated) {
|
|
222
|
-
console.error(
|
|
223
|
-
|
|
224
|
-
|
|
243
|
+
console.error(
|
|
244
|
+
'[IntegrationMappingRepositoryDocumentDB] Mapping not found after update',
|
|
245
|
+
{
|
|
246
|
+
mappingId: fromObjectId(objectId),
|
|
247
|
+
}
|
|
248
|
+
);
|
|
225
249
|
throw new Error(
|
|
226
250
|
'Failed to update mapping: Document not found after update. ' +
|
|
227
|
-
|
|
251
|
+
'This indicates a database consistency issue.'
|
|
228
252
|
);
|
|
229
253
|
}
|
|
230
|
-
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
254
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
255
|
+
'IntegrationMapping',
|
|
256
|
+
updated
|
|
257
|
+
);
|
|
231
258
|
return this._mapMapping(decryptedMapping);
|
|
232
259
|
}
|
|
233
260
|
|
|
@@ -254,5 +281,3 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
254
281
|
}
|
|
255
282
|
|
|
256
283
|
module.exports = { IntegrationMappingRepositoryDocumentDB };
|
|
257
|
-
|
|
258
|
-
|
|
@@ -15,11 +15,6 @@ const {
|
|
|
15
15
|
DocumentDBEncryptionService,
|
|
16
16
|
} = require('../../database/documentdb-encryption-service');
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* @see credential-repository-documentdb.js for the same pattern
|
|
20
|
-
* @see integration-mapping-repository-documentdb.js for the same pattern
|
|
21
|
-
* @see encryption-schema-registry.js for custom schema configuration
|
|
22
|
-
*/
|
|
23
18
|
class ProcessRepositoryDocumentDB extends ProcessRepositoryInterface {
|
|
24
19
|
constructor() {
|
|
25
20
|
super();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.503.
|
|
4
|
+
"version": "2.0.0--canary.503.ce72072.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0--canary.503.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0--canary.503.
|
|
43
|
-
"@friggframework/test": "2.0.0--canary.503.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0--canary.503.ce72072.0",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0--canary.503.ce72072.0",
|
|
43
|
+
"@friggframework/test": "2.0.0--canary.503.ce72072.0",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "ce72072f759299e7fd70fc2c9fd29811d3d727a6"
|
|
84
84
|
}
|