@izara_project/izara-core-generate-service-code 1.0.85 → 1.0.87
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/package.json +1 -1
- package/src/compile/compileProject.js +1 -2
- package/src/compile/loadSchemas.js +29 -17
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +2 -1
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +32 -14
- package/src/emit/crud/crudActionPlan.js +1 -1
- package/src/emit/crud/emitCrudApplicationArtifacts.js +10 -4
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +16 -8
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +12 -3
- package/src/emit/crud/templates/CreateLogicalLib.ejs +85 -20
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +48 -7
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +47 -6
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +754 -353
- package/src/emit/function/functionYamlArtifact.js +4 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +5 -5
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +70 -89
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +14 -10
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +14 -10
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +56 -16
- package/src/emit/rbac/templates/DeleteTargetRole_Main.ejs +96 -0
- package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +110 -0
- package/src/emit/rbac/templates/GetTargetRole_Main.ejs +62 -0
- package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +76 -34
- package/src/emit/rbac/templates/UpdateTargetRole_Main.ejs +107 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +24 -21
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +12 -0
- package/src/emit/resource/emitResourceArtifacts.js +75 -8
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +4 -2
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +14 -18
- package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +4 -2
- package/src/emit/systemText/emitSystemTextSchemas.js +5 -2
- package/src/generate.js +18 -12
- package/src/generateResources/IntTest/generateResources/generateResources.js +1 -1
- package/src/generateResources/IntTest/generateTests/generateTemplate.js +1 -1
- package/src/generateResources/IntTest/upload/uploadIntTest.js +8 -2
- package/test/createTargetRoleHandler.test.js +42 -15
- package/test/crudApplicationArtifacts.test.js +62 -3
- package/test/customFlowApplicationArtifacts.test.js +3 -5
- package/test/dynamicCrudFlowSchemas.test.js +5 -17
- package/test/dynamicRbacFlowSchemas.test.js +5 -5
- package/test/functionYamlArtifact.test.js +4 -2
- package/test/publicApi.test.js +18 -14
- package/test/resourceArtifacts.test.js +7 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2020 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
19
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
20
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
21
|
+
import { NoRetryError } from '@izara_project/izara-core-library-core';
|
|
22
|
+
|
|
23
|
+
export default async function GetTargetRole(_izContext, requestParams) {
|
|
24
|
+
try {
|
|
25
|
+
const { identifiersConcat, roleIdKey } = requestParams;
|
|
26
|
+
if (!roleIdKey) {
|
|
27
|
+
throw new NoRetryError('roleIdKey is required');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const targetRolesTable = dynamodbSharedLib.tableName(_izContext, 'TargetRoles');
|
|
31
|
+
const rolePermissionsTable = dynamodbSharedLib.tableName(_izContext, 'RolePermissions');
|
|
32
|
+
const roleUsersTable = dynamodbSharedLib.tableName(_izContext, 'RoleUsers');
|
|
33
|
+
|
|
34
|
+
const role = identifiersConcat
|
|
35
|
+
? await dynamodbSharedLib.getItem(_izContext, targetRolesTable, { identifiersConcat, roleIdKey })
|
|
36
|
+
: null;
|
|
37
|
+
|
|
38
|
+
const [permsResult, usersResult] = await Promise.all([
|
|
39
|
+
dynamodbSharedLib.query(_izContext, rolePermissionsTable, { roleIdKey }),
|
|
40
|
+
dynamodbSharedLib.query(_izContext, roleUsersTable, { roleIdKey })
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const result = {
|
|
44
|
+
role,
|
|
45
|
+
roleIdKey,
|
|
46
|
+
permissions: permsResult?.Items || [],
|
|
47
|
+
users: usersResult?.Items || []
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
await sns.publishMessage(_izContext, {
|
|
51
|
+
message: { returnResult: result },
|
|
52
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
53
|
+
_izContext,
|
|
54
|
+
'GetTargetRole_Out'
|
|
55
|
+
)
|
|
56
|
+
});
|
|
57
|
+
return result;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:GetTargetRole] error:`, error);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -35,21 +35,25 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
|
|
|
35
35
|
} = requestParams;
|
|
36
36
|
|
|
37
37
|
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
38
|
-
let identifiersConcat =
|
|
38
|
+
let identifiersConcat =
|
|
39
|
+
requestParams.identifiersConcat || requestParams.identifierConcat;
|
|
39
40
|
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
40
|
-
if (targetIdentifiers.identifierConcat) {
|
|
41
|
-
identifiersConcat =
|
|
41
|
+
if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
|
|
42
|
+
identifiersConcat =
|
|
43
|
+
targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
|
|
42
44
|
} else {
|
|
43
|
-
const sortedKeys = Object.keys(targetIdentifiers)
|
|
45
|
+
const sortedKeys = Object.keys(targetIdentifiers)
|
|
46
|
+
.filter(
|
|
47
|
+
(k) =>
|
|
48
|
+
k !== 'submittedByUserId' &&
|
|
49
|
+
k !== 'identifierConcat' &&
|
|
50
|
+
k !== 'identifiersConcat'
|
|
51
|
+
)
|
|
52
|
+
.sort();
|
|
44
53
|
const parts = [];
|
|
45
54
|
for (const key of sortedKeys) {
|
|
46
55
|
const value = targetIdentifiers[key];
|
|
47
|
-
if (
|
|
48
|
-
key !== 'submittedByUserId' &&
|
|
49
|
-
key !== 'identifierConcat' &&
|
|
50
|
-
value !== undefined &&
|
|
51
|
-
value !== null
|
|
52
|
-
) {
|
|
56
|
+
if (value !== undefined && value !== null) {
|
|
53
57
|
parts.push(`${key}#${value}`);
|
|
54
58
|
}
|
|
55
59
|
}
|
|
@@ -70,41 +74,79 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
const uniqueIdentify = `${usedTimestamp}_${_izContext.uniqueRequestId || Date.now()}`;
|
|
73
|
-
const roleLimitKeys = Array.isArray(requestParams.roleLimitIds)
|
|
74
|
-
? requestParams.roleLimitIds
|
|
75
|
-
: [roleLimitId || `${identifiersConcat}_${flowTypeConcat}`];
|
|
76
77
|
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
for (const key of roleLimitKeys) {
|
|
81
|
-
const record = await dynamodbSharedLib.getItem(
|
|
78
|
+
let targetPlanTier = requestParams.planTier || null;
|
|
79
|
+
if (!targetPlanTier && identifiersConcat) {
|
|
80
|
+
const targetRolesResult = await dynamodbSharedLib.query(
|
|
82
81
|
_izContext,
|
|
83
|
-
dynamodbSharedLib.tableName(_izContext, '
|
|
84
|
-
{
|
|
82
|
+
dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
|
|
83
|
+
{ identifiersConcat }
|
|
85
84
|
);
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
let targetRoleItems = [];
|
|
86
|
+
if (Array.isArray(targetRolesResult)) {
|
|
87
|
+
targetRoleItems = targetRolesResult;
|
|
88
|
+
} else if (targetRolesResult && targetRolesResult.Items) {
|
|
89
|
+
targetRoleItems = targetRolesResult.Items;
|
|
90
|
+
}
|
|
91
|
+
for (const roleItem of targetRoleItems) {
|
|
92
|
+
if (roleItem.roleType === 'plan_tier') {
|
|
93
|
+
targetPlanTier = roleItem.roleIdKey;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!targetPlanTier) {
|
|
99
|
+
targetPlanTier = 'tier-free';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const limitRecords = [];
|
|
103
|
+
const tierPermission = await dynamodbSharedLib.getItem(
|
|
104
|
+
_izContext,
|
|
105
|
+
dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
|
|
106
|
+
{ roleIdKey: targetPlanTier, flowTypeConcat }
|
|
107
|
+
);
|
|
108
|
+
if (tierPermission && typeof tierPermission.limitValue === 'number') {
|
|
109
|
+
limitRecords.push(tierPermission);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (Array.isArray(requestParams.roleIdKeys)) {
|
|
113
|
+
for (const rKey of requestParams.roleIdKeys) {
|
|
114
|
+
const perm = await dynamodbSharedLib.getItem(
|
|
115
|
+
_izContext,
|
|
116
|
+
dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
|
|
117
|
+
{ roleIdKey: rKey, flowTypeConcat }
|
|
118
|
+
);
|
|
119
|
+
if (perm && typeof perm.limitValue === 'number') {
|
|
120
|
+
limitRecords.push(perm);
|
|
121
|
+
}
|
|
88
122
|
}
|
|
89
123
|
}
|
|
90
124
|
|
|
125
|
+
let maxLimit = Infinity;
|
|
91
126
|
if (limitRecords.length > 0) {
|
|
92
|
-
const isDecrease = (rec)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
127
|
+
const isDecrease = function (rec) {
|
|
128
|
+
if (
|
|
129
|
+
rec.effect === 'decrease' ||
|
|
130
|
+
rec.actionType === 'decrease' ||
|
|
131
|
+
rec.action === 'decrease'
|
|
132
|
+
) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
};
|
|
96
137
|
|
|
97
138
|
const increaseLimits = limitRecords.filter((rec) => !isDecrease(rec));
|
|
98
139
|
const decreaseLimits = limitRecords.filter((rec) => isDecrease(rec));
|
|
99
140
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
let maxIncrease = Infinity;
|
|
142
|
+
if (increaseLimits.length > 0) {
|
|
143
|
+
maxIncrease = Math.max(...increaseLimits.map((r) => r.limitValue));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let minDecrease = Infinity;
|
|
147
|
+
if (decreaseLimits.length > 0) {
|
|
148
|
+
minDecrease = Math.min(...decreaseLimits.map((r) => r.limitValue));
|
|
149
|
+
}
|
|
108
150
|
|
|
109
151
|
maxLimit = Math.min(maxIncrease, minDecrease);
|
|
110
152
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2020 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
19
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
20
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
21
|
+
import { consts, NoRetryError } from '@izara_project/izara-core-library-core';
|
|
22
|
+
|
|
23
|
+
export default async function UpdateTargetRole(_izContext, requestParams) {
|
|
24
|
+
try {
|
|
25
|
+
const submittedByUserId =
|
|
26
|
+
requestParams.submittedByUserId ||
|
|
27
|
+
_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
identifiersConcat,
|
|
31
|
+
roleIdKey,
|
|
32
|
+
roleName,
|
|
33
|
+
permissions
|
|
34
|
+
} = requestParams;
|
|
35
|
+
|
|
36
|
+
if (!roleIdKey) {
|
|
37
|
+
throw new NoRetryError('roleIdKey is required');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (roleIdKey.endsWith('_owner')) {
|
|
41
|
+
throw new NoRetryError('Cannot modify system owner role');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const targetRolesTable = dynamodbSharedLib.tableName(_izContext, 'TargetRoles');
|
|
45
|
+
const rolePermissionsTable = dynamodbSharedLib.tableName(_izContext, 'RolePermissions');
|
|
46
|
+
|
|
47
|
+
if (roleName && identifiersConcat) {
|
|
48
|
+
const existingRole = await dynamodbSharedLib.getItem(_izContext, targetRolesTable, {
|
|
49
|
+
identifiersConcat,
|
|
50
|
+
roleIdKey
|
|
51
|
+
});
|
|
52
|
+
if (existingRole) {
|
|
53
|
+
await dynamodbSharedLib.putItem(_izContext, targetRolesTable, {
|
|
54
|
+
...existingRole,
|
|
55
|
+
roleName
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (Array.isArray(permissions)) {
|
|
61
|
+
const currentPermsQuery = await dynamodbSharedLib.query(_izContext, rolePermissionsTable, {
|
|
62
|
+
roleIdKey
|
|
63
|
+
});
|
|
64
|
+
const currentPerms = currentPermsQuery?.Items || [];
|
|
65
|
+
const currentFlowMap = new Map(currentPerms.map((p) => [p.flowTypeConcat, p]));
|
|
66
|
+
|
|
67
|
+
const newFlowSet = new Set();
|
|
68
|
+
for (const perm of permissions) {
|
|
69
|
+
const flowTypeConcat = typeof perm === 'string' ? perm : perm.flowTypeConcat;
|
|
70
|
+
if (flowTypeConcat) {
|
|
71
|
+
newFlowSet.add(flowTypeConcat);
|
|
72
|
+
const permission =
|
|
73
|
+
typeof perm === 'object' && perm.permission !== undefined
|
|
74
|
+
? perm.permission
|
|
75
|
+
: true;
|
|
76
|
+
const parameterGroups = (typeof perm === 'object' && perm.parameterGroups) || {};
|
|
77
|
+
await dynamodbSharedLib.putItem(_izContext, rolePermissionsTable, {
|
|
78
|
+
roleIdKey,
|
|
79
|
+
flowTypeConcat,
|
|
80
|
+
permission,
|
|
81
|
+
parameterGroups
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const [oldFlow] of currentFlowMap.entries()) {
|
|
87
|
+
if (!newFlowSet.has(oldFlow)) {
|
|
88
|
+
await dynamodbSharedLib.deleteItem(_izContext, rolePermissionsTable, {
|
|
89
|
+
roleIdKey,
|
|
90
|
+
flowTypeConcat: oldFlow
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await sns.publishMessage(_izContext, {
|
|
97
|
+
message: { returnResult: { roleIdKey, status: 'updated' } },
|
|
98
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
99
|
+
_izContext,
|
|
100
|
+
'UpdateTargetRole_Out'
|
|
101
|
+
)
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:UpdateTargetRole] error:`, error);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -52,7 +52,7 @@ async function _getL2Cache(_izContext, submittedByUserId, cacheSubKey) {
|
|
|
52
52
|
try {
|
|
53
53
|
const tableName = dynamodbSharedLib.tableName(_izContext, 'RbacPermissionCaches');
|
|
54
54
|
const result = await dynamodbSharedLib.getItem(_izContext, tableName, {
|
|
55
|
-
submittedByUserId,
|
|
55
|
+
userId: submittedByUserId,
|
|
56
56
|
cacheKey: cacheSubKey
|
|
57
57
|
});
|
|
58
58
|
if (result && result.ttlTimestamp && result.ttlTimestamp > Math.floor(Date.now() / 1000)) {
|
|
@@ -77,7 +77,7 @@ async function _setL2Cache(_izContext, submittedByUserId, cacheSubKey, value) {
|
|
|
77
77
|
const tableName = dynamodbSharedLib.tableName(_izContext, 'RbacPermissionCaches');
|
|
78
78
|
const ttlTimestamp = Math.floor(Date.now() / 1000) + L2_TTL_SECONDS;
|
|
79
79
|
await dynamodbSharedLib.putItem(_izContext, tableName, {
|
|
80
|
-
submittedByUserId,
|
|
80
|
+
userId: submittedByUserId,
|
|
81
81
|
cacheKey: cacheSubKey,
|
|
82
82
|
permission: value.returnValue ? value.returnValue.permission : value.permission,
|
|
83
83
|
roleIdKey: value.returnValue ? value.returnValue.roleIdKey : value.roleIdKey,
|
|
@@ -101,19 +101,22 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
101
101
|
if (typeof targetIdentifiers === 'string') {
|
|
102
102
|
targetId = targetIdentifiers;
|
|
103
103
|
} else if (typeof targetIdentifiers === 'object') {
|
|
104
|
-
if (targetIdentifiers.identifierConcat) {
|
|
105
|
-
targetId =
|
|
104
|
+
if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
|
|
105
|
+
targetId =
|
|
106
|
+
targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
|
|
106
107
|
} else {
|
|
107
|
-
const sortedKeys = Object.keys(targetIdentifiers)
|
|
108
|
+
const sortedKeys = Object.keys(targetIdentifiers)
|
|
109
|
+
.filter(
|
|
110
|
+
(k) =>
|
|
111
|
+
k !== 'submittedByUserId' &&
|
|
112
|
+
k !== 'identifierConcat' &&
|
|
113
|
+
k !== 'identifiersConcat'
|
|
114
|
+
)
|
|
115
|
+
.sort();
|
|
108
116
|
const parts = [];
|
|
109
117
|
for (const key of sortedKeys) {
|
|
110
118
|
const value = targetIdentifiers[key];
|
|
111
|
-
if (
|
|
112
|
-
key !== 'submittedByUserId' &&
|
|
113
|
-
key !== 'identifierConcat' &&
|
|
114
|
-
value !== undefined &&
|
|
115
|
-
value !== null
|
|
116
|
-
) {
|
|
119
|
+
if (value !== undefined && value !== null) {
|
|
117
120
|
parts.push(`${key}#${value}`);
|
|
118
121
|
}
|
|
119
122
|
}
|
|
@@ -133,7 +136,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
133
136
|
throw new Error('Missing flowTypeConcat in requestParams');
|
|
134
137
|
}
|
|
135
138
|
|
|
136
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams
|
|
139
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams:`, {
|
|
137
140
|
submittedByUserId,
|
|
138
141
|
targetId,
|
|
139
142
|
flowTypeConcat,
|
|
@@ -175,7 +178,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
175
178
|
// 1. Check L1 In-Memory Cache
|
|
176
179
|
const l1Hit = _getL1Cache(fullCacheKey);
|
|
177
180
|
if (l1Hit) {
|
|
178
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L1 Cache hit
|
|
181
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L1 Cache hit:`, l1Hit);
|
|
179
182
|
await _publicMessageOut(_izContext, { ...l1Hit, parentFlowId });
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
@@ -183,19 +186,19 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
183
186
|
// 2. Check L2 Shared DynamoDB Cache
|
|
184
187
|
const l2Hit = await _getL2Cache(_izContext, submittedByUserId, cacheSubKey);
|
|
185
188
|
if (l2Hit) {
|
|
186
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L2 Cache hit
|
|
189
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L2 Cache hit:`, l2Hit);
|
|
187
190
|
_setL1Cache(fullCacheKey, l2Hit);
|
|
188
191
|
await _publicMessageOut(_izContext, { ...l2Hit, parentFlowId });
|
|
189
192
|
return;
|
|
190
193
|
}
|
|
191
194
|
|
|
192
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Cache miss — querying DynamoDB
|
|
195
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Cache miss — querying DynamoDB`);
|
|
193
196
|
|
|
194
197
|
// 3. Fallback to DB Query
|
|
195
198
|
const userRolesResult = await dynamodbSharedLib.query(
|
|
196
199
|
_izContext,
|
|
197
200
|
dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
|
|
198
|
-
{ submittedByUserId }
|
|
201
|
+
{ userId: submittedByUserId }
|
|
199
202
|
);
|
|
200
203
|
|
|
201
204
|
let userRoles = [];
|
|
@@ -205,7 +208,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
205
208
|
userRoles = userRolesResult.Items;
|
|
206
209
|
}
|
|
207
210
|
|
|
208
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] userRoles fetched
|
|
211
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] userRoles fetched:`, { userRoles });
|
|
209
212
|
|
|
210
213
|
const targetIdPrefix = `${targetId}_`;
|
|
211
214
|
const targetRoles = [];
|
|
@@ -215,13 +218,13 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
215
218
|
}
|
|
216
219
|
}
|
|
217
220
|
|
|
218
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] targetRoles filtered
|
|
221
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] targetRoles filtered:`, {
|
|
219
222
|
targetIdPrefix,
|
|
220
223
|
targetRoles
|
|
221
224
|
});
|
|
222
225
|
|
|
223
226
|
if (targetRoles.length === 0) {
|
|
224
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] no targetRoles found, permission denied
|
|
227
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] no targetRoles found, permission denied`);
|
|
225
228
|
const result = {
|
|
226
229
|
returnValue: {
|
|
227
230
|
permission: false,
|
|
@@ -250,7 +253,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
250
253
|
})
|
|
251
254
|
);
|
|
252
255
|
|
|
253
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] rolePermissions fetched
|
|
256
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] rolePermissions fetched:`, {
|
|
254
257
|
rolePermissions
|
|
255
258
|
});
|
|
256
259
|
|
|
@@ -278,7 +281,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
278
281
|
status: 'Completed'
|
|
279
282
|
};
|
|
280
283
|
|
|
281
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] validation result
|
|
284
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] validation result:`, cacheResult);
|
|
282
285
|
|
|
283
286
|
// Store in L1 & L2 Cache
|
|
284
287
|
_setL1Cache(fullCacheKey, cacheResult);
|
|
@@ -26,6 +26,18 @@ import { sns } from '@izara_project/izara-core-library-external-request';
|
|
|
26
26
|
export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
27
27
|
try {
|
|
28
28
|
const { roleIdKey, userId } = requestParams;
|
|
29
|
+
<% if (operation === 'Delete') { -%>
|
|
30
|
+
if (roleIdKey && roleIdKey.endsWith('_owner')) {
|
|
31
|
+
const remainingUsers = await dynamodbSharedLib.query(
|
|
32
|
+
_izContext,
|
|
33
|
+
dynamodbSharedLib.tableName(_izContext, 'RoleUsers'),
|
|
34
|
+
{ roleIdKey }
|
|
35
|
+
);
|
|
36
|
+
if (remainingUsers?.Items?.length <= 1) {
|
|
37
|
+
throw new Error('Cannot remove the last remaining owner');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
<% } -%>
|
|
29
41
|
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
30
42
|
{
|
|
31
43
|
action: '<%- action %>',
|
|
@@ -31,18 +31,18 @@ const RELATIONSHIP_ACTIONS = [
|
|
|
31
31
|
];
|
|
32
32
|
const RBAC_ACTIONS = [
|
|
33
33
|
'CreateTargetRole',
|
|
34
|
-
'
|
|
34
|
+
'UpdateTargetRole',
|
|
35
35
|
'DeleteTargetRole',
|
|
36
|
+
'GetTargetRole',
|
|
37
|
+
'ListTargetRole',
|
|
36
38
|
'CreateRolePermissions',
|
|
37
39
|
'ListRolePermissions',
|
|
38
40
|
'DeleteRolePermissions',
|
|
39
41
|
'CreateUserRole',
|
|
40
42
|
'ListUserInRoles',
|
|
41
43
|
'DeleteUserFromRole',
|
|
44
|
+
'GetMyPermissions',
|
|
42
45
|
'ValidatorRbac',
|
|
43
|
-
'CreateRoleLimit',
|
|
44
|
-
'ListRoleLimits',
|
|
45
|
-
'DeleteRoleLimit',
|
|
46
46
|
'ReservedDynamicUsage',
|
|
47
47
|
'ConfirmUsage',
|
|
48
48
|
'CancelUsage'
|
|
@@ -59,12 +59,12 @@ const SYSTEM_TABLES = [
|
|
|
59
59
|
'AwaitingStep'
|
|
60
60
|
];
|
|
61
61
|
const RBAC_TABLES = [
|
|
62
|
+
'Roles',
|
|
62
63
|
'TargetRoles',
|
|
63
64
|
'RolePermissions',
|
|
64
65
|
'RoleUsers',
|
|
65
66
|
'UserRoles',
|
|
66
67
|
'RbacPermissionCaches',
|
|
67
|
-
'RoleLimit',
|
|
68
68
|
'RunningTotalUsage',
|
|
69
69
|
'RunningTotalReservedUsage',
|
|
70
70
|
'WebSocketTask'
|
|
@@ -414,12 +414,12 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
414
414
|
const systemTables = [...SYSTEM_TABLES];
|
|
415
415
|
if (rbac) {
|
|
416
416
|
systemTables.push(
|
|
417
|
+
'Roles',
|
|
417
418
|
'TargetRoles',
|
|
418
419
|
'RolePermissions',
|
|
419
420
|
'RoleUsers',
|
|
420
421
|
'UserRoles',
|
|
421
422
|
'RbacPermissionCaches',
|
|
422
|
-
'RoleLimit',
|
|
423
423
|
'RunningTotalUsage',
|
|
424
424
|
'RunningTotalReservedUsage'
|
|
425
425
|
);
|
|
@@ -728,7 +728,15 @@ function roleStatements(state, roleName) {
|
|
|
728
728
|
addStatement(
|
|
729
729
|
statements,
|
|
730
730
|
['sns:Publish'],
|
|
731
|
-
|
|
731
|
+
[
|
|
732
|
+
...topicArns(roleTopicNames(state, roleName)),
|
|
733
|
+
...roleExternalTopicArns(state, roleName)
|
|
734
|
+
]
|
|
735
|
+
);
|
|
736
|
+
addStatement(
|
|
737
|
+
statements,
|
|
738
|
+
['lambda:InvokeFunction'],
|
|
739
|
+
roleExternalLambdaArns(state, roleName)
|
|
732
740
|
);
|
|
733
741
|
if (state.webSocketRoles.has(roleName)) {
|
|
734
742
|
statements.push({
|
|
@@ -765,10 +773,11 @@ function roleTableNames(state, roleName) {
|
|
|
765
773
|
'WebSocketTask',
|
|
766
774
|
...(state.rbac
|
|
767
775
|
? [
|
|
776
|
+
'Roles',
|
|
768
777
|
'TargetRoles',
|
|
778
|
+
'RolePermissions',
|
|
769
779
|
'RoleUsers',
|
|
770
780
|
'UserRoles',
|
|
771
|
-
'RoleLimit',
|
|
772
781
|
'RunningTotalUsage',
|
|
773
782
|
'RunningTotalReservedUsage'
|
|
774
783
|
]
|
|
@@ -925,6 +934,9 @@ function roleTopicNames(state, roleName) {
|
|
|
925
934
|
topics.push(`${action}_In`, `${action}_Out`);
|
|
926
935
|
}
|
|
927
936
|
}
|
|
937
|
+
if (state.rbac) {
|
|
938
|
+
topics.push('ValidatorRbac_In');
|
|
939
|
+
}
|
|
928
940
|
return topics;
|
|
929
941
|
}
|
|
930
942
|
if (roleName === 'FlowRelationshipRole') {
|
|
@@ -937,6 +949,9 @@ function roleTopicNames(state, roleName) {
|
|
|
937
949
|
topics.push(`${action}_In`, `${action}_Out`);
|
|
938
950
|
}
|
|
939
951
|
}
|
|
952
|
+
if (state.rbac) {
|
|
953
|
+
topics.push('ValidatorRbac_In');
|
|
954
|
+
}
|
|
940
955
|
return topics;
|
|
941
956
|
}
|
|
942
957
|
if (roleName === 'FlowRbacRole') {
|
|
@@ -1023,6 +1038,58 @@ function roleExternalDynamoTables(state, roleName) {
|
|
|
1023
1038
|
return [];
|
|
1024
1039
|
}
|
|
1025
1040
|
|
|
1041
|
+
function roleExternalTopicArns(state, roleName) {
|
|
1042
|
+
if (!state.rbac) {
|
|
1043
|
+
return [];
|
|
1044
|
+
}
|
|
1045
|
+
const extraTags = getRbacValidatorServiceTags(state).filter(
|
|
1046
|
+
(tag) => tag && tag !== 'Rbac'
|
|
1047
|
+
);
|
|
1048
|
+
const extraTopics = extraTags.map(
|
|
1049
|
+
(tag) =>
|
|
1050
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_ValidatorRbac_In`
|
|
1051
|
+
);
|
|
1052
|
+
if (roleName === 'FlowObjectsRole') {
|
|
1053
|
+
return [
|
|
1054
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
|
|
1055
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ConfirmUsage_In`,
|
|
1056
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_CancelUsage_In`,
|
|
1057
|
+
...extraTopics
|
|
1058
|
+
];
|
|
1059
|
+
}
|
|
1060
|
+
if (roleName === 'FlowRbacRole' || roleName === 'FlowRelationshipRole') {
|
|
1061
|
+
return [
|
|
1062
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
|
|
1063
|
+
...extraTopics
|
|
1064
|
+
];
|
|
1065
|
+
}
|
|
1066
|
+
return [];
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
function roleExternalLambdaArns(state, roleName) {
|
|
1070
|
+
if (!state.rbac) {
|
|
1071
|
+
return [];
|
|
1072
|
+
}
|
|
1073
|
+
const extraTags = getRbacValidatorServiceTags(state).filter(
|
|
1074
|
+
(tag) => tag && tag !== 'Rbac'
|
|
1075
|
+
);
|
|
1076
|
+
const extraLambdas = extraTags.map(
|
|
1077
|
+
(tag) =>
|
|
1078
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ValidatorRbacHdrInv`
|
|
1079
|
+
);
|
|
1080
|
+
if (
|
|
1081
|
+
roleName === 'FlowObjectsRole' ||
|
|
1082
|
+
roleName === 'FlowRbacRole' ||
|
|
1083
|
+
roleName === 'FlowRelationshipRole'
|
|
1084
|
+
) {
|
|
1085
|
+
return [
|
|
1086
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ValidatorRbacHdrInv`,
|
|
1087
|
+
...extraLambdas
|
|
1088
|
+
];
|
|
1089
|
+
}
|
|
1090
|
+
return [];
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1026
1093
|
function queueArns(queueNames) {
|
|
1027
1094
|
return [...new Set(queueNames)]
|
|
1028
1095
|
.sort()
|
|
@@ -58,7 +58,8 @@ export function generatedLambdaRole() {
|
|
|
58
58
|
Resource: [
|
|
59
59
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
|
|
60
60
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', 'Rbac')}`,
|
|
61
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<%
|
|
61
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<% if (rbac) { %>,
|
|
62
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% } %><% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
62
63
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
63
64
|
]
|
|
64
65
|
}<% } %>
|
|
@@ -77,7 +78,8 @@ export function generatedLambdaRole() {
|
|
|
77
78
|
Effect: 'Allow',
|
|
78
79
|
Action: ['sns:Publish'],
|
|
79
80
|
Resource: [
|
|
80
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}
|
|
81
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
|
|
82
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
81
83
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
82
84
|
]
|
|
83
85
|
}
|