UNPKG

83.7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.ModelAuthTransformer = void 0;
4const graphql_transformer_core_1 = require("graphql-transformer-core");
5const cloudform_types_1 = require("cloudform-types");
6const resources_1 = require("./resources");
7const graphql_1 = require("graphql");
8const graphql_transformer_common_1 = require("graphql-transformer-common");
9const graphql_mapping_template_1 = require("graphql-mapping-template");
10const ModelDirectiveConfiguration_1 = require("./ModelDirectiveConfiguration");
11const constants_1 = require("./constants");
12const validateAuthModes = (authConfig) => {
13 let additionalAuthModes = [];
14 if (authConfig.additionalAuthenticationProviders) {
15 additionalAuthModes = authConfig.additionalAuthenticationProviders.map(p => p.authenticationType).filter(t => !!t);
16 }
17 const authModes = [...additionalAuthModes, authConfig.defaultAuthentication.authenticationType];
18 for (let i = 0; i < authModes.length; i++) {
19 const mode = authModes[i];
20 if (mode !== 'API_KEY' && mode !== 'AMAZON_COGNITO_USER_POOLS' && mode !== 'AWS_IAM' && mode !== 'OPENID_CONNECT') {
21 throw new Error(`Invalid auth mode ${mode}`);
22 }
23 }
24};
25class ModelAuthTransformer extends graphql_transformer_core_1.Transformer {
26 constructor(config) {
27 super('ModelAuthTransformer', graphql_transformer_core_1.gql `
28 directive @auth(rules: [AuthRule!]!) on OBJECT | FIELD_DEFINITION
29 input AuthRule {
30 # Specifies the auth rule's strategy. Allowed values are 'owner', 'groups', 'public', 'private'.
31 allow: AuthStrategy!
32
33 # Legacy name for identityClaim
34 identityField: String @deprecated(reason: "The 'identityField' argument is replaced by the 'identityClaim'.")
35
36 # Specifies the name of the provider to use for the rule. This overrides the default provider
37 # when 'public' and 'private' AuthStrategy is used. Specifying a provider for 'owner' or 'groups'
38 # are not allowed.
39 provider: AuthProvider
40
41 # Specifies the name of the claim to look for on the request's JWT token
42 # from Cognito User Pools (and in the future OIDC) that contains the identity
43 # of the user. If 'allow' is 'groups', this value should point to a list of groups
44 # in the claims. If 'allow' is 'owner', this value should point to the logged in user identity string.
45 # Defaults to "cognito:username" for Cognito User Pools auth.
46 identityClaim: String
47
48 # Allows for custom config of 'groups' which is validated against the JWT
49 # Specifies a static list of groups that should have access to the object
50 groupClaim: String
51
52 # Allowed when the 'allow' argument is 'owner'.
53 # Specifies the field of type String or [String] that contains owner(s) that can access the object.
54 ownerField: String # defaults to "owner"
55 # Allowed when the 'allow' argument is 'groups'.
56 # Specifies the field of type String or [String] that contains group(s) that can access the object.
57 groupsField: String
58
59 # Allowed when the 'allow' argument is 'groups'.
60 # Specifies a static list of groups that should have access to the object.
61 groups: [String]
62
63 # Specifies operations to which this auth rule should be applied.
64 operations: [ModelOperation]
65
66 # Deprecated. It is recommended to use the 'operations' arguments.
67 queries: [ModelQuery]
68 @deprecated(reason: "The 'queries' argument will be replaced by the 'operations' argument in a future release.")
69
70 # Deprecated. It is recommended to use the 'operations' arguments.
71 mutations: [ModelMutation]
72 @deprecated(reason: "The 'mutations' argument will be replaced by the 'operations' argument in a future release.")
73 }
74 enum AuthStrategy {
75 owner
76 groups
77 private
78 public
79 }
80 enum AuthProvider {
81 apiKey
82 iam
83 oidc
84 userPools
85 }
86 enum ModelOperation {
87 create
88 update
89 delete
90 read
91 }
92 enum ModelQuery @deprecated(reason: "ModelQuery will be replaced by the 'ModelOperation' in a future release.") {
93 get
94 list
95 }
96 enum ModelMutation @deprecated(reason: "ModelMutation will be replaced by the 'ModelOperation' in a future release.") {
97 create
98 update
99 delete
100 }
101 `);
102 this.updateAPIAuthentication = (ctx) => {
103 const apiRecord = ctx.getResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLAPILogicalID);
104 const updated = this.resources.updateGraphQLAPIWithAuth(apiRecord, this.config.authConfig);
105 ctx.setResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.GraphQLAPILogicalID, updated);
106 };
107 this.before = (ctx) => {
108 const template = this.resources.initTemplate(this.getApiKeyConfig());
109 ctx.mergeResources(template.Resources);
110 ctx.mergeParameters(template.Parameters);
111 ctx.mergeOutputs(template.Outputs);
112 ctx.mergeConditions(template.Conditions);
113 this.updateAPIAuthentication(ctx);
114 if (!ctx.metadata.has(constants_1.AUTH_NON_MODEL_TYPES)) {
115 ctx.metadata.set(constants_1.AUTH_NON_MODEL_TYPES, new Set());
116 }
117 };
118 this.after = (ctx) => {
119 if (this.generateIAMPolicyforAuthRole === true) {
120 if (this.authPolicyResources.size === 0) {
121 throw new Error('AuthRole policies should be generated, but no resources were added');
122 }
123 ctx.mergeParameters({
124 [graphql_transformer_common_1.ResourceConstants.PARAMETERS.AuthRoleName]: new cloudform_types_1.StringParameter({
125 Description: 'Reference to the name of the Auth Role created for the project.',
126 }),
127 });
128 const authPolicies = this.resources.makeIAMPolicyForRole(true, this.authPolicyResources);
129 for (let i = 0; i < authPolicies.length; i++) {
130 const paddedIndex = `${i + 1}`.padStart(2, '0');
131 const resourceName = `${graphql_transformer_common_1.ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`;
132 ctx.mergeResources({
133 [resourceName]: authPolicies[i],
134 });
135 }
136 }
137 if (this.generateIAMPolicyforUnauthRole === true) {
138 if (this.unauthPolicyResources.size === 0) {
139 throw new Error('UnauthRole policies should be generated, but no resources were added');
140 }
141 ctx.mergeParameters({
142 [graphql_transformer_common_1.ResourceConstants.PARAMETERS.UnauthRoleName]: new cloudform_types_1.StringParameter({
143 Description: 'Reference to the name of the Unauth Role created for the project.',
144 }),
145 });
146 const unauthPolicies = this.resources.makeIAMPolicyForRole(false, this.unauthPolicyResources);
147 for (let i = 0; i < unauthPolicies.length; i++) {
148 const paddedIndex = `${i + 1}`.padStart(2, '0');
149 const resourceName = `${graphql_transformer_common_1.ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`;
150 ctx.mergeResources({
151 [resourceName]: unauthPolicies[i],
152 });
153 }
154 }
155 };
156 this.object = (def, directive, ctx) => {
157 const modelDirective = def.directives.find(dir => dir.name.value === 'model');
158 if (!modelDirective) {
159 throw new graphql_transformer_core_1.InvalidDirectiveError('Types annotated with @auth must also be annotated with @model.');
160 }
161 const searchableDirective = def.directives.find(dir => dir.name.value === 'searchable');
162 const rules = this.getAuthRulesFromDirective(directive);
163 this.ensureDefaultAuthProviderAssigned(rules);
164 this.validateRules(rules);
165 this.setAuthPolicyFlag(rules);
166 this.setUnauthPolicyFlag(rules);
167 this.propagateAuthDirectivesToNestedTypes(def, rules, ctx);
168 const { operationRules, queryRules } = this.splitRules(rules);
169 const modelConfiguration = new ModelDirectiveConfiguration_1.ModelDirectiveConfiguration(modelDirective, def);
170 const directives = this.getDirectivesForRules(rules, false);
171 if (directives.length > 0) {
172 this.extendTypeWithDirectives(ctx, def.name.value, directives);
173 }
174 this.addTypeToResourceReferences(def.name.value, rules);
175 this.protectCreateMutation(ctx, graphql_transformer_common_1.ResolverResourceIDs.DynamoDBCreateResolverResourceID(def.name.value), operationRules.create, def, modelConfiguration);
176 this.protectUpdateMutation(ctx, graphql_transformer_common_1.ResolverResourceIDs.DynamoDBUpdateResolverResourceID(def.name.value), operationRules.update, def, modelConfiguration);
177 this.protectDeleteMutation(ctx, graphql_transformer_common_1.ResolverResourceIDs.DynamoDBDeleteResolverResourceID(def.name.value), operationRules.delete, def, modelConfiguration);
178 this.protectGetQuery(ctx, graphql_transformer_common_1.ResolverResourceIDs.DynamoDBGetResolverResourceID(def.name.value), queryRules.get, def, modelConfiguration);
179 this.protectListQuery(ctx, graphql_transformer_common_1.ResolverResourceIDs.DynamoDBListResolverResourceID(def.name.value), queryRules.list, def, modelConfiguration);
180 this.protectConnections(ctx, def, operationRules.read, modelConfiguration);
181 this.protectQueries(ctx, def, operationRules.read, modelConfiguration);
182 if (searchableDirective) {
183 this.protectSearchQuery(ctx, def, graphql_transformer_common_1.ResolverResourceIDs.ElasticsearchSearchResolverResourceID(def.name.value), operationRules.read);
184 }
185 if (this.isSyncEnabled(ctx, def.name.value)) {
186 this.protectSyncQuery(ctx, def, graphql_transformer_common_1.ResolverResourceIDs.SyncResolverResourceID(def.name.value), operationRules.read);
187 }
188 if (modelConfiguration.getName('level') !== 'off') {
189 this.protectOnCreateSubscription(ctx, operationRules.read, def, modelConfiguration);
190 this.protectOnUpdateSubscription(ctx, operationRules.read, def, modelConfiguration);
191 this.protectOnDeleteSubscription(ctx, operationRules.read, def, modelConfiguration);
192 }
193 this.updateMutationConditionInput(ctx, def, rules);
194 };
195 this.field = (parent, definition, directive, ctx) => {
196 if (parent.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
197 throw new graphql_transformer_core_1.InvalidDirectiveError(`The @auth directive cannot be placed on an interface's field. See ${parent.name.value}${definition.name.value}`);
198 }
199 const modelDirective = parent.directives.find(dir => dir.name.value === 'model');
200 const isParentTypeBuiltinType = parent.name.value === ctx.getQueryTypeName() ||
201 parent.name.value === ctx.getMutationTypeName() ||
202 parent.name.value === ctx.getSubscriptionTypeName();
203 if (isParentTypeBuiltinType) {
204 console.warn(`Be careful when using @auth directives on a field in a root type. @auth directives on field definitions use the source \
205object to perform authorization logic and the source will be an empty object for fields on root types. \
206Static group authorization should perform as expected.`);
207 }
208 const rules = this.getAuthRulesFromDirective(directive);
209 this.ensureDefaultAuthProviderAssigned(rules);
210 this.validateFieldRules(rules, isParentTypeBuiltinType, modelDirective !== undefined);
211 this.setAuthPolicyFlag(rules);
212 this.setUnauthPolicyFlag(rules);
213 this.addFieldToResourceReferences(parent.name.value, definition.name.value, rules);
214 const includeDefault = this.isTypeNeedsDefaultProviderAccess(parent);
215 const typeDirectives = isParentTypeBuiltinType ? [] : this.getDirectivesForRules(rules, includeDefault);
216 if (typeDirectives.length > 0) {
217 this.extendTypeWithDirectives(ctx, parent.name.value, typeDirectives);
218 }
219 const isOpRule = (op) => (rule) => {
220 if (rule.operations) {
221 const matchesOp = rule.operations.find(o => o === op);
222 return Boolean(matchesOp);
223 }
224 if (rule.operations === null) {
225 return false;
226 }
227 return true;
228 };
229 if (modelDirective) {
230 const isReadRule = isOpRule('read');
231 const isCreateRule = isOpRule('create');
232 const isUpdateRule = isOpRule('update');
233 const isDeleteRule = isOpRule('delete');
234 const modelConfiguration = new ModelDirectiveConfiguration_1.ModelDirectiveConfiguration(modelDirective, parent);
235 const readRules = rules.filter((rule) => isReadRule(rule));
236 this.protectReadForField(ctx, parent, definition, readRules, modelConfiguration);
237 const createRules = rules.filter((rule) => isCreateRule(rule));
238 this.protectCreateForField(ctx, parent, definition, createRules, modelConfiguration);
239 const updateRules = rules.filter((rule) => isUpdateRule(rule));
240 this.protectUpdateForField(ctx, parent, definition, updateRules, modelConfiguration);
241 const deleteRules = rules.filter((rule) => isDeleteRule(rule));
242 this.protectDeleteForField(ctx, parent, definition, deleteRules, modelConfiguration);
243 }
244 else {
245 const directives = this.getDirectivesForRules(rules, false);
246 if (directives.length > 0) {
247 this.addDirectivesToField(ctx, parent.name.value, definition.name.value, directives);
248 }
249 const staticGroupRules = rules.filter((rule) => rule.groups);
250 this.protectField(ctx, parent, definition, staticGroupRules);
251 }
252 };
253 if (config && config.authConfig) {
254 this.config = config;
255 if (!this.config.authConfig.additionalAuthenticationProviders) {
256 this.config.authConfig.additionalAuthenticationProviders = [];
257 }
258 }
259 else {
260 this.config = { authConfig: { defaultAuthentication: { authenticationType: 'API_KEY' }, additionalAuthenticationProviders: [] } };
261 }
262 validateAuthModes(this.config.authConfig);
263 this.resources = new resources_1.ResourceFactory();
264 this.configuredAuthProviders = this.getConfiguredAuthProviders();
265 this.generateIAMPolicyforUnauthRole = false;
266 this.generateIAMPolicyforAuthRole = false;
267 this.authPolicyResources = new Set();
268 this.unauthPolicyResources = new Set();
269 }
270 getApiKeyConfig() {
271 let authProviders = [];
272 if (this.config.authConfig.additionalAuthenticationProviders) {
273 authProviders = authProviders.concat(this.config.authConfig.additionalAuthenticationProviders.filter(p => !!p.authenticationType));
274 }
275 authProviders.push(this.config.authConfig.defaultAuthentication);
276 const apiKeyAuthProvider = authProviders.find(p => p.authenticationType === 'API_KEY');
277 return apiKeyAuthProvider ? apiKeyAuthProvider.apiKeyConfig : { apiKeyExpirationDays: 7 };
278 }
279 propagateAuthDirectivesToNestedTypes(type, rules, ctx) {
280 const seenNonModelTypes = ctx.metadata.get(constants_1.AUTH_NON_MODEL_TYPES);
281 const nonModelTypePredicate = (fieldType) => {
282 if (fieldType) {
283 if (fieldType.kind !== 'ObjectTypeDefinition') {
284 return undefined;
285 }
286 const typeModel = fieldType.directives.find(dir => dir.name.value === 'model');
287 return typeModel !== undefined ? undefined : fieldType;
288 }
289 return fieldType;
290 };
291 const nonModelFieldTypes = type.fields.map(f => ctx.getType(graphql_transformer_common_1.getBaseType(f.type))).filter(nonModelTypePredicate);
292 for (const nonModelFieldType of nonModelFieldTypes) {
293 if (!seenNonModelTypes.has(nonModelFieldType.name.value)) {
294 seenNonModelTypes.add(nonModelFieldType.name.value);
295 const directives = this.getDirectivesForRules(rules, false);
296 if (directives.length > 0) {
297 this.extendTypeWithDirectives(ctx, nonModelFieldType.name.value, directives);
298 }
299 const hasIAM = directives.filter(directive => directive.name.value === 'aws_iam') || this.configuredAuthProviders.default === 'iam';
300 if (hasIAM) {
301 this.unauthPolicyResources.add(`${nonModelFieldType.name.value}/null`);
302 this.authPolicyResources.add(`${nonModelFieldType.name.value}/null`);
303 }
304 this.propagateAuthDirectivesToNestedTypes(nonModelFieldType, rules, ctx);
305 }
306 }
307 }
308 protectField(ctx, parent, field, staticGroupRules) {
309 const typeName = parent.name.value;
310 const fieldName = field.name.value;
311 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(typeName, fieldName);
312 let fieldResolverResource = ctx.getResource(resolverResourceId);
313 const templateParts = [];
314 if (staticGroupRules && staticGroupRules.length) {
315 const staticGroupAuthorizationRules = this.getStaticGroupRules(staticGroupRules);
316 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules, field);
317 const throwIfUnauthorizedExpression = this.resources.throwIfStaticGroupUnauthorized(field);
318 const authCheckExpressions = [staticGroupAuthorizationExpression, graphql_mapping_template_1.newline(), throwIfUnauthorizedExpression];
319 templateParts.push(graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression(authCheckExpressions)));
320 }
321 if (!fieldResolverResource) {
322 fieldResolverResource = this.resources.blankResolver(typeName, fieldName);
323 ctx.setResource(resolverResourceId, fieldResolverResource);
324 const noneDS = ctx.getResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.NoneDataSource);
325 if (!noneDS) {
326 ctx.setResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.NoneDataSource, this.resources.noneDataSource());
327 }
328 }
329 else {
330 templateParts.push(fieldResolverResource.Properties.RequestMappingTemplate);
331 }
332 fieldResolverResource.Properties.RequestMappingTemplate = templateParts.join('\n\n');
333 ctx.setResource(resolverResourceId, fieldResolverResource);
334 }
335 protectReadForField(ctx, parent, field, rules, modelConfiguration) {
336 if (rules && rules.length) {
337 const directives = this.getDirectivesForRules(rules, false);
338 if (directives.length > 0) {
339 this.addDirectivesToField(ctx, parent.name.value, field.name.value, directives);
340 const addDirectivesForOperation = (operationType) => {
341 if (modelConfiguration.shouldHave(operationType)) {
342 const operationName = modelConfiguration.getName(operationType);
343 const includeDefault = this.isTypeHasRulesForOperation(parent, operationType);
344 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
345 this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives);
346 }
347 };
348 addDirectivesForOperation('get');
349 addDirectivesForOperation('list');
350 }
351 const addResourceReference = (operationType) => {
352 if (modelConfiguration.shouldHave(operationType)) {
353 const operationName = modelConfiguration.getName(operationType);
354 this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules);
355 }
356 };
357 addResourceReference('get');
358 addResourceReference('list');
359 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(parent.name.value, field.name.value);
360 let resolver = ctx.getResource(resolverResourceId);
361 if (!resolver) {
362 const noneDS = ctx.getResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.NoneDataSource);
363 if (!noneDS) {
364 ctx.setResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.NoneDataSource, this.resources.noneDataSource());
365 }
366 ctx.mapResourceToStack(parent.name.value, resolverResourceId);
367 resolver = this.resources.blankResolver(parent.name.value, field.name.value);
368 }
369 const authExpression = this.authorizationExpressionOnSingleObject(rules, 'ctx.source');
370 if (modelConfiguration.getName('level') === 'on') {
371 if (field.type.kind === graphql_1.Kind.NON_NULL_TYPE) {
372 throw new graphql_transformer_core_1.InvalidDirectiveError(`\nPer-field auth on the required field ${field.name.value} is not supported with subscriptions.
373Either make the field optional, set auth on the object and not the field, or disable subscriptions for the object (setting level to off or public)\n`);
374 }
375 resolver.Properties.ResponseMappingTemplate = graphql_mapping_template_1.print(this.resources.operationCheckExpression(ctx.getMutationTypeName(), field.name.value));
376 }
377 const templateParts = [graphql_mapping_template_1.print(authExpression), resolver.Properties.RequestMappingTemplate];
378 resolver.Properties.RequestMappingTemplate = templateParts.join('\n\n');
379 ctx.setResource(resolverResourceId, resolver);
380 }
381 }
382 protectUpdateForField(ctx, parent, field, rules, modelConfiguration) {
383 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.DynamoDBUpdateResolverResourceID(parent.name.value);
384 const subscriptionOperation = 'onUpdate';
385 this.protectUpdateMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, field, subscriptionOperation);
386 }
387 protectDeleteForField(ctx, parent, field, rules, modelConfiguration) {
388 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.DynamoDBUpdateResolverResourceID(parent.name.value);
389 const subscriptionOperation = 'onDelete';
390 this.protectDeleteMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, field, subscriptionOperation);
391 }
392 protectCreateForField(ctx, parent, field, rules, modelConfiguration) {
393 const typeName = parent.name.value;
394 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.DynamoDBCreateResolverResourceID(typeName);
395 const createResolverResource = ctx.getResource(resolverResourceId);
396 const mutationTypeName = ctx.getMutationTypeName();
397 if (rules && rules.length && createResolverResource) {
398 const directives = this.getDirectivesForRules(rules, false);
399 let operationName = undefined;
400 if (directives.length > 0) {
401 this.addDirectivesToField(ctx, typeName, field.name.value, directives);
402 if (modelConfiguration.shouldHave('create')) {
403 const includeDefault = this.isTypeHasRulesForOperation(parent, 'create');
404 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
405 operationName = modelConfiguration.getName('create');
406 this.addDirectivesToOperation(ctx, mutationTypeName, operationName, operationDirectives);
407 }
408 }
409 if (operationName) {
410 this.addFieldToResourceReferences(mutationTypeName, operationName, rules);
411 }
412 const staticGroupAuthorizationRules = this.getStaticGroupRules(rules);
413 const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules);
414 const ownerAuthorizationRules = this.getOwnerRules(rules);
415 const providerAuthorization = this.hasProviderAuthRules(rules);
416 if ((staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) &&
417 providerAuthorization === false) {
418 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules, field);
419 const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForCreateOperationsByField(dynamicGroupAuthorizationRules, field.name.value);
420 const fieldIsList = (fieldName) => {
421 const field = parent.fields.find(field => field.name.value === fieldName);
422 if (field) {
423 return graphql_transformer_common_1.isListType(field.type);
424 }
425 return false;
426 };
427 const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForCreateOperationsByField(ownerAuthorizationRules, field.name.value, fieldIsList);
428 const throwIfUnauthorizedExpression = this.resources.throwIfUnauthorized(field);
429 const authModesToCheck = new Set();
430 const expressions = new Array();
431 if (ownerAuthorizationRules.find(r => r.provider === 'userPools') ||
432 staticGroupAuthorizationRules.find(r => r.provider === 'userPools') ||
433 dynamicGroupAuthorizationRules.find(r => r.provider === 'userPools')) {
434 authModesToCheck.add('userPools');
435 }
436 if (ownerAuthorizationRules.find(r => r.provider === 'oidc') ||
437 staticGroupAuthorizationRules.find(r => r.provider === 'oidc') ||
438 dynamicGroupAuthorizationRules.find(r => r.provider === 'oidc')) {
439 authModesToCheck.add('oidc');
440 }
441 if (authModesToCheck.size > 0) {
442 const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools';
443 expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault));
444 }
445 const authCheckExpressions = [
446 staticGroupAuthorizationExpression,
447 graphql_mapping_template_1.newline(),
448 dynamicGroupAuthorizationExpression,
449 graphql_mapping_template_1.newline(),
450 ownerAuthorizationExpression,
451 graphql_mapping_template_1.newline(),
452 throwIfUnauthorizedExpression,
453 ];
454 expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, graphql_mapping_template_1.compoundExpression(authCheckExpressions)));
455 const templateParts = [
456 graphql_mapping_template_1.print(graphql_mapping_template_1.iff(graphql_mapping_template_1.raw(`$ctx.args.input.containsKey("${field.name.value}")`), graphql_mapping_template_1.compoundExpression(expressions))),
457 createResolverResource.Properties.RequestMappingTemplate,
458 ];
459 createResolverResource.Properties.RequestMappingTemplate = templateParts.join('\n\n');
460 ctx.setResource(resolverResourceId, createResolverResource);
461 }
462 if (modelConfiguration.shouldHave('onCreate') && modelConfiguration.getName('level') === 'on') {
463 const getTemplateParts = [createResolverResource.Properties.ResponseMappingTemplate];
464 if (!this.isOperationExpressionSet(mutationTypeName, createResolverResource.Properties.ResponseMappingTemplate)) {
465 getTemplateParts.unshift(this.resources.setOperationExpression(mutationTypeName));
466 }
467 createResolverResource.Properties.ResponseMappingTemplate = getTemplateParts.join('\n\n');
468 ctx.setResource(resolverResourceId, createResolverResource);
469 }
470 }
471 }
472 splitRules(rules) {
473 const queryRules = {
474 get: [],
475 list: [],
476 };
477 const operationRules = {
478 create: [],
479 update: [],
480 delete: [],
481 read: [],
482 };
483 const matchQuery = (op) => (rule) => {
484 if (rule.queries) {
485 const matchesOp = rule.queries.find(o => o === op);
486 return Boolean(matchesOp);
487 }
488 else if (rule.queries === null) {
489 return false;
490 }
491 return true;
492 };
493 const matchMutation = (op) => (rule) => {
494 if (rule.mutations) {
495 const matchesOp = rule.mutations.find(o => o === op);
496 return Boolean(matchesOp);
497 }
498 else if (rule.mutations === null) {
499 return false;
500 }
501 return true;
502 };
503 const matchOperation = (op) => (rule) => {
504 if (rule.operations) {
505 const matchesOp = rule.operations.find(o => o === op);
506 return Boolean(matchesOp);
507 }
508 else if (rule.operations === null) {
509 return false;
510 }
511 return true;
512 };
513 for (const rule of rules) {
514 if (isTruthyOrNull(rule.operations)) {
515 if (matchOperation('read')(rule)) {
516 queryRules.get.push(rule);
517 queryRules.list.push(rule);
518 operationRules.read.push(rule);
519 }
520 if (matchOperation('create')(rule)) {
521 operationRules.create.push(rule);
522 }
523 if (matchOperation('update')(rule)) {
524 operationRules.update.push(rule);
525 }
526 if (matchOperation('delete')(rule)) {
527 operationRules.delete.push(rule);
528 }
529 }
530 else {
531 if (isUndefined(rule.queries)) {
532 queryRules.get.push(rule);
533 queryRules.list.push(rule);
534 operationRules.read.push(rule);
535 }
536 else {
537 if (matchQuery('get')(rule)) {
538 queryRules.get.push(rule);
539 }
540 if (matchQuery('list')(rule)) {
541 queryRules.list.push(rule);
542 }
543 }
544 if (isUndefined(rule.mutations)) {
545 operationRules.create.push(rule);
546 operationRules.update.push(rule);
547 operationRules.delete.push(rule);
548 }
549 else {
550 if (matchMutation('create')(rule)) {
551 operationRules.create.push(rule);
552 }
553 if (matchMutation('update')(rule)) {
554 operationRules.update.push(rule);
555 }
556 if (matchMutation('delete')(rule)) {
557 operationRules.delete.push(rule);
558 }
559 }
560 }
561 }
562 return {
563 operationRules,
564 queryRules,
565 };
566 }
567 validateRules(rules) {
568 for (const rule of rules) {
569 this.validateRuleAuthStrategy(rule);
570 const { queries, mutations, operations } = rule;
571 if (mutations && operations) {
572 console.warn(`It is not recommended to use 'mutations' and 'operations'. The 'operations' argument will be used.`);
573 }
574 if (queries && operations) {
575 console.warn(`It is not recommended to use 'queries' and 'operations'. The 'operations' argument will be used.`);
576 }
577 this.commonRuleValidation(rule);
578 }
579 }
580 validateFieldRules(rules, isParentTypeBuiltinType, parentHasModelDirective) {
581 for (const rule of rules) {
582 this.validateRuleAuthStrategy(rule);
583 const { queries, mutations } = rule;
584 if (queries || mutations) {
585 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directives used on field definitions may not specify the 'queries' or 'mutations' arguments. \
586All @auth directives used on field definitions are performed when the field is resolved and can be thought of as 'read' operations.`);
587 }
588 if (isParentTypeBuiltinType && rule.operations && rule.operations.length > 0) {
589 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth rules on fields within Query, Mutation, Subscription cannot specify 'operations' argument as these rules \
590are already on an operation already.`);
591 }
592 if (!parentHasModelDirective && rule.operations && rule.operations.length > 0) {
593 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth rules on fields within types that does not have @model directive cannot specify 'operations' argument as there are \
594operations will be generated by the CLI.`);
595 }
596 this.commonRuleValidation(rule);
597 }
598 }
599 commonRuleValidation(rule) {
600 const { identityField, identityClaim, allow, groups, groupsField, groupClaim } = rule;
601 if (allow === 'groups' && (identityClaim || identityField)) {
602 throw new graphql_transformer_core_1.InvalidDirectiveError(`
603 @auth identityField/Claim can only be used for 'allow: owner'`);
604 }
605 if (allow === 'owner' && groupClaim) {
606 throw new graphql_transformer_core_1.InvalidDirectiveError(`
607 @auth groupClaim can only be used 'allow: groups'`);
608 }
609 if (groupsField && groups) {
610 throw new graphql_transformer_core_1.InvalidDirectiveError('This rule has groupsField and groups, please use one or the other');
611 }
612 if (identityField && identityClaim) {
613 throw new graphql_transformer_core_1.InvalidDirectiveError('Please use consider IdentifyClaim over IdentityField as it is deprecated.');
614 }
615 }
616 protectGetQuery(ctx, resolverResourceId, rules, parent, modelConfiguration) {
617 const resolver = ctx.getResource(resolverResourceId);
618 if (!rules || rules.length === 0 || !resolver) {
619 return;
620 }
621 else {
622 let operationName = undefined;
623 if (modelConfiguration.shouldHave('get')) {
624 operationName = modelConfiguration.getName('get');
625 const includeDefault = parent !== null ? this.isTypeHasRulesForOperation(parent, 'get') : false;
626 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
627 if (operationDirectives.length > 0) {
628 this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives);
629 }
630 }
631 if (operationName) {
632 this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules);
633 }
634 const authExpression = this.authorizationExpressionOnSingleObject(rules);
635 if (authExpression) {
636 const templateParts = [graphql_mapping_template_1.print(authExpression), resolver.Properties.ResponseMappingTemplate];
637 resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n');
638 ctx.setResource(resolverResourceId, resolver);
639 }
640 }
641 }
642 authorizationExpressionOnSingleObject(rules, objectPath = 'ctx.result') {
643 const staticGroupAuthorizationRules = this.getStaticGroupRules(rules);
644 const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules);
645 const ownerAuthorizationRules = this.getOwnerRules(rules);
646 const providerAuthorization = this.hasProviderAuthRules(rules);
647 if ((staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) &&
648 providerAuthorization === false) {
649 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules);
650 const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForReadOperations(dynamicGroupAuthorizationRules, objectPath);
651 const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForReadOperations(ownerAuthorizationRules, objectPath);
652 const throwIfUnauthorizedExpression = this.resources.throwIfUnauthorized();
653 const authModesToCheck = new Set();
654 const expressions = new Array();
655 if (ownerAuthorizationRules.find(r => r.provider === 'userPools') ||
656 staticGroupAuthorizationRules.find(r => r.provider === 'userPools') ||
657 dynamicGroupAuthorizationRules.find(r => r.provider === 'userPools')) {
658 authModesToCheck.add('userPools');
659 }
660 if (ownerAuthorizationRules.find(r => r.provider === 'oidc') ||
661 staticGroupAuthorizationRules.find(r => r.provider === 'oidc') ||
662 dynamicGroupAuthorizationRules.find(r => r.provider === 'oidc')) {
663 authModesToCheck.add('oidc');
664 }
665 if (authModesToCheck.size > 0) {
666 const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools';
667 expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault));
668 }
669 const templateExpressions = [
670 staticGroupAuthorizationExpression,
671 graphql_mapping_template_1.newline(),
672 dynamicGroupAuthorizationExpression,
673 graphql_mapping_template_1.newline(),
674 ownerAuthorizationExpression,
675 graphql_mapping_template_1.newline(),
676 throwIfUnauthorizedExpression,
677 ];
678 expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, graphql_mapping_template_1.compoundExpression(templateExpressions)));
679 return graphql_mapping_template_1.compoundExpression(expressions);
680 }
681 }
682 protectListQuery(ctx, resolverResourceId, rules, parent, modelConfiguration, explicitOperationName = undefined) {
683 const resolver = ctx.getResource(resolverResourceId);
684 if (!rules || rules.length === 0 || !resolver) {
685 return;
686 }
687 if (modelConfiguration.shouldHave('list')) {
688 const operationName = explicitOperationName ? explicitOperationName : modelConfiguration.getName('list');
689 const includeDefault = parent !== null ? this.isTypeHasRulesForOperation(parent, 'list') : false;
690 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
691 if (operationDirectives.length > 0) {
692 this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives);
693 }
694 this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules);
695 }
696 const authExpression = this.authorizationExpressionForListResult(rules);
697 if (authExpression) {
698 const templateParts = [graphql_mapping_template_1.print(authExpression), resolver.Properties.ResponseMappingTemplate];
699 resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n');
700 ctx.setResource(resolverResourceId, resolver);
701 }
702 }
703 authorizationExpressionForListResult(rules, itemList = 'ctx.result.items') {
704 const staticGroupAuthorizationRules = this.getStaticGroupRules(rules);
705 const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules);
706 const ownerAuthorizationRules = this.getOwnerRules(rules);
707 const providerAuthorization = this.hasProviderAuthRules(rules);
708 if ((staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) &&
709 providerAuthorization === false) {
710 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules);
711 const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForReadOperations(dynamicGroupAuthorizationRules, 'item', graphql_transformer_common_1.ResourceConstants.SNIPPETS.IsLocalDynamicGroupAuthorizedVariable, graphql_mapping_template_1.raw(`false`));
712 const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForReadOperations(ownerAuthorizationRules, 'item', graphql_transformer_common_1.ResourceConstants.SNIPPETS.IsLocalOwnerAuthorizedVariable, graphql_mapping_template_1.raw(`false`));
713 const appendIfLocallyAuthorized = this.resources.appendItemIfLocallyAuthorized();
714 const ifNotStaticallyAuthedFilterObjects = graphql_mapping_template_1.iff(graphql_mapping_template_1.not(graphql_mapping_template_1.ref(graphql_transformer_common_1.ResourceConstants.SNIPPETS.IsStaticGroupAuthorizedVariable)), graphql_mapping_template_1.compoundExpression([
715 graphql_mapping_template_1.set(graphql_mapping_template_1.ref('items'), graphql_mapping_template_1.list([])),
716 graphql_mapping_template_1.forEach(graphql_mapping_template_1.ref('item'), graphql_mapping_template_1.ref(itemList), [
717 dynamicGroupAuthorizationExpression,
718 graphql_mapping_template_1.newline(),
719 ownerAuthorizationExpression,
720 graphql_mapping_template_1.newline(),
721 appendIfLocallyAuthorized,
722 ]),
723 graphql_mapping_template_1.set(graphql_mapping_template_1.ref(itemList), graphql_mapping_template_1.ref('items')),
724 ]));
725 const authModesToCheck = new Set();
726 const expressions = new Array();
727 if (ownerAuthorizationRules.find(r => r.provider === 'userPools') ||
728 staticGroupAuthorizationRules.find(r => r.provider === 'userPools') ||
729 dynamicGroupAuthorizationRules.find(r => r.provider === 'userPools')) {
730 authModesToCheck.add('userPools');
731 }
732 if (ownerAuthorizationRules.find(r => r.provider === 'oidc') ||
733 staticGroupAuthorizationRules.find(r => r.provider === 'oidc') ||
734 dynamicGroupAuthorizationRules.find(r => r.provider === 'oidc')) {
735 authModesToCheck.add('oidc');
736 }
737 if (authModesToCheck.size > 0) {
738 const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools';
739 expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault));
740 }
741 const templateExpressions = [
742 staticGroupAuthorizationExpression,
743 graphql_mapping_template_1.newline(),
744 graphql_mapping_template_1.comment('[Start] If not static group authorized, filter items'),
745 ifNotStaticallyAuthedFilterObjects,
746 graphql_mapping_template_1.comment('[End] If not static group authorized, filter items'),
747 ];
748 expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, graphql_mapping_template_1.compoundExpression(templateExpressions)));
749 return graphql_mapping_template_1.compoundExpression(expressions);
750 }
751 }
752 protectCreateMutation(ctx, resolverResourceId, rules, parent, modelConfiguration) {
753 const resolver = ctx.getResource(resolverResourceId);
754 if (!rules || rules.length === 0 || !resolver) {
755 return;
756 }
757 else {
758 const mutationTypeName = ctx.getMutationTypeName();
759 if (modelConfiguration.shouldHave('create')) {
760 const operationName = modelConfiguration.getName('create');
761 const includeDefault = this.isTypeHasRulesForOperation(parent, 'create');
762 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
763 if (operationDirectives.length > 0) {
764 this.addDirectivesToOperation(ctx, mutationTypeName, operationName, operationDirectives);
765 }
766 this.addFieldToResourceReferences(mutationTypeName, operationName, rules);
767 }
768 const staticGroupAuthorizationRules = this.getStaticGroupRules(rules);
769 const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules);
770 const ownerAuthorizationRules = this.getOwnerRules(rules);
771 const providerAuthorization = this.hasProviderAuthRules(rules);
772 if ((staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) &&
773 providerAuthorization === false) {
774 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules);
775 const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForCreateOperations(dynamicGroupAuthorizationRules);
776 const fieldIsList = (fieldName) => {
777 const field = parent.fields.find(field => field.name.value === fieldName);
778 if (field) {
779 return graphql_transformer_common_1.isListType(field.type);
780 }
781 return false;
782 };
783 const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForCreateOperations(ownerAuthorizationRules, fieldIsList);
784 const throwIfUnauthorizedExpression = this.resources.throwIfUnauthorized();
785 const authModesToCheck = new Set();
786 const expressions = new Array();
787 if (ownerAuthorizationRules.find(r => r.provider === 'userPools') ||
788 staticGroupAuthorizationRules.find(r => r.provider === 'userPools') ||
789 dynamicGroupAuthorizationRules.find(r => r.provider === 'userPools')) {
790 authModesToCheck.add('userPools');
791 }
792 if (ownerAuthorizationRules.find(r => r.provider === 'oidc') ||
793 staticGroupAuthorizationRules.find(r => r.provider === 'oidc') ||
794 dynamicGroupAuthorizationRules.find(r => r.provider === 'oidc')) {
795 authModesToCheck.add('oidc');
796 }
797 if (authModesToCheck.size > 0) {
798 const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools';
799 expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault));
800 }
801 const authCheckExpressions = [
802 staticGroupAuthorizationExpression,
803 graphql_mapping_template_1.newline(),
804 dynamicGroupAuthorizationExpression,
805 graphql_mapping_template_1.newline(),
806 ownerAuthorizationExpression,
807 graphql_mapping_template_1.newline(),
808 throwIfUnauthorizedExpression,
809 ];
810 expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, graphql_mapping_template_1.compoundExpression(authCheckExpressions)));
811 const templateParts = [graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression(expressions)), resolver.Properties.RequestMappingTemplate];
812 resolver.Properties.RequestMappingTemplate = templateParts.join('\n\n');
813 ctx.setResource(resolverResourceId, resolver);
814 }
815 }
816 }
817 protectUpdateOrDeleteMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, isUpdate, field, ifCondition, subscriptionOperation) {
818 const resolver = ctx.getResource(resolverResourceId);
819 if (!rules || rules.length === 0 || !resolver) {
820 return;
821 }
822 else {
823 const mutationTypeName = ctx.getMutationTypeName();
824 if (modelConfiguration.shouldHave(isUpdate ? 'update' : 'delete')) {
825 const operationName = modelConfiguration.getName(isUpdate ? 'update' : 'delete');
826 const includeDefault = Boolean(!field && this.isTypeHasRulesForOperation(parent, isUpdate ? 'update' : 'delete'));
827 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
828 if (operationDirectives.length > 0) {
829 this.addDirectivesToOperation(ctx, mutationTypeName, operationName, operationDirectives);
830 }
831 this.addFieldToResourceReferences(mutationTypeName, operationName, rules);
832 }
833 const staticGroupAuthorizationRules = this.getStaticGroupRules(rules);
834 const dynamicGroupAuthorizationRules = this.getDynamicGroupRules(rules);
835 const ownerAuthorizationRules = this.getOwnerRules(rules);
836 const providerAuthorization = this.hasProviderAuthRules(rules);
837 if ((staticGroupAuthorizationRules.length > 0 || dynamicGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) &&
838 providerAuthorization === false) {
839 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules, field);
840 const fieldIsList = (fieldName) => {
841 const field = parent.fields.find(field => field.name.value === fieldName);
842 if (field) {
843 return graphql_transformer_common_1.isListType(field.type);
844 }
845 return false;
846 };
847 const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForUpdateOrDeleteOperations(dynamicGroupAuthorizationRules, fieldIsList, field ? field.name.value : undefined);
848 const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForUpdateOrDeleteOperations(ownerAuthorizationRules, fieldIsList, field ? field.name.value : undefined);
849 const collectAuthCondition = this.resources.collectAuthCondition();
850 const staticGroupAuthorizedVariable = this.resources.getStaticAuthorizationVariable(field);
851 const ifNotStaticallyAuthedCreateAuthCondition = graphql_mapping_template_1.iff(graphql_mapping_template_1.raw(`! $${staticGroupAuthorizedVariable}`), graphql_mapping_template_1.compoundExpression([
852 dynamicGroupAuthorizationExpression,
853 graphql_mapping_template_1.newline(),
854 ownerAuthorizationExpression,
855 graphql_mapping_template_1.newline(),
856 collectAuthCondition,
857 ]));
858 const throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty = this.resources.throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty(field);
859 const authModesToCheck = new Set();
860 const expressions = new Array();
861 if (ownerAuthorizationRules.find(r => r.provider === 'userPools') ||
862 staticGroupAuthorizationRules.find(r => r.provider === 'userPools') ||
863 dynamicGroupAuthorizationRules.find(r => r.provider === 'userPools')) {
864 authModesToCheck.add('userPools');
865 }
866 if (ownerAuthorizationRules.find(r => r.provider === 'oidc') ||
867 staticGroupAuthorizationRules.find(r => r.provider === 'oidc') ||
868 dynamicGroupAuthorizationRules.find(r => r.provider === 'oidc')) {
869 authModesToCheck.add('oidc');
870 }
871 if (authModesToCheck.size > 0) {
872 const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools';
873 expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault));
874 }
875 const authorizationLogic = graphql_mapping_template_1.compoundExpression([
876 staticGroupAuthorizationExpression,
877 graphql_mapping_template_1.newline(),
878 ifNotStaticallyAuthedCreateAuthCondition,
879 graphql_mapping_template_1.newline(),
880 throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty,
881 ]);
882 expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, authorizationLogic));
883 const templateParts = [
884 graphql_mapping_template_1.print(field && ifCondition ? graphql_mapping_template_1.iff(ifCondition, graphql_mapping_template_1.compoundExpression(expressions)) : graphql_mapping_template_1.compoundExpression(expressions)),
885 resolver.Properties.RequestMappingTemplate,
886 ];
887 resolver.Properties.RequestMappingTemplate = templateParts.join('\n\n');
888 ctx.setResource(resolverResourceId, resolver);
889 }
890 if (field &&
891 subscriptionOperation &&
892 modelConfiguration.shouldHave(subscriptionOperation) &&
893 modelConfiguration.getName('level') === 'on') {
894 let mutationResolver = resolver;
895 let mutationResolverResourceID = resolverResourceId;
896 if (subscriptionOperation === 'onDelete') {
897 mutationResolverResourceID = graphql_transformer_common_1.ResolverResourceIDs.DynamoDBDeleteResolverResourceID(parent.name.value);
898 mutationResolver = ctx.getResource(mutationResolverResourceID);
899 }
900 const getTemplateParts = [mutationResolver.Properties.ResponseMappingTemplate];
901 if (!this.isOperationExpressionSet(mutationTypeName, mutationResolver.Properties.ResponseMappingTemplate)) {
902 getTemplateParts.unshift(this.resources.setOperationExpression(mutationTypeName));
903 }
904 mutationResolver.Properties.ResponseMappingTemplate = getTemplateParts.join('\n\n');
905 ctx.setResource(mutationResolverResourceID, mutationResolver);
906 }
907 }
908 }
909 protectUpdateMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, field, subscriptionOperation) {
910 return this.protectUpdateOrDeleteMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, true, field, field ? graphql_mapping_template_1.raw(`$ctx.args.input.containsKey("${field.name.value}")`) : undefined, subscriptionOperation);
911 }
912 protectDeleteMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, field, subscriptionOperation) {
913 return this.protectUpdateOrDeleteMutation(ctx, resolverResourceId, rules, parent, modelConfiguration, false, field, field
914 ? graphql_mapping_template_1.raw(`$ctx.args.input.containsKey("${field.name.value}") && $util.isNull($ctx.args.input.get("${field.name.value}"))`)
915 : undefined, subscriptionOperation);
916 }
917 protectConnections(ctx, def, rules, modelConfiguration) {
918 const thisModelName = def.name.value;
919 for (const inputDef of ctx.inputDocument.definitions) {
920 if (inputDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
921 for (const field of inputDef.fields) {
922 const returnTypeName = graphql_transformer_common_1.getBaseType(field.type);
923 if (fieldHasDirective(field, 'connection') && returnTypeName === thisModelName) {
924 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(inputDef.name.value, field.name.value);
925 const directives = this.getDirectivesForRules(rules, false);
926 if (directives.length > 0) {
927 this.addDirectivesToField(ctx, inputDef.name.value, field.name.value, directives);
928 }
929 if (graphql_transformer_common_1.isListType(field.type)) {
930 this.protectListQuery(ctx, resolverResourceId, rules, null, modelConfiguration);
931 }
932 else {
933 this.protectGetQuery(ctx, resolverResourceId, rules, null, modelConfiguration);
934 }
935 }
936 }
937 }
938 }
939 }
940 protectQueries(ctx, def, rules, modelConfiguration) {
941 const secondaryKeyDirectivesWithQueries = (def.directives || []).filter(d => {
942 const isKey = d.name.value === 'key';
943 const args = graphql_transformer_core_1.getDirectiveArguments(d);
944 const isSecondaryKey = Boolean(args.name);
945 const hasQueryField = Boolean(args.queryField);
946 return isKey && isSecondaryKey && hasQueryField;
947 });
948 for (const keyWithQuery of secondaryKeyDirectivesWithQueries) {
949 const args = graphql_transformer_core_1.getDirectiveArguments(keyWithQuery);
950 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(ctx.getQueryTypeName(), args.queryField);
951 this.protectListQuery(ctx, resolverResourceId, rules, null, modelConfiguration, args.queryField);
952 }
953 }
954 protectSearchQuery(ctx, def, resolverResourceId, rules) {
955 const resolver = ctx.getResource(resolverResourceId);
956 if (!rules || rules.length === 0 || !resolver) {
957 return;
958 }
959 else {
960 const operationName = resolver.Properties.FieldName;
961 const includeDefault = def !== null ? this.isTypeHasRulesForOperation(def, 'list') : false;
962 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
963 if (operationDirectives.length > 0) {
964 this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives);
965 }
966 this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules);
967 const authExpression = this.authorizationExpressionForListResult(rules, 'es_items');
968 if (authExpression) {
969 const templateParts = [
970 graphql_mapping_template_1.print(this.resources.makeESItemsExpression(ctx.isProjectUsingDataStore())),
971 graphql_mapping_template_1.print(authExpression),
972 graphql_mapping_template_1.print(this.resources.makeESToGQLExpression()),
973 ];
974 resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n');
975 ctx.setResource(resolverResourceId, resolver);
976 }
977 }
978 }
979 protectSyncQuery(ctx, def, resolverResourceID, rules) {
980 const resolver = ctx.getResource(resolverResourceID);
981 if (!rules || rules.length === 0 || !resolver) {
982 return;
983 }
984 const operationName = resolver.Properties.FieldName;
985 const includeDefault = def !== null ? this.isTypeHasRulesForOperation(def, 'list') : false;
986 const operationDirectives = this.getDirectivesForRules(rules, includeDefault);
987 if (operationDirectives.length > 0) {
988 this.addDirectivesToOperation(ctx, ctx.getQueryTypeName(), operationName, operationDirectives);
989 }
990 this.addFieldToResourceReferences(ctx.getQueryTypeName(), operationName, rules);
991 const authExpression = this.authorizationExpressionForListResult(rules);
992 if (authExpression) {
993 const templateParts = [graphql_mapping_template_1.print(authExpression), resolver.Properties.ResponseMappingTemplate];
994 resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n');
995 ctx.setResource(resolverResourceID, resolver);
996 }
997 }
998 protectOnCreateSubscription(ctx, rules, parent, modelConfiguration) {
999 const names = modelConfiguration.getNames('onCreate');
1000 const level = modelConfiguration.getName('level');
1001 if (names) {
1002 names.forEach(name => {
1003 this.addSubscriptionResolvers(ctx, rules, parent, level, name);
1004 });
1005 }
1006 }
1007 protectOnUpdateSubscription(ctx, rules, parent, modelConfiguration) {
1008 const names = modelConfiguration.getNames('onUpdate');
1009 const level = modelConfiguration.getName('level');
1010 if (names) {
1011 names.forEach(name => {
1012 this.addSubscriptionResolvers(ctx, rules, parent, level, name);
1013 });
1014 }
1015 }
1016 protectOnDeleteSubscription(ctx, rules, parent, modelConfiguration) {
1017 const names = modelConfiguration.getNames('onDelete');
1018 const level = modelConfiguration.getName('level');
1019 if (names) {
1020 names.forEach(name => {
1021 this.addSubscriptionResolvers(ctx, rules, parent, level, name);
1022 });
1023 }
1024 }
1025 addSubscriptionResolvers(ctx, rules, parent, level, fieldName) {
1026 const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID('Subscription', fieldName);
1027 const resolver = this.resources.generateSubscriptionResolver(fieldName);
1028 const noneDS = ctx.getResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.NoneDataSource);
1029 if (!rules || rules.length === 0) {
1030 return;
1031 }
1032 else if (level === 'public') {
1033 ctx.setResource(resolverResourceId, resolver);
1034 }
1035 else {
1036 const includeDefault = parent !== null ? this.isTypeHasRulesForOperation(parent, 'get') : false;
1037 const directives = this.getDirectivesForRules(rules, includeDefault);
1038 if (directives.length > 0) {
1039 this.addDirectivesToField(ctx, ctx.getSubscriptionTypeName(), fieldName, directives);
1040 }
1041 this.addFieldToResourceReferences(ctx.getSubscriptionTypeName(), fieldName, rules);
1042 const staticGroupAuthorizationRules = this.getStaticGroupRules(rules);
1043 const ownerAuthorizationRules = this.getOwnerRules(rules);
1044 const providerAuthorization = this.hasProviderAuthRules(rules);
1045 if ((staticGroupAuthorizationRules.length > 0 || ownerAuthorizationRules.length > 0) && providerAuthorization === false) {
1046 const staticGroupAuthorizationExpression = this.resources.staticGroupAuthorizationExpression(staticGroupAuthorizationRules);
1047 const ownerAuthorizationExpression = this.resources.ownerAuthorizationExpressionForSubscriptions(ownerAuthorizationRules);
1048 const throwIfUnauthorizedExpression = this.resources.throwIfSubscriptionUnauthorized();
1049 const authModesToCheck = new Set();
1050 const expressions = new Array();
1051 if (ownerAuthorizationRules.find(r => r.provider === 'userPools') ||
1052 staticGroupAuthorizationRules.find(r => r.provider === 'userPools')) {
1053 authModesToCheck.add('userPools');
1054 }
1055 if (ownerAuthorizationRules.find(r => r.provider === 'oidc') || staticGroupAuthorizationRules.find(r => r.provider === 'oidc')) {
1056 authModesToCheck.add('oidc');
1057 }
1058 if (authModesToCheck.size > 0) {
1059 const isUserPoolTheDefault = this.configuredAuthProviders.default === 'userPools';
1060 expressions.push(this.resources.getAuthModeDeterminationExpression(authModesToCheck, isUserPoolTheDefault));
1061 }
1062 const authCheckExpressions = [
1063 staticGroupAuthorizationExpression,
1064 graphql_mapping_template_1.newline(),
1065 ownerAuthorizationExpression,
1066 graphql_mapping_template_1.newline(),
1067 throwIfUnauthorizedExpression,
1068 ];
1069 expressions.push(this.resources.getAuthModeCheckWrappedExpression(authModesToCheck, graphql_mapping_template_1.compoundExpression(authCheckExpressions)));
1070 const templateParts = [graphql_mapping_template_1.print(graphql_mapping_template_1.compoundExpression(expressions)), resolver.Properties.ResponseMappingTemplate];
1071 resolver.Properties.ResponseMappingTemplate = templateParts.join('\n\n');
1072 ctx.setResource(resolverResourceId, resolver);
1073 const ownerRules = rules.filter(rule => rule.allow === constants_1.OWNER_AUTH_STRATEGY);
1074 const needsDefaultOwnerField = ownerRules.find(rule => !rule.ownerField);
1075 const hasStaticGroupAuth = rules.find(rule => rule.allow === constants_1.GROUPS_AUTH_STRATEGY && !rule.groupsField);
1076 if (ownerRules) {
1077 if (needsDefaultOwnerField) {
1078 this.addOwner(ctx, parent.name.value);
1079 }
1080 const makeNonNull = hasStaticGroupAuth ? false : true;
1081 this.addSubscriptionOwnerArgument(ctx, resolver, ownerRules, makeNonNull);
1082 }
1083 }
1084 }
1085 if (!noneDS) {
1086 ctx.setResource(graphql_transformer_common_1.ResourceConstants.RESOURCES.NoneDataSource, this.resources.noneDataSource());
1087 }
1088 ctx.mapResourceToStack(parent.name.value, resolverResourceId);
1089 }
1090 addSubscriptionOwnerArgument(ctx, resolver, ownerRules, makeNonNull = false) {
1091 let subscription = ctx.getSubscription();
1092 let createField = subscription.fields.find(field => field.name.value === resolver.Properties.FieldName);
1093 const nameNode = makeNonNull ? graphql_transformer_common_1.makeNonNullType(graphql_transformer_common_1.makeNamedType('String')) : graphql_transformer_common_1.makeNamedType('String');
1094 const ownerArgumentList = ownerRules.map(rule => {
1095 return graphql_transformer_common_1.makeInputValueDefinition(rule.ownerField || constants_1.DEFAULT_OWNER_FIELD, nameNode);
1096 });
1097 createField = {
1098 ...createField,
1099 arguments: ownerArgumentList,
1100 };
1101 subscription = {
1102 ...subscription,
1103 fields: subscription.fields.map(field => (field.name.value === resolver.Properties.FieldName ? createField : field)),
1104 };
1105 ctx.putType(subscription);
1106 }
1107 addOwner(ctx, parent) {
1108 const modelType = ctx.getType(parent);
1109 const fields = graphql_transformer_core_1.getFieldArguments(modelType);
1110 if (!('owner' in fields)) {
1111 modelType.fields.push(graphql_transformer_common_1.makeField(constants_1.DEFAULT_OWNER_FIELD, [], graphql_transformer_common_1.makeNamedType('String')));
1112 }
1113 ctx.putType(modelType);
1114 }
1115 getOwnerRules(rules) {
1116 return rules.filter(rule => rule.allow === 'owner');
1117 }
1118 getStaticGroupRules(rules) {
1119 return rules.filter(rule => rule.allow === 'groups' && Boolean(rule.groups));
1120 }
1121 getDynamicGroupRules(rules) {
1122 return rules.filter(rule => rule.allow === 'groups' && !Boolean(rule.groups));
1123 }
1124 hasProviderAuthRules(rules) {
1125 return rules.filter(rule => rule.provider === 'userPools' && (rule.allow === 'public' || rule.allow === 'private')).length > 0;
1126 }
1127 extendTypeWithDirectives(ctx, typeName, directives) {
1128 let objectTypeExtension = graphql_transformer_common_1.blankObjectExtension(typeName);
1129 objectTypeExtension = graphql_transformer_common_1.extensionWithDirectives(objectTypeExtension, directives);
1130 ctx.addObjectExtension(objectTypeExtension);
1131 }
1132 addDirectivesToOperation(ctx, typeName, operationName, directives) {
1133 this.addDirectivesToField(ctx, typeName, operationName, directives);
1134 const type = ctx.getType(typeName);
1135 if (type) {
1136 const field = type.fields.find(f => f.name.value === operationName);
1137 if (field) {
1138 const returnFieldType = field.type;
1139 if (returnFieldType.name) {
1140 const returnTypeName = returnFieldType.name.value;
1141 this.extendTypeWithDirectives(ctx, returnTypeName, directives);
1142 }
1143 }
1144 }
1145 }
1146 addDirectivesToField(ctx, typeName, fieldName, directives) {
1147 const type = ctx.getType(typeName);
1148 if (type) {
1149 const field = type.fields.find(f => f.name.value === fieldName);
1150 if (field) {
1151 const newFields = [...type.fields.filter(f => f.name.value !== field.name.value), graphql_transformer_common_1.extendFieldWithDirectives(field, directives)];
1152 const newMutation = {
1153 ...type,
1154 fields: newFields,
1155 };
1156 ctx.putType(newMutation);
1157 }
1158 }
1159 }
1160 getDirectivesForRules(rules, addDefaultIfNeeded = true) {
1161 if (!rules || rules.length === 0) {
1162 return [];
1163 }
1164 const directives = new Array();
1165 const addDirectiveIfNeeded = (provider, directiveName) => {
1166 if ((this.configuredAuthProviders.default !== provider && Boolean(rules.find(r => r.provider === provider))) ||
1167 (this.configuredAuthProviders.default === provider &&
1168 Boolean(rules.find(r => r.provider !== provider && addDefaultIfNeeded === true)))) {
1169 directives.push(graphql_transformer_common_1.makeDirective(directiveName, []));
1170 }
1171 };
1172 const authProviderDirectiveMap = new Map([
1173 ['apiKey', 'aws_api_key'],
1174 ['iam', 'aws_iam'],
1175 ['oidc', 'aws_oidc'],
1176 ['userPools', 'aws_cognito_user_pools'],
1177 ]);
1178 for (const entry of authProviderDirectiveMap.entries()) {
1179 addDirectiveIfNeeded(entry[0], entry[1]);
1180 }
1181 if (Boolean(rules.find(r => r.provider === this.configuredAuthProviders.default)) &&
1182 Boolean(rules.find(r => r.provider !== this.configuredAuthProviders.default) &&
1183 !Boolean(directives.find(d => d.name.value === authProviderDirectiveMap.get(this.configuredAuthProviders.default))))) {
1184 directives.push(graphql_transformer_common_1.makeDirective(authProviderDirectiveMap.get(this.configuredAuthProviders.default), []));
1185 }
1186 return directives;
1187 }
1188 ensureDefaultAuthProviderAssigned(rules) {
1189 for (const rule of rules) {
1190 if (!rule.provider) {
1191 switch (rule.allow) {
1192 case 'owner':
1193 case 'groups':
1194 rule.provider = 'userPools';
1195 break;
1196 case 'private':
1197 rule.provider = 'userPools';
1198 break;
1199 case 'public':
1200 rule.provider = 'apiKey';
1201 break;
1202 default:
1203 rule.provider = null;
1204 break;
1205 }
1206 }
1207 }
1208 }
1209 validateRuleAuthStrategy(rule) {
1210 if (rule.allow === 'groups' && rule.provider !== 'userPools' && rule.provider !== 'oidc') {
1211 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'groups' strategy only supports 'userPools' and 'oidc' providers, but found '${rule.provider}' assigned.`);
1212 }
1213 if (rule.allow === 'owner') {
1214 if (rule.provider !== null && rule.provider !== 'userPools' && rule.provider !== 'oidc') {
1215 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'owner' strategy only supports 'userPools' (default) and 'oidc' providers, but \
1216found '${rule.provider}' assigned.`);
1217 }
1218 }
1219 if (rule.allow === 'public') {
1220 if (rule.provider !== null && rule.provider !== 'apiKey' && rule.provider !== 'iam') {
1221 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'public' strategy only supports 'apiKey' (default) and 'iam' providers, but \
1222found '${rule.provider}' assigned.`);
1223 }
1224 }
1225 if (rule.allow === 'private') {
1226 if (rule.provider !== null && rule.provider !== 'userPools' && rule.provider !== 'iam') {
1227 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'private' strategy only supports 'userPools' (default) and 'iam' providers, but \
1228found '${rule.provider}' assigned.`);
1229 }
1230 }
1231 if (rule.provider === 'apiKey' && this.configuredAuthProviders.hasApiKey === false) {
1232 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'apiKey' provider found, but the project has no API Key authentication provider configured.`);
1233 }
1234 else if (rule.provider === 'oidc' && this.configuredAuthProviders.hasOIDC === false) {
1235 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'oidc' provider found, but the project has no OPENID_CONNECT authentication provider configured.`);
1236 }
1237 else if (rule.provider === 'userPools' && this.configuredAuthProviders.hasUserPools === false) {
1238 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'userPools' provider found, but the project has no Cognito User Pools authentication provider configured.`);
1239 }
1240 else if (rule.provider === 'iam' && this.configuredAuthProviders.hasIAM === false) {
1241 throw new graphql_transformer_core_1.InvalidDirectiveError(`@auth directive with 'iam' provider found, but the project has no IAM authentication provider configured.`);
1242 }
1243 }
1244 getConfiguredAuthProviders() {
1245 const providers = [
1246 this.config.authConfig.defaultAuthentication.authenticationType,
1247 ...this.config.authConfig.additionalAuthenticationProviders.map(p => p.authenticationType),
1248 ];
1249 const getAuthProvider = (authType) => {
1250 switch (authType) {
1251 case 'AMAZON_COGNITO_USER_POOLS':
1252 return 'userPools';
1253 case 'API_KEY':
1254 return 'apiKey';
1255 case 'AWS_IAM':
1256 return 'iam';
1257 case 'OPENID_CONNECT':
1258 return 'oidc';
1259 }
1260 };
1261 return {
1262 default: getAuthProvider(this.config.authConfig.defaultAuthentication.authenticationType),
1263 onlyDefaultAuthProviderConfigured: this.config.authConfig.additionalAuthenticationProviders.length === 0,
1264 hasApiKey: providers.find(p => p === 'API_KEY') ? true : false,
1265 hasUserPools: providers.find(p => p === 'AMAZON_COGNITO_USER_POOLS') ? true : false,
1266 hasOIDC: providers.find(p => p === 'OPENID_CONNECT') ? true : false,
1267 hasIAM: providers.find(p => p === 'AWS_IAM') ? true : false,
1268 };
1269 }
1270 setAuthPolicyFlag(rules) {
1271 if (!rules || rules.length === 0 || this.generateIAMPolicyforAuthRole === true) {
1272 return;
1273 }
1274 for (const rule of rules) {
1275 if ((rule.allow === 'private' || rule.allow === 'public') && rule.provider === 'iam') {
1276 this.generateIAMPolicyforAuthRole = true;
1277 return;
1278 }
1279 }
1280 }
1281 setUnauthPolicyFlag(rules) {
1282 if (!rules || rules.length === 0 || this.generateIAMPolicyforUnauthRole === true) {
1283 return;
1284 }
1285 for (const rule of rules) {
1286 if (rule.allow === 'public' && rule.provider === 'iam') {
1287 this.generateIAMPolicyforUnauthRole = true;
1288 return;
1289 }
1290 }
1291 }
1292 getAuthRulesFromDirective(directive) {
1293 const get = (s) => (arg) => arg.name.value === s;
1294 const getArg = (arg, dflt) => {
1295 const argument = directive.arguments.find(get(arg));
1296 return argument ? graphql_1.valueFromASTUntyped(argument.value) : dflt;
1297 };
1298 return getArg('rules', []);
1299 }
1300 isTypeNeedsDefaultProviderAccess(def) {
1301 const authDirective = def.directives.find(dir => dir.name.value === 'auth');
1302 if (!authDirective) {
1303 return true;
1304 }
1305 const rules = this.getAuthRulesFromDirective(authDirective);
1306 this.ensureDefaultAuthProviderAssigned(rules);
1307 return Boolean(rules.find(r => r.provider === this.configuredAuthProviders.default));
1308 }
1309 isTypeHasRulesForOperation(def, operation) {
1310 const authDirective = def.directives.find(dir => dir.name.value === 'auth');
1311 if (!authDirective) {
1312 return false;
1313 }
1314 const rules = this.getAuthRulesFromDirective(authDirective);
1315 this.ensureDefaultAuthProviderAssigned(rules);
1316 const { operationRules, queryRules } = this.splitRules(rules);
1317 const hasRulesForDefaultProvider = (operationRules) => {
1318 return Boolean(operationRules.find(r => r.provider === this.configuredAuthProviders.default));
1319 };
1320 switch (operation) {
1321 case 'create':
1322 return hasRulesForDefaultProvider(operationRules.create);
1323 case 'update':
1324 return hasRulesForDefaultProvider(operationRules.update);
1325 case 'delete':
1326 return hasRulesForDefaultProvider(operationRules.delete);
1327 case 'get':
1328 return hasRulesForDefaultProvider(operationRules.read) || hasRulesForDefaultProvider(queryRules.get);
1329 case 'list':
1330 return hasRulesForDefaultProvider(operationRules.read) || hasRulesForDefaultProvider(queryRules.list);
1331 }
1332 return false;
1333 }
1334 addTypeToResourceReferences(typeName, rules) {
1335 const iamPublicRules = rules.filter(r => r.allow === 'public' && r.provider === 'iam');
1336 const iamPrivateRules = rules.filter(r => r.allow === 'private' && r.provider === 'iam');
1337 if (iamPublicRules.length > 0) {
1338 this.unauthPolicyResources.add(`${typeName}/null`);
1339 this.authPolicyResources.add(`${typeName}/null`);
1340 }
1341 if (iamPrivateRules.length > 0) {
1342 this.authPolicyResources.add(`${typeName}/null`);
1343 }
1344 }
1345 addFieldToResourceReferences(typeName, fieldName, rules) {
1346 const iamPublicRules = rules.filter(r => r.allow === 'public' && r.provider === 'iam');
1347 const iamPrivateRules = rules.filter(r => r.allow === 'private' && r.provider === 'iam');
1348 if (iamPublicRules.length > 0) {
1349 this.unauthPolicyResources.add(`${typeName}/${fieldName}`);
1350 this.authPolicyResources.add(`${typeName}/${fieldName}`);
1351 }
1352 if (iamPrivateRules.length > 0) {
1353 this.authPolicyResources.add(`${typeName}/${fieldName}`);
1354 }
1355 }
1356 isOperationExpressionSet(operationTypeName, template) {
1357 return template.includes(`$context.result.operation = "${operationTypeName}"`);
1358 }
1359 updateMutationConditionInput(ctx, type, rules) {
1360 const tableXMutationConditionInputName = graphql_transformer_common_1.ModelResourceIDs.ModelConditionInputTypeName(type.name.value);
1361 if (this.typeExist(tableXMutationConditionInputName, ctx)) {
1362 const tableXMutationConditionInput = ctx.getType(tableXMutationConditionInputName);
1363 const fieldNames = new Set();
1364 const getAuthFieldNames = () => {
1365 if (rules.length > 0) {
1366 const ownerRules = this.getOwnerRules(rules);
1367 const ownerFieldNameArgs = ownerRules.filter(rule => !!rule.ownerField).map(rule => rule.ownerField);
1368 ownerFieldNameArgs.forEach((f) => fieldNames.add(f));
1369 if (ownerRules.find(rule => !rule.ownerField)) {
1370 fieldNames.add('owner');
1371 }
1372 const groupsRules = rules.filter(rule => rule.allow === 'groups');
1373 const groupFieldNameArgs = groupsRules.filter(rule => !!rule.groupsField).map(rule => rule.groupsField);
1374 groupFieldNameArgs.forEach((f) => fieldNames.add(f));
1375 if (groupsRules.find(rule => !rule.groupsField)) {
1376 fieldNames.add('groups');
1377 }
1378 }
1379 };
1380 getAuthFieldNames();
1381 if (fieldNames.size > 0) {
1382 const reducedFields = tableXMutationConditionInput.fields.filter(field => !fieldNames.has(field.name.value));
1383 const updatedInput = {
1384 ...tableXMutationConditionInput,
1385 fields: reducedFields,
1386 };
1387 ctx.putType(updatedInput);
1388 }
1389 }
1390 }
1391 typeExist(type, ctx) {
1392 return Boolean(type in ctx.nodeMap);
1393 }
1394 isSyncEnabled(ctx, typeName) {
1395 const resolverConfig = ctx.getResolverConfig();
1396 if (resolverConfig && resolverConfig.project) {
1397 return true;
1398 }
1399 if (resolverConfig && resolverConfig.models && resolverConfig.models[typeName]) {
1400 return true;
1401 }
1402 return false;
1403 }
1404}
1405exports.ModelAuthTransformer = ModelAuthTransformer;
1406function fieldHasDirective(field, directiveName) {
1407 return (field.directives && field.directives.length && Boolean(field.directives.find((d) => d.name.value === directiveName)));
1408}
1409function isTruthyOrNull(obj) {
1410 return obj || obj === null;
1411}
1412function isUndefined(obj) {
1413 return obj === undefined;
1414}
1415//# sourceMappingURL=ModelAuthTransformer.js.map
\No newline at end of file