UNPKG

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