1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | return new (P || (P = Promise))(function (resolve, reject) {
|
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8 | });
|
9 | };
|
10 | Object.defineProperty(exports, "__esModule", { value: true });
|
11 | const AWS = require("aws-sdk");
|
12 | const tools_1 = require("./tools");
|
13 | AWS.config.update({ region: 'us-east-1' });
|
14 | const kms = new AWS.KMS({ apiVersion: '2014-11-01' });
|
15 | function encrypt(data, kmsKeyId) {
|
16 | return new Promise((res, rej) => {
|
17 | try {
|
18 | if (!data || data === '') {
|
19 | return res(null);
|
20 | }
|
21 | kms.encrypt({ KeyId: kmsKeyId, Plaintext: data }, function (err, _data) {
|
22 | if (err) {
|
23 | rej(err);
|
24 | }
|
25 | else {
|
26 | res(_data);
|
27 | }
|
28 | });
|
29 | }
|
30 | catch (error) {
|
31 | rej(error.message);
|
32 | }
|
33 | });
|
34 | }
|
35 | function decrypt(blob, kmsKeyId) {
|
36 | return new Promise((res, rej) => {
|
37 | try {
|
38 | if ((blob && !blob.CiphertextBlob) || !blob) {
|
39 | return res(blob);
|
40 | }
|
41 | kms.decrypt({ CiphertextBlob: blob.CiphertextBlob }, function (err, _data) {
|
42 | if (err) {
|
43 | console.log(err);
|
44 | rej(err);
|
45 | }
|
46 | else {
|
47 | res(_data);
|
48 | }
|
49 | });
|
50 | }
|
51 | catch (error) {
|
52 | console.log(143, error.message);
|
53 | rej(error.message);
|
54 | }
|
55 | });
|
56 | }
|
57 | class DynamoDbApi {
|
58 | constructor(dynamoDb, _kmsKeyId) {
|
59 | this.dynamoDb = dynamoDb;
|
60 | this.kmsKeyId = _kmsKeyId;
|
61 | process.setMaxListeners(Infinity);
|
62 | }
|
63 | decryptItem(item, decryptFields) {
|
64 | return __awaiter(this, void 0, void 0, function* () {
|
65 | try {
|
66 | const Keys = Object.keys(item);
|
67 | for (let i = 0; i < Keys.length; i++) {
|
68 | if (item[Keys[i]] && item[Keys[i]]['CiphertextBlob'] && decryptFields.indexOf(Keys[i]) > -1) {
|
69 | const decryptedTmp = yield decrypt(item[Keys[i]], this.kmsKeyId);
|
70 | if (decryptedTmp && decryptedTmp.Plaintext) {
|
71 | const val = decryptedTmp.Plaintext.toString();
|
72 | item[Keys[i]] = val.indexOf('{') > -1 ? JSON.parse(val) : val;
|
73 | }
|
74 | }
|
75 | }
|
76 | }
|
77 | catch (error) {
|
78 | console.log('decryptItem():', error);
|
79 | }
|
80 | return item;
|
81 | });
|
82 | }
|
83 | encryptItem(item, encryptFields) {
|
84 | return __awaiter(this, void 0, void 0, function* () {
|
85 | try {
|
86 | const Keys = Object.keys(item);
|
87 | for (let i = 0; i < Keys.length; i++) {
|
88 | if (item[Keys[i]] && encryptFields.indexOf(Keys[i]) > -1) {
|
89 | const encryptedTmp = yield encrypt(typeof item[Keys[i]] === 'object' ? JSON.stringify(item[Keys[i]]) : item[Keys[i]], this.kmsKeyId);
|
90 | if (encryptedTmp) {
|
91 | item[Keys[i]] = encryptedTmp;
|
92 | }
|
93 | }
|
94 | }
|
95 | }
|
96 | catch (error) {
|
97 | console.log('tools.encryptItem() error:', error.message);
|
98 | }
|
99 | finally {
|
100 | return item;
|
101 | }
|
102 | });
|
103 | }
|
104 | get(params, context, decryptFields) {
|
105 | const dynamoDb = this.dynamoDb;
|
106 | return new Promise((res, rej) => {
|
107 | if (!dynamoDb) {
|
108 | return rej(tools_1.response(false, 'dynamoDbTable undefined'));
|
109 | }
|
110 | try {
|
111 | dynamoDb.get(params, (error, result) => __awaiter(this, void 0, void 0, function* () {
|
112 | if (error) {
|
113 | return rej(tools_1.response(false, error, `Could not get '${context}' info`));
|
114 | }
|
115 | else if (result.Item) {
|
116 | if (decryptFields && decryptFields.length) {
|
117 | result.Item = yield this.decryptItem(result.Item, decryptFields);
|
118 | }
|
119 | return res(tools_1.response(true, null, result.Item));
|
120 | }
|
121 | else {
|
122 | return res(tools_1.response(false, `'${context}' info not found`));
|
123 | }
|
124 | }));
|
125 | }
|
126 | catch (error) {
|
127 | console.log(479, error.message);
|
128 | rej(tools_1.response(false, error));
|
129 | }
|
130 | });
|
131 | }
|
132 | _scan(dynamoDb, params, context, decryptFields) {
|
133 | return __awaiter(this, void 0, void 0, function* () {
|
134 | if (!dynamoDb) {
|
135 | return tools_1.response(false, 'dynamoDbTable undefined');
|
136 | }
|
137 | try {
|
138 | let count = 0;
|
139 | const result = yield dynamoDb.scan(params).promise();
|
140 | if (result.Items && result.Items.length) {
|
141 | if (decryptFields && decryptFields.length) {
|
142 | for (let i = 0; i < result.Items.length; i++) {
|
143 | result.Items[i] = yield this.decryptItem(result.Items[i], decryptFields);
|
144 | }
|
145 | }
|
146 | return tools_1.response(true, null, result);
|
147 | }
|
148 | else {
|
149 | return tools_1.response(false, `${context} info not found`, result);
|
150 | }
|
151 | }
|
152 | catch (error) {
|
153 | console.log('263 Error tools.db._scan()', error.message, params);
|
154 | return tools_1.response(false, error);
|
155 | }
|
156 | });
|
157 | }
|
158 | scan(params, context, decryptFields) {
|
159 | return __awaiter(this, void 0, void 0, function* () {
|
160 | const dynamoDb = this.dynamoDb;
|
161 | try {
|
162 | let items = [], result, whileMax = 1000, i = 0, count = 0, done = false, LastEvaluatedKey = null;
|
163 | while (!done && (i < whileMax)) {
|
164 | result = yield this._scan(dynamoDb, params, context, decryptFields);
|
165 | if (!result.success && !params.Limit) {
|
166 | done = true;
|
167 | return result;
|
168 | }
|
169 | else {
|
170 | if (params.Limit) {
|
171 | if (result.data) {
|
172 | count += result.data.Count;
|
173 | if (!result.data.LastEvaluatedKey) {
|
174 | done = true;
|
175 | items.push(...result.data.Items);
|
176 | }
|
177 | else {
|
178 | if (count === params.Limit) {
|
179 | done = true;
|
180 | items.push(...result.data.Items);
|
181 | LastEvaluatedKey = result.data.LastEvaluatedKey;
|
182 | }
|
183 | else if (count > params.Limit) {
|
184 | done = true;
|
185 | const keys = Object.keys(result.data.LastEvaluatedKey);
|
186 | items.push(...result.data.Items.slice(0, (count - params.Limit)));
|
187 | for (let j = 0; j < keys.length; j++) {
|
188 | LastEvaluatedKey[keys[j]] = result.data.Items[count - params.Limit - 1][keys[j]];
|
189 | }
|
190 | }
|
191 | else {
|
192 | LastEvaluatedKey = result.data.LastEvaluatedKey;
|
193 | params['ExclusiveStartKey'] = LastEvaluatedKey;
|
194 | items.push(...result.data.Items);
|
195 | }
|
196 | }
|
197 | }
|
198 | else {
|
199 | LastEvaluatedKey = result.data.LastEvaluatedKey;
|
200 | params['ExclusiveStartKey'] = LastEvaluatedKey;
|
201 | }
|
202 | }
|
203 | else {
|
204 | done = true;
|
205 | LastEvaluatedKey = result.data.LastEvaluatedKey;
|
206 | items.push(...result.data.Items);
|
207 | }
|
208 | }
|
209 | i++;
|
210 | }
|
211 | return tools_1.response(true, null, {
|
212 | Items: items,
|
213 | Count: items.length,
|
214 | CountV2: result.data.ScannedCount,
|
215 | LastEvaluatedKey: LastEvaluatedKey,
|
216 | Loops: i
|
217 | });
|
218 | }
|
219 | catch (error) {
|
220 | return tools_1.response(false, error);
|
221 | }
|
222 | });
|
223 | }
|
224 | query(params, context, decryptFields) {
|
225 | return __awaiter(this, void 0, void 0, function* () {
|
226 | const dynamoDb = this.dynamoDb;
|
227 | if (!dynamoDb) {
|
228 | return tools_1.response(false, 'dynamoDbTable undefined');
|
229 | }
|
230 | try {
|
231 | const result = yield dynamoDb.query(params).promise();
|
232 | if (result.Items && result.Items.length) {
|
233 | if (decryptFields && decryptFields.length) {
|
234 | for (let i = 0; i < result.Items.length; i++) {
|
235 | result.Items[i] = yield this.decryptItem(result.Items[i], decryptFields);
|
236 | }
|
237 | }
|
238 | return tools_1.response(true, null, result.Items.length > 1 ? result.Items : result.Items[0]);
|
239 | }
|
240 | else {
|
241 | return tools_1.response(false, `'${context}' info not found`);
|
242 | }
|
243 | }
|
244 | catch (error) {
|
245 | console.log('263 Error tools.db.query()', error.message, params);
|
246 | return tools_1.response(false, error.message, `Could not get '${context}' info`);
|
247 | }
|
248 | });
|
249 | }
|
250 | queryRAW(params, context, decryptFields) {
|
251 | return __awaiter(this, void 0, void 0, function* () {
|
252 | const dynamoDb = this.dynamoDb;
|
253 | if (!dynamoDb) {
|
254 | return tools_1.response(false, 'dynamoDbTable undefined');
|
255 | }
|
256 | try {
|
257 | let result = yield dynamoDb.query(params).promise();
|
258 | if (!result) {
|
259 | return tools_1.response(false, `'${context}' - Error on dynamoDb.query(params).promise().`);
|
260 | }
|
261 | let promises = [];
|
262 | if (result.Items && result.Items.length) {
|
263 | if (decryptFields && decryptFields.length) {
|
264 | for (let i = 0; i < result.Items.length; i++) {
|
265 | promises.push(this.decryptItem(result.Items[i], decryptFields));
|
266 | }
|
267 | result = yield Promise.all(promises).then(results => {
|
268 | delete result.Items;
|
269 | result['Items'] = results;
|
270 | return result;
|
271 | });
|
272 | }
|
273 | return tools_1.response(true, null, result);
|
274 | }
|
275 | else {
|
276 | return tools_1.response(false, `'${context}' info not found`, result);
|
277 | }
|
278 | }
|
279 | catch (error) {
|
280 | console.log('263 Error tools.db.query()', error.message, params);
|
281 | return tools_1.response(false, error.message, `Could not get '${context}' info`);
|
282 | }
|
283 | });
|
284 | }
|
285 | delete(params, context, decryptFields) {
|
286 | const dynamoDb = this.dynamoDb;
|
287 | return new Promise((res, rej) => {
|
288 | if (!dynamoDb) {
|
289 | return rej(tools_1.response(false, 'dynamoDbTable undefined'));
|
290 | }
|
291 | try {
|
292 | if (params.force) {
|
293 | dynamoDb.delete(params, (error, result) => __awaiter(this, void 0, void 0, function* () {
|
294 | if (error) {
|
295 | return rej(tools_1.response(false, error, `Could not delete '${context}' info`));
|
296 | }
|
297 | return res(tools_1.response(true, null, result));
|
298 | }));
|
299 | }
|
300 | else {
|
301 | if (!params.Key) {
|
302 | return tools_1.response(false, 'Key is required. Cannot delete item');
|
303 | }
|
304 | const _params = {
|
305 | TableName: params.TableName,
|
306 | Key: params.Key,
|
307 | UpdateExpression: "set deleted =:d",
|
308 | ExpressionAttributeValues: {
|
309 | ":d": true
|
310 | }
|
311 | };
|
312 | dynamoDb.update(_params, (error, result) => {
|
313 | if (error) {
|
314 | console.log(params, error);
|
315 | return rej(tools_1.response(false, error, `Could not update '${context}' item to 'deleted' state`));
|
316 | }
|
317 | else {
|
318 | return res(tools_1.response(true, null, result));
|
319 | }
|
320 | });
|
321 | }
|
322 | }
|
323 | catch (error) {
|
324 | console.log(479, error.message);
|
325 | rej(tools_1.response(false, error));
|
326 | }
|
327 | });
|
328 | }
|
329 | put(params, context, encryptFields) {
|
330 | return new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
|
331 | const dynamoDb = this.dynamoDb;
|
332 | try {
|
333 | if (!dynamoDb) {
|
334 | return rej(tools_1.response(false, 'dynamoDbTable undefined'));
|
335 | }
|
336 | if (encryptFields && encryptFields.length) {
|
337 | params.Item = yield this.encryptItem(params.Item, encryptFields);
|
338 | }
|
339 | params.Item.updatedAt = new Date().toISOString();
|
340 | params.Item.createdAt = new Date().toISOString();
|
341 | dynamoDb.put(params, (error, result) => {
|
342 | if (error) {
|
343 | console.log(params, error);
|
344 | return rej(tools_1.response(false, error, `Could not insert '${context}' item`));
|
345 | }
|
346 | else {
|
347 | return res(tools_1.response(true, null, result));
|
348 | }
|
349 | });
|
350 | }
|
351 | catch (error) {
|
352 | console.log('295 tools.db.put()', error);
|
353 | rej(tools_1.response(false, error.message));
|
354 | }
|
355 | }));
|
356 | }
|
357 | getUpdateExpression(item, encryptFields) {
|
358 | return __awaiter(this, void 0, void 0, function* () {
|
359 | let expressions = {}, updates = '';
|
360 | if (encryptFields) {
|
361 | item = yield this.encryptItem(item, encryptFields);
|
362 | }
|
363 | const Keys = Object.keys(item);
|
364 | for (let i = 0; i < Keys.length; i++) {
|
365 | expressions[`:v${i}`] = item[Keys[i]];
|
366 | updates += `${Keys[i]} =:v${i},`;
|
367 | }
|
368 | updates = updates.replace(/(^,)|(,$)/g, "");
|
369 | return {
|
370 | expressions: expressions,
|
371 | updates: updates
|
372 | };
|
373 | });
|
374 | }
|
375 | getUpdateExpressionV2(item, encryptFields) {
|
376 | return __awaiter(this, void 0, void 0, function* () {
|
377 | let attributesValue = {}, attributesName = {}, updates = '';
|
378 | if (encryptFields) {
|
379 | item = yield this.encryptItem(item, encryptFields);
|
380 | }
|
381 | const Keys = Object.keys(item);
|
382 | for (let i = 0; i < Keys.length; i++) {
|
383 | attributesValue[`:v${i}`] = item[Keys[i]];
|
384 | attributesName[`#a${i}`] = Keys[i];
|
385 | updates += `#a${i} =:v${i},`;
|
386 | }
|
387 | updates = updates.replace(/(^,)|(,$)/g, "");
|
388 | return {
|
389 | attributesValue: attributesValue,
|
390 | updates: updates,
|
391 | attributesName: attributesName
|
392 | };
|
393 | });
|
394 | }
|
395 | update(params, context, encryptFields) {
|
396 | const dynamoDb = this.dynamoDb;
|
397 | return new Promise((res, rej) => {
|
398 | if (!dynamoDb) {
|
399 | return rej(tools_1.response(false, 'dynamoDbTable undefined'));
|
400 | }
|
401 | try {
|
402 | params.ExpressionAttributeValues[':upd'] = new Date().toISOString();
|
403 | params.UpdateExpression += ', updatedAt =:upd';
|
404 | dynamoDb.update(params, (error, result) => {
|
405 | if (error) {
|
406 | console.log(params, error);
|
407 | return rej(tools_1.response(false, error));
|
408 | }
|
409 | else {
|
410 | return res(tools_1.response(true, null, result));
|
411 | }
|
412 | });
|
413 | }
|
414 | catch (error) {
|
415 | console.log(error);
|
416 | rej(tools_1.response(false, error));
|
417 | }
|
418 | });
|
419 | }
|
420 | }
|
421 | exports.DynamoDbApi = DynamoDbApi;
|
422 |
|
\ | No newline at end of file |