ag-common 0.0.91 → 0.0.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ export declare const enforceDynamoProvisionCap: ({ tables, readsMax, writesMax, }: {
2
+ tables: any[];
3
+ /**
4
+ * default 25
5
+ */
6
+ readsMax?: number | undefined;
7
+ /**
8
+ * default 25
9
+ */
10
+ writesMax?: number | undefined;
11
+ }) => void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enforceDynamoProvisionCap = void 0;
4
+ const log_1 = require("../../common/helpers/log");
5
+ const math_1 = require("../../common/helpers/math");
6
+ const string_1 = require("../../common/helpers/string");
7
+ const extractSum = ({ str, regex }) => {
8
+ var _a;
9
+ return (0, math_1.sumArray)(((_a = str
10
+ .match(regex)) === null || _a === void 0 ? void 0 : _a.map((s2) => (0, string_1.trim)(s2.substring(s2.indexOf(':') + 1), ':', ',', ' ')).filter((r) => r && Number(r)).map((r) => Number(r))) || []);
11
+ };
12
+ const enforceDynamoProvisionCap = ({ tables, readsMax = 25, writesMax = 25, }) => {
13
+ if (!tables || tables.length === 0) {
14
+ (0, log_1.warn)('error in dynamo FT enforce');
15
+ return;
16
+ }
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ const t = tables[0];
19
+ const s = (0, string_1.safeStringify)(t.node._children.Resource.node.scope);
20
+ const reads = extractSum({ str: s, regex: /readCapacityUnits.*/gim });
21
+ const writes = extractSum({ str: s, regex: /writeCapacityUnits.*/gim });
22
+ if (reads > readsMax) {
23
+ throw new Error(`dynamo table provisioned reads:${reads} greater than max:${readsMax}`);
24
+ }
25
+ if (writes > writesMax) {
26
+ throw new Error(`dynamo table provisioned writes:${writes} greater than max:${writesMax}`);
27
+ }
28
+ (0, log_1.warn)(`dynamo provisioned total: R=${reads} W=${writes}`);
29
+ };
30
+ exports.enforceDynamoProvisionCap = enforceDynamoProvisionCap;
@@ -1,6 +1,7 @@
1
1
  export * from './api';
2
2
  export * from './aws';
3
3
  export * from './dynamo';
4
+ export * from './enforceDynamoProvisionCap';
4
5
  export * from './dynamoInfra';
5
6
  export * from './openApiHelpers';
6
7
  export * from './s3';
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  __exportStar(require("./api"), exports);
14
14
  __exportStar(require("./aws"), exports);
15
15
  __exportStar(require("./dynamo"), exports);
16
+ __exportStar(require("./enforceDynamoProvisionCap"), exports);
16
17
  __exportStar(require("./dynamoInfra"), exports);
17
18
  __exportStar(require("./openApiHelpers"), exports);
18
19
  __exportStar(require("./s3"), exports);
@@ -8,10 +8,14 @@ export declare type NextType<T> = ({ event, body, params, userProfile, lang, }:
8
8
  userProfile?: User;
9
9
  lang: TLang;
10
10
  }) => Promise<APIGatewayProxyResult>;
