@cxbuilder/flow-config 1.0.1 → 1.1.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/.jsii +43 -105
- package/CHANGELOG.md +22 -0
- package/dist/backend/FlowConfig/index.js +109 -15
- package/dist/backend/FlowConfig/index.js.map +3 -3
- package/dist/backend/Static/static/assets/{index-Bx9Z3cF9.js → index-FHwnAA8f.js} +14 -14
- package/dist/backend/Static/static/index.html +1 -1
- package/dist/infrastructure/FlowConfigStack.d.ts +4 -0
- package/dist/infrastructure/FlowConfigStack.js +30 -3
- package/dist/infrastructure/api/Api.d.ts +2 -2
- package/dist/infrastructure/api/Api.js +41 -42
- package/dist/infrastructure/createLambda.js +11 -6
- package/dist/infrastructure/tsconfig.tsbuildinfo +1 -1
- package/docs/Permissions-v1.md +132 -0
- package/docs/{Permissions.md → Permissions-v2.md} +15 -15
- package/package.json +1 -3
package/.jsii
CHANGED
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"yaml": "^2.8.0"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@aws-solutions-constructs/aws-openapigateway-lambda": "^2.85.2",
|
|
24
23
|
"aws-cdk-lib": "2.194.0",
|
|
25
24
|
"constructs": "^10.0.0"
|
|
26
25
|
},
|
|
@@ -107,78 +106,6 @@
|
|
|
107
106
|
}
|
|
108
107
|
}
|
|
109
108
|
},
|
|
110
|
-
"@aws-solutions-constructs/aws-openapigateway-lambda": {
|
|
111
|
-
"targets": {
|
|
112
|
-
"dotnet": {
|
|
113
|
-
"iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
|
|
114
|
-
"namespace": "Amazon.SolutionsConstructs.AWS.OpenApiGatewayLambda",
|
|
115
|
-
"packageId": "Amazon.SolutionsConstructs.AWS.OpenApiGatewayLambda",
|
|
116
|
-
"signAssembly": true
|
|
117
|
-
},
|
|
118
|
-
"java": {
|
|
119
|
-
"maven": {
|
|
120
|
-
"artifactId": "openapigatewaylambda",
|
|
121
|
-
"groupId": "software.amazon.awsconstructs"
|
|
122
|
-
},
|
|
123
|
-
"package": "software.amazon.awsconstructs.services.openapigatewaylambda"
|
|
124
|
-
},
|
|
125
|
-
"js": {
|
|
126
|
-
"npm": "@aws-solutions-constructs/aws-openapigateway-lambda"
|
|
127
|
-
},
|
|
128
|
-
"python": {
|
|
129
|
-
"distName": "aws-solutions-constructs.aws-openapigateway-lambda",
|
|
130
|
-
"module": "aws_solutions_constructs.aws_openapigateway_lambda"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
"@aws-solutions-constructs/core": {
|
|
135
|
-
"targets": {
|
|
136
|
-
"dotnet": {
|
|
137
|
-
"iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
|
|
138
|
-
"namespace": "Amazon.SolutionsConstructs.AWS.Core",
|
|
139
|
-
"packageId": "Amazon.SolutionsConstructs.AWS.Core",
|
|
140
|
-
"signAssembly": true
|
|
141
|
-
},
|
|
142
|
-
"java": {
|
|
143
|
-
"maven": {
|
|
144
|
-
"artifactId": "core",
|
|
145
|
-
"groupId": "software.amazon.awsconstructs"
|
|
146
|
-
},
|
|
147
|
-
"package": "software.amazon.awsconstructs.services.core"
|
|
148
|
-
},
|
|
149
|
-
"js": {
|
|
150
|
-
"npm": "@aws-solutions-constructs/core"
|
|
151
|
-
},
|
|
152
|
-
"python": {
|
|
153
|
-
"distName": "aws-solutions-constructs.core",
|
|
154
|
-
"module": "aws_solutions_constructs.core"
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
"@aws-solutions-constructs/resources": {
|
|
159
|
-
"targets": {
|
|
160
|
-
"dotnet": {
|
|
161
|
-
"iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
|
|
162
|
-
"namespace": "Amazon.SolutionsConstructs.AWS.Resources",
|
|
163
|
-
"packageId": "Amazon.SolutionsConstructs.AWS.Resources",
|
|
164
|
-
"signAssembly": true
|
|
165
|
-
},
|
|
166
|
-
"java": {
|
|
167
|
-
"maven": {
|
|
168
|
-
"artifactId": "resources",
|
|
169
|
-
"groupId": "software.amazon.awsconstructs"
|
|
170
|
-
},
|
|
171
|
-
"package": "software.amazon.awsconstructs.services.resources"
|
|
172
|
-
},
|
|
173
|
-
"js": {
|
|
174
|
-
"npm": "@aws-solutions-constructs/resources"
|
|
175
|
-
},
|
|
176
|
-
"python": {
|
|
177
|
-
"distName": "aws-solutions-constructs.resources",
|
|
178
|
-
"module": "aws_solutions_constructs.resources"
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
109
|
"aws-cdk-lib": {
|
|
183
110
|
"submodules": {
|
|
184
111
|
"aws-cdk-lib.alexa_ask": {
|
|
@@ -4089,7 +4016,7 @@
|
|
|
4089
4016
|
"kind": "interface",
|
|
4090
4017
|
"locationInModule": {
|
|
4091
4018
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4092
|
-
"line":
|
|
4019
|
+
"line": 24
|
|
4093
4020
|
},
|
|
4094
4021
|
"name": "CognitoConfig",
|
|
4095
4022
|
"properties": [
|
|
@@ -4102,7 +4029,7 @@
|
|
|
4102
4029
|
"immutable": true,
|
|
4103
4030
|
"locationInModule": {
|
|
4104
4031
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4105
|
-
"line":
|
|
4032
|
+
"line": 30
|
|
4106
4033
|
},
|
|
4107
4034
|
"name": "domain",
|
|
4108
4035
|
"type": {
|
|
@@ -4117,7 +4044,7 @@
|
|
|
4117
4044
|
"immutable": true,
|
|
4118
4045
|
"locationInModule": {
|
|
4119
4046
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4120
|
-
"line":
|
|
4047
|
+
"line": 25
|
|
4121
4048
|
},
|
|
4122
4049
|
"name": "userPoolId",
|
|
4123
4050
|
"type": {
|
|
@@ -4134,7 +4061,7 @@
|
|
|
4134
4061
|
"immutable": true,
|
|
4135
4062
|
"locationInModule": {
|
|
4136
4063
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4137
|
-
"line":
|
|
4064
|
+
"line": 35
|
|
4138
4065
|
},
|
|
4139
4066
|
"name": "ssoProviderName",
|
|
4140
4067
|
"optional": true,
|
|
@@ -4158,7 +4085,7 @@
|
|
|
4158
4085
|
},
|
|
4159
4086
|
"locationInModule": {
|
|
4160
4087
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4161
|
-
"line":
|
|
4088
|
+
"line": 143
|
|
4162
4089
|
},
|
|
4163
4090
|
"parameters": [
|
|
4164
4091
|
{
|
|
@@ -4184,7 +4111,7 @@
|
|
|
4184
4111
|
"kind": "class",
|
|
4185
4112
|
"locationInModule": {
|
|
4186
4113
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4187
|
-
"line":
|
|
4114
|
+
"line": 118
|
|
4188
4115
|
},
|
|
4189
4116
|
"methods": [
|
|
4190
4117
|
{
|
|
@@ -4194,7 +4121,7 @@
|
|
|
4194
4121
|
},
|
|
4195
4122
|
"locationInModule": {
|
|
4196
4123
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4197
|
-
"line":
|
|
4124
|
+
"line": 267
|
|
4198
4125
|
},
|
|
4199
4126
|
"name": "associate3pApp"
|
|
4200
4127
|
},
|
|
@@ -4204,7 +4131,7 @@
|
|
|
4204
4131
|
},
|
|
4205
4132
|
"locationInModule": {
|
|
4206
4133
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4207
|
-
"line":
|
|
4134
|
+
"line": 207
|
|
4208
4135
|
},
|
|
4209
4136
|
"name": "createUserPoolClient",
|
|
4210
4137
|
"returns": {
|
|
@@ -4212,6 +4139,17 @@
|
|
|
4212
4139
|
"fqn": "aws-cdk-lib.aws_cognito.UserPoolClient"
|
|
4213
4140
|
}
|
|
4214
4141
|
}
|
|
4142
|
+
},
|
|
4143
|
+
{
|
|
4144
|
+
"docs": {
|
|
4145
|
+
"stability": "stable",
|
|
4146
|
+
"summary": "Create Cognito User Groups for role-based access control."
|
|
4147
|
+
},
|
|
4148
|
+
"locationInModule": {
|
|
4149
|
+
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4150
|
+
"line": 235
|
|
4151
|
+
},
|
|
4152
|
+
"name": "createUserPoolGroups"
|
|
4215
4153
|
}
|
|
4216
4154
|
],
|
|
4217
4155
|
"name": "FlowConfigStack",
|
|
@@ -4223,7 +4161,7 @@
|
|
|
4223
4161
|
"immutable": true,
|
|
4224
4162
|
"locationInModule": {
|
|
4225
4163
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4226
|
-
"line":
|
|
4164
|
+
"line": 138
|
|
4227
4165
|
},
|
|
4228
4166
|
"name": "appUrl",
|
|
4229
4167
|
"type": {
|
|
@@ -4236,7 +4174,7 @@
|
|
|
4236
4174
|
},
|
|
4237
4175
|
"locationInModule": {
|
|
4238
4176
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4239
|
-
"line":
|
|
4177
|
+
"line": 122
|
|
4240
4178
|
},
|
|
4241
4179
|
"name": "alertTopic",
|
|
4242
4180
|
"type": {
|
|
@@ -4249,7 +4187,7 @@
|
|
|
4249
4187
|
},
|
|
4250
4188
|
"locationInModule": {
|
|
4251
4189
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4252
|
-
"line":
|
|
4190
|
+
"line": 146
|
|
4253
4191
|
},
|
|
4254
4192
|
"name": "props",
|
|
4255
4193
|
"type": {
|
|
@@ -4262,7 +4200,7 @@
|
|
|
4262
4200
|
},
|
|
4263
4201
|
"locationInModule": {
|
|
4264
4202
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4265
|
-
"line":
|
|
4203
|
+
"line": 123
|
|
4266
4204
|
},
|
|
4267
4205
|
"name": "table",
|
|
4268
4206
|
"type": {
|
|
@@ -4275,7 +4213,7 @@
|
|
|
4275
4213
|
},
|
|
4276
4214
|
"locationInModule": {
|
|
4277
4215
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4278
|
-
"line":
|
|
4216
|
+
"line": 119
|
|
4279
4217
|
},
|
|
4280
4218
|
"name": "userPool",
|
|
4281
4219
|
"type": {
|
|
@@ -4288,7 +4226,7 @@
|
|
|
4288
4226
|
},
|
|
4289
4227
|
"locationInModule": {
|
|
4290
4228
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4291
|
-
"line":
|
|
4229
|
+
"line": 121
|
|
4292
4230
|
},
|
|
4293
4231
|
"name": "userPoolClient",
|
|
4294
4232
|
"type": {
|
|
@@ -4311,7 +4249,7 @@
|
|
|
4311
4249
|
"kind": "interface",
|
|
4312
4250
|
"locationInModule": {
|
|
4313
4251
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4314
|
-
"line":
|
|
4252
|
+
"line": 89
|
|
4315
4253
|
},
|
|
4316
4254
|
"name": "FlowConfigStackProps",
|
|
4317
4255
|
"properties": [
|
|
@@ -4324,7 +4262,7 @@
|
|
|
4324
4262
|
"immutable": true,
|
|
4325
4263
|
"locationInModule": {
|
|
4326
4264
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4327
|
-
"line":
|
|
4265
|
+
"line": 100
|
|
4328
4266
|
},
|
|
4329
4267
|
"name": "alertEmails",
|
|
4330
4268
|
"type": {
|
|
@@ -4344,7 +4282,7 @@
|
|
|
4344
4282
|
"immutable": true,
|
|
4345
4283
|
"locationInModule": {
|
|
4346
4284
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4347
|
-
"line":
|
|
4285
|
+
"line": 94
|
|
4348
4286
|
},
|
|
4349
4287
|
"name": "cognito",
|
|
4350
4288
|
"type": {
|
|
@@ -4359,7 +4297,7 @@
|
|
|
4359
4297
|
"immutable": true,
|
|
4360
4298
|
"locationInModule": {
|
|
4361
4299
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4362
|
-
"line":
|
|
4300
|
+
"line": 95
|
|
4363
4301
|
},
|
|
4364
4302
|
"name": "connectInstanceArn",
|
|
4365
4303
|
"type": {
|
|
@@ -4375,7 +4313,7 @@
|
|
|
4375
4313
|
"immutable": true,
|
|
4376
4314
|
"locationInModule": {
|
|
4377
4315
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4378
|
-
"line":
|
|
4316
|
+
"line": 93
|
|
4379
4317
|
},
|
|
4380
4318
|
"name": "prefix",
|
|
4381
4319
|
"type": {
|
|
@@ -4392,7 +4330,7 @@
|
|
|
4392
4330
|
"immutable": true,
|
|
4393
4331
|
"locationInModule": {
|
|
4394
4332
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4395
|
-
"line":
|
|
4333
|
+
"line": 115
|
|
4396
4334
|
},
|
|
4397
4335
|
"name": "globalTable",
|
|
4398
4336
|
"optional": true,
|
|
@@ -4408,7 +4346,7 @@
|
|
|
4408
4346
|
"immutable": true,
|
|
4409
4347
|
"locationInModule": {
|
|
4410
4348
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4411
|
-
"line":
|
|
4349
|
+
"line": 101
|
|
4412
4350
|
},
|
|
4413
4351
|
"name": "prod",
|
|
4414
4352
|
"optional": true,
|
|
@@ -4426,7 +4364,7 @@
|
|
|
4426
4364
|
"immutable": true,
|
|
4427
4365
|
"locationInModule": {
|
|
4428
4366
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4429
|
-
"line":
|
|
4367
|
+
"line": 108
|
|
4430
4368
|
},
|
|
4431
4369
|
"name": "vpc",
|
|
4432
4370
|
"optional": true,
|
|
@@ -4448,7 +4386,7 @@
|
|
|
4448
4386
|
"kind": "interface",
|
|
4449
4387
|
"locationInModule": {
|
|
4450
4388
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4451
|
-
"line":
|
|
4389
|
+
"line": 66
|
|
4452
4390
|
},
|
|
4453
4391
|
"name": "GlobalTableConfig",
|
|
4454
4392
|
"properties": [
|
|
@@ -4461,7 +4399,7 @@
|
|
|
4461
4399
|
"immutable": true,
|
|
4462
4400
|
"locationInModule": {
|
|
4463
4401
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4464
|
-
"line":
|
|
4402
|
+
"line": 70
|
|
4465
4403
|
},
|
|
4466
4404
|
"name": "isPrimaryRegion",
|
|
4467
4405
|
"type": {
|
|
@@ -4477,7 +4415,7 @@
|
|
|
4477
4415
|
"immutable": true,
|
|
4478
4416
|
"locationInModule": {
|
|
4479
4417
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4480
|
-
"line":
|
|
4418
|
+
"line": 76
|
|
4481
4419
|
},
|
|
4482
4420
|
"name": "replicaRegions",
|
|
4483
4421
|
"optional": true,
|
|
@@ -4504,7 +4442,7 @@
|
|
|
4504
4442
|
"kind": "interface",
|
|
4505
4443
|
"locationInModule": {
|
|
4506
4444
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4507
|
-
"line":
|
|
4445
|
+
"line": 41
|
|
4508
4446
|
},
|
|
4509
4447
|
"name": "VpcConfig",
|
|
4510
4448
|
"properties": [
|
|
@@ -4517,7 +4455,7 @@
|
|
|
4517
4455
|
"immutable": true,
|
|
4518
4456
|
"locationInModule": {
|
|
4519
4457
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4520
|
-
"line":
|
|
4458
|
+
"line": 50
|
|
4521
4459
|
},
|
|
4522
4460
|
"name": "lambdaSecurityGroupIds",
|
|
4523
4461
|
"type": {
|
|
@@ -4538,7 +4476,7 @@
|
|
|
4538
4476
|
"immutable": true,
|
|
4539
4477
|
"locationInModule": {
|
|
4540
4478
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4541
|
-
"line":
|
|
4479
|
+
"line": 55
|
|
4542
4480
|
},
|
|
4543
4481
|
"name": "privateSubnetIds",
|
|
4544
4482
|
"type": {
|
|
@@ -4559,7 +4497,7 @@
|
|
|
4559
4497
|
"immutable": true,
|
|
4560
4498
|
"locationInModule": {
|
|
4561
4499
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4562
|
-
"line":
|
|
4500
|
+
"line": 60
|
|
4563
4501
|
},
|
|
4564
4502
|
"name": "vpcEndpointSecurityGroupIds",
|
|
4565
4503
|
"type": {
|
|
@@ -4580,7 +4518,7 @@
|
|
|
4580
4518
|
"immutable": true,
|
|
4581
4519
|
"locationInModule": {
|
|
4582
4520
|
"filename": "infrastructure/FlowConfigStack.ts",
|
|
4583
|
-
"line":
|
|
4521
|
+
"line": 45
|
|
4584
4522
|
},
|
|
4585
4523
|
"name": "vpcId",
|
|
4586
4524
|
"type": {
|
|
@@ -4591,6 +4529,6 @@
|
|
|
4591
4529
|
"symbolId": "infrastructure/FlowConfigStack:VpcConfig"
|
|
4592
4530
|
}
|
|
4593
4531
|
},
|
|
4594
|
-
"version": "1.0
|
|
4595
|
-
"fingerprint": "
|
|
4532
|
+
"version": "1.1.0",
|
|
4533
|
+
"fingerprint": "HFZB1viUfyeGHk8/FgKUYwz6TaxogYZ+PsdAxRdPVdA="
|
|
4596
4534
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.1.0] - 2025-06-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Role-based access control (RBAC) using Amazon Cognito User Groups
|
|
13
|
+
- Three permission levels: FlowConfigAdmin, FlowConfigEdit, and FlowConfigRead
|
|
14
|
+
- Backend permission validation for all API endpoints
|
|
15
|
+
- Frontend UI adapts based on user permissions
|
|
16
|
+
- Read-only mode for users without edit access
|
|
17
|
+
- Access denied screen for users without any FlowConfig permissions
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Replaced placeholder permission system with full Cognito Groups implementation
|
|
22
|
+
- FlowConfigEdit users can add languages to prompts but cannot remove existing ones
|
|
23
|
+
- FlowConfigEdit users can add/remove channels but cannot modify structure
|
|
24
|
+
- Preview functionality remains available to all permission levels
|
|
25
|
+
|
|
26
|
+
## [1.0.2] - 2025-06-20
|
|
27
|
+
|
|
28
|
+
- Converted to `SpecRestApi` because `@aws-solutions-constructs/aws-openapigateway-lambda` is not compatible with `Role.customizeRoles`
|
|
29
|
+
|
|
8
30
|
## [1.0.0] - 2025-06-18
|
|
9
31
|
|
|
10
32
|
### Added
|
|
@@ -151,6 +151,78 @@ function stripSSML(text) {
|
|
|
151
151
|
}
|
|
152
152
|
__name(stripSSML, "stripSSML");
|
|
153
153
|
|
|
154
|
+
// backend/shared/permissions.ts
|
|
155
|
+
var COGNITO_GROUPS = {
|
|
156
|
+
ADMIN: "FlowConfigAdmin",
|
|
157
|
+
EDIT: "FlowConfigEdit",
|
|
158
|
+
READ: "FlowConfigRead"
|
|
159
|
+
};
|
|
160
|
+
function extractCognitoGroups(claims) {
|
|
161
|
+
const groupsClaim = claims["cognito:groups"];
|
|
162
|
+
if (!groupsClaim) {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
if (typeof groupsClaim === "string") {
|
|
166
|
+
return groupsClaim.split(",").map((group) => group.trim());
|
|
167
|
+
}
|
|
168
|
+
if (Array.isArray(groupsClaim)) {
|
|
169
|
+
return groupsClaim;
|
|
170
|
+
}
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
__name(extractCognitoGroups, "extractCognitoGroups");
|
|
174
|
+
function hasFlowConfigAccess(claims) {
|
|
175
|
+
const userGroups = extractCognitoGroups(claims);
|
|
176
|
+
const flowConfigGroups = Object.values(COGNITO_GROUPS);
|
|
177
|
+
return userGroups.some((group) => flowConfigGroups.includes(group));
|
|
178
|
+
}
|
|
179
|
+
__name(hasFlowConfigAccess, "hasFlowConfigAccess");
|
|
180
|
+
function getAccessLevel(claims) {
|
|
181
|
+
const userGroups = extractCognitoGroups(claims);
|
|
182
|
+
if (userGroups.includes(COGNITO_GROUPS.ADMIN)) {
|
|
183
|
+
return "Full";
|
|
184
|
+
}
|
|
185
|
+
if (userGroups.includes(COGNITO_GROUPS.EDIT)) {
|
|
186
|
+
return "Edit";
|
|
187
|
+
}
|
|
188
|
+
if (userGroups.includes(COGNITO_GROUPS.READ)) {
|
|
189
|
+
return "Read";
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
__name(getAccessLevel, "getAccessLevel");
|
|
194
|
+
function checkActionPermission(claims, action) {
|
|
195
|
+
const accessLevel = getAccessLevel(claims);
|
|
196
|
+
if (!accessLevel) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
switch (action) {
|
|
200
|
+
case "Read":
|
|
201
|
+
return accessLevel;
|
|
202
|
+
case "Edit":
|
|
203
|
+
if (accessLevel === "Edit" || accessLevel === "Full") {
|
|
204
|
+
return accessLevel;
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
case "Create":
|
|
208
|
+
case "Delete":
|
|
209
|
+
if (accessLevel === "Full") {
|
|
210
|
+
return accessLevel;
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
default:
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
__name(checkActionPermission, "checkActionPermission");
|
|
218
|
+
function validateFlowConfigPermission(claims, _flowConfigId, action) {
|
|
219
|
+
if (!hasFlowConfigAccess(claims)) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
return checkActionPermission(claims, action);
|
|
223
|
+
}
|
|
224
|
+
__name(validateFlowConfigPermission, "validateFlowConfigPermission");
|
|
225
|
+
|
|
154
226
|
// backend/FlowConfig.ts
|
|
155
227
|
var env = process.env;
|
|
156
228
|
var client2 = new import_client_dynamodb.DynamoDBClient();
|
|
@@ -198,7 +270,7 @@ async function listFlowConfigs(event, claims) {
|
|
|
198
270
|
}
|
|
199
271
|
const resultItems = [];
|
|
200
272
|
for (const config of filteredConfigs) {
|
|
201
|
-
const accessLevel =
|
|
273
|
+
const accessLevel = validateFlowConfigPermission(claims, config.id, "Read");
|
|
202
274
|
if (accessLevel) {
|
|
203
275
|
resultItems.push({
|
|
204
276
|
id: config.id,
|
|
@@ -216,7 +288,7 @@ async function listFlowConfigs(event, claims) {
|
|
|
216
288
|
__name(listFlowConfigs, "listFlowConfigs");
|
|
217
289
|
async function getFlowConfig(flowConfigId, claims) {
|
|
218
290
|
try {
|
|
219
|
-
const accessLevel =
|
|
291
|
+
const accessLevel = validateFlowConfigPermission(claims, flowConfigId, "Read");
|
|
220
292
|
if (!accessLevel) {
|
|
221
293
|
return respondMessage(403, "Access denied");
|
|
222
294
|
}
|
|
@@ -278,10 +350,16 @@ async function saveFlowConfig(flowConfigId, event, claims) {
|
|
|
278
350
|
const response = await docClient.send(getCommand);
|
|
279
351
|
const existingConfig = response.Item;
|
|
280
352
|
const action = existingConfig ? "Edit" : "Create";
|
|
281
|
-
const accessLevel =
|
|
353
|
+
const accessLevel = validateFlowConfigPermission(claims, flowConfigId, action);
|
|
282
354
|
if (!accessLevel) {
|
|
283
355
|
return respondMessage(403, "Access denied");
|
|
284
356
|
}
|
|
357
|
+
if (accessLevel === "Edit" && existingConfig) {
|
|
358
|
+
const structuralChangeError = validateEditOnlyChanges(existingConfig, body);
|
|
359
|
+
if (structuralChangeError) {
|
|
360
|
+
return respondMessage(403, `FlowConfigEdit users cannot make structural changes: ${structuralChangeError}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
285
363
|
const putCommand = new import_lib_dynamodb.PutCommand({
|
|
286
364
|
TableName: env.FLOW_CONFIGS_TABLE_NAME,
|
|
287
365
|
Item: body
|
|
@@ -296,7 +374,7 @@ async function saveFlowConfig(flowConfigId, event, claims) {
|
|
|
296
374
|
__name(saveFlowConfig, "saveFlowConfig");
|
|
297
375
|
async function deleteFlowConfig(flowConfigId, claims) {
|
|
298
376
|
try {
|
|
299
|
-
const accessLevel =
|
|
377
|
+
const accessLevel = validateFlowConfigPermission(claims, flowConfigId, "Delete");
|
|
300
378
|
if (!accessLevel) {
|
|
301
379
|
return respondMessage(403, "Access denied");
|
|
302
380
|
}
|
|
@@ -355,7 +433,7 @@ async function previewFlowConfig(event, claims) {
|
|
|
355
433
|
"FlowConfig must have id, description, variables, and prompts"
|
|
356
434
|
);
|
|
357
435
|
}
|
|
358
|
-
const accessLevel =
|
|
436
|
+
const accessLevel = validateFlowConfigPermission(claims, flowConfig.id, "Read");
|
|
359
437
|
if (!accessLevel) {
|
|
360
438
|
return respondMessage(403, "Access denied");
|
|
361
439
|
}
|
|
@@ -369,18 +447,34 @@ async function previewFlowConfig(event, claims) {
|
|
|
369
447
|
}
|
|
370
448
|
}
|
|
371
449
|
__name(previewFlowConfig, "previewFlowConfig");
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
return
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
450
|
+
function validateEditOnlyChanges(existingConfig, newConfig) {
|
|
451
|
+
if (existingConfig.description !== newConfig.description) {
|
|
452
|
+
return "Cannot modify description";
|
|
453
|
+
}
|
|
454
|
+
const existingVarKeys = Object.keys(existingConfig.variables || {}).sort();
|
|
455
|
+
const newVarKeys = Object.keys(newConfig.variables || {}).sort();
|
|
456
|
+
if (existingVarKeys.length !== newVarKeys.length || !existingVarKeys.every((key, index) => key === newVarKeys[index])) {
|
|
457
|
+
return "Cannot add or remove variables";
|
|
458
|
+
}
|
|
459
|
+
const existingPromptKeys = Object.keys(existingConfig.prompts || {}).sort();
|
|
460
|
+
const newPromptKeys = Object.keys(newConfig.prompts || {}).sort();
|
|
461
|
+
if (existingPromptKeys.length !== newPromptKeys.length || !existingPromptKeys.every((key, index) => key === newPromptKeys[index])) {
|
|
462
|
+
return "Cannot add or remove prompts";
|
|
463
|
+
}
|
|
464
|
+
for (const promptName of existingPromptKeys) {
|
|
465
|
+
const existingPrompt = existingConfig.prompts[promptName];
|
|
466
|
+
const newPrompt = newConfig.prompts[promptName];
|
|
467
|
+
const existingLangs = Object.keys(existingPrompt || {});
|
|
468
|
+
const newLangs = Object.keys(newPrompt || {});
|
|
469
|
+
for (const existingLang of existingLangs) {
|
|
470
|
+
if (!newLangs.includes(existingLang)) {
|
|
471
|
+
return `Cannot remove language ${existingLang} from prompt ${promptName}`;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
381
474
|
}
|
|
475
|
+
return null;
|
|
382
476
|
}
|
|
383
|
-
__name(
|
|
477
|
+
__name(validateEditOnlyChanges, "validateEditOnlyChanges");
|
|
384
478
|
// Annotate the CommonJS export names for ESM import in node:
|
|
385
479
|
0 && (module.exports = {
|
|
386
480
|
handler
|