11
- export declare function validateOpenApi<T>({ event, next, authorized, schema, COGNITO_USER_POOL_ID, }: {
11
+ export declare function validateOpenApi<T>({ event, next, authorized, schema, COGNITO_USER_POOL_ID, jwksRegion, }: {
12
12
  COGNITO_USER_POOL_ID: string;
13
13
  schema: any;
14
14
  event: APIGatewayEvent;
15
15
  next: NextType<T>;
16
16
  authorized?: true | false | 'optional';
17
+ /**
18
+ * default ap-southeast-2
19
+ */
20
+ jwksRegion?: string;
17
21
  }): Promise<APIGatewayProxyResult>;
@@ -43,7 +43,7 @@ const getOperation = ({ path, method, resource, schema, }) => {
43
43
  const pathParams = (re === null || re === void 0 ? void 0 : re.groups) && JSON.parse(JSON.stringify(re === null || re === void 0 ? void 0 : re.groups));
44
44
  return { operation, pathParams };
45
45
  };
46
- function validateOpenApi({ event, next, authorized, schema, COGNITO_USER_POOL_ID, }) {
46
+ function validateOpenApi({ event, next, authorized, schema, COGNITO_USER_POOL_ID, jwksRegion = 'ap-southeast-2', }) {
47
47
  var _a, _b, _c, _d, _e;
48
48
  return __awaiter(this, void 0, void 0, function* () {
49
49
  if (!schema) {
@@ -107,6 +107,7 @@ function validateOpenApi({ event, next, authorized, schema, COGNITO_USER_POOL_ID
107
107
  ({ error, userProfile } = yield (0, validations_1.getAndValidateToken)({
108
108
  tokenRaw: authHeader,
109
109
  COGNITO_USER_POOL_ID,
110
+ jwksRegion,
110
111
  }));
111
112
  if (error) {
112
113
  return error;
@@ -2,6 +2,9 @@ import { error } from '../../common/helpers/log';
2
2
  import { User } from '../../ui/helpers/jwt';
3
3
  import { APIGatewayProxyResult } from '../types';
4
4
  export declare const getAndValidateToken: ({ tokenRaw, jwksRegion, COGNITO_USER_POOL_ID, }: {
5
+ /**
6
+ * default ap-southeast-2
7
+ */
5
8
  jwksRegion?: string | undefined;
6
9
  tokenRaw?: string | undefined;
7
10
  COGNITO_USER_POOL_ID: string;
@@ -65,17 +65,32 @@ const getAndValidateToken = ({ tokenRaw, jwksRegion = 'ap-southeast-2', COGNITO_
65
65
  let token = '';
66
66
  try {
67
67
  if (!tokenRaw) {
68
- (0, log_1.error)('no auth headers');
68
+ const m = 'auth error: no auth headers';
69
+ (0, log_1.error)(m);
69
70
  return {
70
- error: (0, api_1.returnCode)(403, 'auth failed'),
71
+ error: (0, api_1.returnCode)(403, m),
71
72
  };
72
73
  }
73
74
  token = tokenRaw.substring(tokenRaw.indexOf(' ') + 1);
75
+ if (!token) {
76
+ const m = 'auth error: no token';
77
+ (0, log_1.error)(m);
78
+ return {
79
+ error: (0, api_1.returnCode)(403, m),
80
+ };
81
+ }
74
82
  let subject;
75
83
  try {
76
84
  yield jwtVerify({ token, jwksUri, issuer });
77
85
  const decoded = (0, jsonwebtoken_1.decode)(token);
78
86
  (0, log_1.debug)(`decoded=${JSON.stringify(decoded, null, 2)}`);
87
+ if (!decoded.email) {
88
+ const m = 'auth error, no email';
89
+ (0, log_1.error)(m);
90
+ return {
91
+ error: (0, api_1.returnCode)(403, m),
92
+ };
93
+ }
79
94
  subject = decoded === null || decoded === void 0 ? void 0 : decoded.sub;
80
95
  if (!subject) {
81
96
  const mess = 'user should have responded with subject (sub) field';
@@ -96,12 +111,6 @@ const getAndValidateToken = ({ tokenRaw, jwksRegion = 'ap-southeast-2', COGNITO_
96
111
  picture,
97
112
  updatedAt: parseInt(`${decoded.auth_time}000`, 10),
98
113
  };
99
- if (!userProfile || !token || !userProfile.userId) {
100
- (0, log_1.error)('auth fail');
101
- return {
102
- error: (0, api_1.returnCode)(403, 'auth fail'),
103
- };
104
- }
105
114
  return { token, userProfile };
106
115
  }
107
116
  catch (e) {
@@ -114,9 +123,10 @@ const getAndValidateToken = ({ tokenRaw, jwksRegion = 'ap-southeast-2', COGNITO_
114
123
  }
115
124
  }
116
125
  catch (e) {
117
- (0, log_1.error)('auth error', e);
126
+ const m = 'auth error:' + JSON.stringify(e, null, 2);
127
+ (0, log_1.error)(m);
118
128
  return {
119
- error: (0, api_1.returnCode)(403, 'auth fail'),
129
+ error: (0, api_1.returnCode)(403, m),
120
130
  };
121
131
  }
122
132
  });
@@ -24,3 +24,10 @@ export declare function toTitleCase(str: string): string;
24
24
  */
25
25
  export declare function replaceRemove(str: string, ...params: string[]): string;
26
26
  export declare function containsInsensitive(str: string, ...args: string[]): boolean;
27
+ /**
28
+ * safely handles circular references
29
+ * @param obj
30
+ * @param indent
31
+ * @returns
32
+ */
33
+ export declare const safeStringify: (obj: any, indent?: number) => string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.containsInsensitive = exports.replaceRemove = exports.toTitleCase = exports.niceUrl = exports.truncate = exports.trim = exports.trimSide = exports.csvJSON = void 0;
3
+ exports.safeStringify = exports.containsInsensitive = exports.replaceRemove = exports.toTitleCase = exports.niceUrl = exports.truncate = exports.trim = exports.trimSide = exports.csvJSON = void 0;
4
4
  const csvJSON = (csv) => {
5
5
  const lines = csv.split('\n');
6
6
  const result = [];
@@ -117,3 +117,22 @@ function containsInsensitive(str, ...args) {
117
117
  return !!args.find((a) => l.includes(a));
118
118
  }
119
119
  exports.containsInsensitive = containsInsensitive;
120
+ /**
121
+ * safely handles circular references
122
+ * @param obj
123
+ * @param indent
124
+ * @returns
125
+ */
126
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
127
+ const safeStringify = (obj, indent = 2) => {
128
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
+ let cache = [];
130
+ const retVal = JSON.stringify(obj, (_key, value) => typeof value === 'object' && value !== null
131
+ ? cache.includes(value)
132
+ ? undefined // Duplicate reference found, discard key
133
+ : cache.push(value) && value // Store value in our collection
134
+ : value, indent);
135
+ cache = null;
136
+ return retVal;
137
+ };
138
+ exports.safeStringify = safeStringify;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ag-common",
3
- "version": "0.0.91",
3
+ "version": "0.0.95",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Andrei Gec <@andreigec> (https://gec.dev/)",