@kensio/yulin 1.21.11 → 1.21.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/service/cloudfront/controller/web-acl/sim-cf-web-acl-guard.js +1 -0
  2. package/dist/service/wafv2/association/sim-waf-associations.js +1 -1
  3. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.js +1 -0
  4. package/dist/service/wafv2/command/web-acl/sim-waf-web-acl-output.js +1 -0
  5. package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.js +0 -6
  6. package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.js +1 -0
  7. package/dist/service/wafv2/command/web-acl/web-acl.command.d.ts +3 -1
  8. package/dist/service/wafv2/evaluate/sim-waf-evaluation-request.d.ts +8 -0
  9. package/dist/service/wafv2/evaluate/sim-waf-inspected-request.d.ts +14 -1
  10. package/dist/service/wafv2/evaluate/sim-waf-inspected-request.js +7 -1
  11. package/dist/service/wafv2/index.d.ts +2 -1
  12. package/dist/service/wafv2/index.js +2 -1
  13. package/dist/service/wafv2/managed/sim-waf-managed-request.js +1 -2
  14. package/dist/service/wafv2/sim-wafv2.js +2 -1
  15. package/dist/service/wafv2/statement/sim-waf-field-content.d.ts +9 -6
  16. package/dist/service/wafv2/statement/sim-waf-field-content.js +16 -10
  17. package/dist/service/wafv2/statement/sim-waf-set-field.js +3 -3
  18. package/dist/service/wafv2/web-acl/sim-waf-association-config.d.ts +54 -0
  19. package/dist/service/wafv2/web-acl/sim-waf-association-config.js +92 -0
  20. package/dist/service/wafv2/web-acl/sim-waf-web-acl-configuration.d.ts +2 -0
  21. package/dist/service/wafv2/web-acl/sim-waf-web-acl.d.ts +9 -0
  22. package/dist/service/wafv2/web-acl/sim-waf-web-acl.js +15 -0
  23. package/docs/services/wafv2/README.md +19 -5
  24. package/package.json +1 -1
@@ -39,6 +39,7 @@ export class SimCfWebAclGuard {
39
39
  webAclArn,
40
40
  request,
41
41
  body: await requestBody(request),
42
+ resourceType: "CLOUDFRONT",
42
43
  });
43
44
  return decision.action === "BLOCK"
44
45
  ? simWafBlockedHttpResponse(decision.blocked ?? simWafDefaultBlockedResponse())
@@ -58,7 +58,7 @@ export class SimWafAssociations {
58
58
  if (association === undefined) {
59
59
  return undefined;
60
60
  }
61
- return association.webAcl.evaluate(simWafInspectedRequest(request.request, request.body));
61
+ return association.webAcl.evaluate(simWafInspectedRequest(request.request, request.body, association.webAcl.bodyInspectionLimitBytes(association.resourceType)));
62
62
  }
63
63
  /**
64
64
  * Forget whatever is in front of one resource.
@@ -32,6 +32,7 @@ export class SimCfnWafWebAclConfig extends SimCfnWafResourceConfig {
32
32
  Rules: this.rules(),
33
33
  VisibilityConfig: this.value("VisibilityConfig"),
34
34
  CustomResponseBodies: this.value("CustomResponseBodies"),
35
+ AssociationConfig: this.value("AssociationConfig"),
35
36
  };
36
37
  }
37
38
  /**
@@ -17,5 +17,6 @@ export function simWafWebAclOutput(webAcl) {
17
17
  Rules: configuration.rules ?? [],
18
18
  VisibilityConfig: configuration.visibilityConfig,
19
19
  CustomResponseBodies: configuration.customResponseBodies,
20
+ AssociationConfig: configuration.associationConfig,
20
21
  };
21
22
  }
@@ -6,12 +6,6 @@ const refusedMembers = [
6
6
  [(input) => input.CaptchaConfig, "CaptchaConfig", tokenActions],
7
7
  [(input) => input.ChallengeConfig, "ChallengeConfig", tokenActions],
8
8
  [(input) => input.TokenDomains, "TokenDomains", tokenActions],
9
- [
10
- (input) => input.AssociationConfig,
11
- "AssociationConfig",
12
- "it sets the body size a web ACL inspects for the resources it is " +
13
- "associated with, and nothing is associated with a web ACL yet",
14
- ],
15
9
  [
16
10
  (input) => input.DataProtectionConfig,
17
11
  "DataProtectionConfig",
@@ -137,5 +137,6 @@ function configurationOf(input) {
137
137
  customResponseBodies: input.CustomResponseBodies,
138
138
  visibilityConfig: input.VisibilityConfig,
139
139
  description: checkedSimWafDescription(input.Description),
140
+ associationConfig: input.AssociationConfig,
140
141
  };
141
142
  }
@@ -1,5 +1,6 @@
1
1
  import type { SimResponseMetadata } from "../../../aws/metadata/response-metadata.type.js";
2
2
  import type { SimWafActionInput } from "../../web-acl/sim-waf-action.type.js";
3
+ import type { SimWafAssociationConfigInput } from "../../web-acl/sim-waf-association-config.js";
3
4
  import type { SimWafCustomResponseBodies } from "../../web-acl/sim-waf-custom-response.type.js";
4
5
  import type { SimWafRuleInput } from "../../web-acl/sim-waf-rule.type.js";
5
6
  /**
@@ -27,7 +28,7 @@ export interface SimWafWebAclWriteInput {
27
28
  readonly CaptchaConfig?: unknown;
28
29
  readonly ChallengeConfig?: unknown;
29
30
  readonly TokenDomains?: readonly string[] | undefined;
30
- readonly AssociationConfig?: unknown;
31
+ readonly AssociationConfig?: SimWafAssociationConfigInput | undefined;
31
32
  readonly DataProtectionConfig?: unknown;
32
33
  readonly OnSourceDDoSProtectionConfig?: unknown;
33
34
  readonly ApplicationConfig?: unknown;
@@ -72,6 +73,7 @@ export interface SimWafWebAclOutput {
72
73
  readonly Rules: readonly SimWafRuleInput[];
73
74
  readonly VisibilityConfig: unknown;
74
75
  readonly CustomResponseBodies: SimWafCustomResponseBodies | undefined;
76
+ readonly AssociationConfig: SimWafAssociationConfigInput | undefined;
75
77
  }
76
78
  export interface SimGetWebAclCommandOutput {
77
79
  readonly WebACL?: SimWafWebAclOutput | undefined;
@@ -1,3 +1,4 @@
1
+ import type { SimWafBodyInspectionResourceType } from "../web-acl/sim-waf-association-config.js";
1
2
  /**
2
3
  * What a web ACL is asked to decide about.
3
4
  */
@@ -10,4 +11,11 @@ export interface SimWafEvaluationRequest {
10
11
  * stream that cannot be read twice, so it is passed in already buffered.
11
12
  */
12
13
  readonly body?: Uint8Array | undefined;
14
+ /**
15
+ * The type of resource the request reached, when it reached one.
16
+ *
17
+ * Only the body inspection limit reads it, and a web ACL evaluated on its
18
+ * own reads the default limit for every resource type.
19
+ */
20
+ readonly resourceType?: SimWafBodyInspectionResourceType | undefined;
13
21
  }
@@ -22,6 +22,15 @@ export interface SimWafInspectedRequest {
22
22
  readonly host: string;
23
23
  /** The request body, or nothing when the request carried none. */
24
24
  readonly body: Uint8Array | undefined;
25
+ /**
26
+ * How many bytes of the body a rule inspecting it reads.
27
+ *
28
+ * This travels with the request because it belongs to the resource the
29
+ * request reached rather than to the rule. A rule is compiled once, when the
30
+ * web ACL is written, and the same compiled rule then runs in front of a
31
+ * distribution and a REST API stage with a different limit for each.
32
+ */
33
+ readonly bodyInspectionLimitBytes: number;
25
34
  /** The labels the rules that have run so far added to this request. */
26
35
  readonly labels: SimWafRequestLabels;
27
36
  }
@@ -36,5 +45,9 @@ export interface SimWafInspectedRequest {
36
45
  * simulated endpoint is served under `*.sim-aws.localhost`, and a rule reading
37
46
  * the raw Host header would see that suffix on every request that reached
38
47
  * anything at all.
48
+ *
49
+ * The body inspection limit defaults to the 16 KB every resource type this
50
+ * simulation protects reads by default. A web ACL raising it with
51
+ * `AssociationConfig` passes the raised figure in.
39
52
  */
40
- export declare function simWafInspectedRequest(request: Request, body?: Uint8Array): SimWafInspectedRequest;
53
+ export declare function simWafInspectedRequest(request: Request, body?: Uint8Array, bodyInspectionLimitBytes?: number): SimWafInspectedRequest;
@@ -1,4 +1,5 @@
1
1
  import { simAwsRequestHostname } from "../../../serve/http/url/sim-aws-request-hostname.js";
2
+ import { simWafBodyInspectionLimitBytes } from "../web-acl/sim-waf-association-config.js";
2
3
  import { SimWafRequestLabels } from "./sim-waf-request-labels.js";
3
4
  /**
4
5
  * Read the parts of an HTTP request that a web ACL inspects.
@@ -11,8 +12,12 @@ import { SimWafRequestLabels } from "./sim-waf-request-labels.js";
11
12
  * simulated endpoint is served under `*.sim-aws.localhost`, and a rule reading
12
13
  * the raw Host header would see that suffix on every request that reached
13
14
  * anything at all.
15
+ *
16
+ * The body inspection limit defaults to the 16 KB every resource type this
17
+ * simulation protects reads by default. A web ACL raising it with
18
+ * `AssociationConfig` passes the raised figure in.
14
19
  */
15
- export function simWafInspectedRequest(request, body) {
20
+ export function simWafInspectedRequest(request, body, bodyInspectionLimitBytes = simWafBodyInspectionLimitBytes) {
16
21
  const url = new URL(request.url);
17
22
  return {
18
23
  method: request.method,
@@ -24,6 +29,7 @@ export function simWafInspectedRequest(request, body) {
24
29
  headers: request.headers,
25
30
  host: simAwsRequestHostname(request),
26
31
  body,
32
+ bodyInspectionLimitBytes,
27
33
  labels: new SimWafRequestLabels(),
28
34
  };
29
35
  }
@@ -29,7 +29,8 @@ export type { SimWafManagedRuleTier } from "./managed/sim-waf-managed-rule.type.
29
29
  export type { SimWafManagedRuleGroupStatementInput, SimWafOverrideActionInput, SimWafRuleActionOverrideInput, } from "./managed/sim-waf-managed-group.type.js";
30
30
  export { simWafBlockedHttpResponse, type SimWafBlockedResponse, simWafDefaultBlockedResponse, } from "./evaluate/sim-waf-blocked-response.js";
31
31
  export { type SimWafInspectedRequest, simWafInspectedRequest, } from "./evaluate/sim-waf-inspected-request.js";
32
- export { simWafInspectionLimitBytes } from "./statement/sim-waf-field-content.js";
32
+ export { simWafHeaderInspectionLimitBytes } from "./statement/sim-waf-field-content.js";
33
+ export { type SimWafAssociationConfigInput, type SimWafBodyInspectionResourceType, simWafBodyInspectionLimitBytes, } from "./web-acl/sim-waf-association-config.js";
33
34
  export type { SimWafRateBasedStatementInput } from "./statement/sim-waf-rate-based.type.js";
34
35
  export type { SimWafStatementInput } from "./statement/sim-waf-statement.type.js";
35
36
  export { SimWafAssociatedItemException, SimWafDeclarationError, SimWafDuplicateItemException, SimWafError, type SimWafErrorMetadata, SimWafInvalidParameterException, SimWafNonexistentItemException, SimWafOptimisticLockException, SimWafUnavailableEntityException, SimWafUnsimulatedInputException, } from "./error/sim-wafv2.error.js";
@@ -19,5 +19,6 @@ export { SimWafRequestLabels } from "./evaluate/sim-waf-request-labels.js";
19
19
  export { SimWafManagedRules, } from "./managed/sim-waf-managed-rules.js";
20
20
  export { simWafBlockedHttpResponse, simWafDefaultBlockedResponse, } from "./evaluate/sim-waf-blocked-response.js";
21
21
  export { simWafInspectedRequest, } from "./evaluate/sim-waf-inspected-request.js";
22
- export { simWafInspectionLimitBytes } from "./statement/sim-waf-field-content.js";
22
+ export { simWafHeaderInspectionLimitBytes } from "./statement/sim-waf-field-content.js";
23
+ export { simWafBodyInspectionLimitBytes, } from "./web-acl/sim-waf-association-config.js";
23
24
  export { SimWafAssociatedItemException, SimWafDeclarationError, SimWafDuplicateItemException, SimWafError, SimWafInvalidParameterException, SimWafNonexistentItemException, SimWafOptimisticLockException, SimWafUnavailableEntityException, SimWafUnsimulatedInputException, } from "./error/sim-wafv2.error.js";
@@ -1,4 +1,3 @@
1
- import { simWafInspectionLimitBytes } from "../statement/sim-waf-field-content.js";
2
1
  import { simWafQueryArguments } from "../statement/sim-waf-request-fields.js";
3
2
  const encoder = new TextEncoder();
4
3
  const decoder = new TextDecoder();
@@ -22,7 +21,7 @@ export function simWafManagedRequestParts(request) {
22
21
  headerValues: [...request.headers].map(([, value]) => value),
23
22
  userAgent: request.headers.get("user-agent") ?? undefined,
24
23
  cookieHeader,
25
- body: decoder.decode(body.subarray(0, simWafInspectionLimitBytes)),
24
+ body: decoder.decode(body.subarray(0, request.bodyInspectionLimitBytes)),
26
25
  uriPathBytes: simWafByteLength(request.uriPath),
27
26
  queryStringBytes: simWafByteLength(request.queryString),
28
27
  cookieHeaderBytes: simWafByteLength(cookieHeader),
@@ -89,7 +89,8 @@ export class SimWafV2 extends SimWafSets {
89
89
  throw new SimWafNonexistentItemException(`AWS WAF couldn't perform the operation because your resource ` +
90
90
  `doesn't exist: web ACL ${evaluation.webAclArn}.`);
91
91
  }
92
- return webAcl.evaluate(simWafInspectedRequest(evaluation.request, evaluation.body));
92
+ const limitBytes = webAcl.bodyInspectionLimitBytes(evaluation.resourceType);
93
+ return webAcl.evaluate(simWafInspectedRequest(evaluation.request, evaluation.body, limitBytes));
93
94
  }
94
95
  /**
95
96
  * What the AWS managed rule groups do here, and what a test declares of
@@ -15,13 +15,13 @@ export type SimWafFieldContent = {
15
15
  readonly outcome: "noMatch";
16
16
  };
17
17
  /**
18
- * How much of a request body, header set or cookie set WAF reads.
18
+ * How much of a header set or a cookie set WAF reads.
19
19
  *
20
- * Real WAF stops at 8 KB for a web ACL as it is created here. A CloudFront
21
- * association can raise the body limit, which is settled where associations
22
- * are, so this is the one figure until then.
20
+ * Real WAF stops at 8 KB and 200 entries for both, whatever the web ACL is in
21
+ * front of. A body is the component whose limit varies by resource type, and
22
+ * `simWafBodyInspectionLimitBytes` carries that one.
23
23
  */
24
- export declare const simWafInspectionLimitBytes = 8192;
24
+ export declare const simWafHeaderInspectionLimitBytes = 8192;
25
25
  /**
26
26
  * What a rule does about content too large for WAF to read.
27
27
  */
@@ -37,5 +37,8 @@ export declare function requiredSimWafOversizeHandling(handling: string | undefi
37
37
  * settle the statement without looking, and `CONTINUE` inspects as much as WAF
38
38
  * would have read: whole entries while they fit, and the first entry cut to
39
39
  * the limit when even one does not.
40
+ *
41
+ * The limit is passed in because a body's varies with the resource type the
42
+ * request reached, while a header set and a cookie set are always 8 KB.
40
43
  */
41
- export declare function simWafFieldContent(candidates: readonly string[], oversizeHandling: SimWafOversizeHandling): SimWafFieldContent;
44
+ export declare function simWafFieldContent(candidates: readonly string[], oversizeHandling: SimWafOversizeHandling, limitBytes: number): SimWafFieldContent;
@@ -1,12 +1,12 @@
1
1
  import { invalidSimWafRule } from "./sim-waf-rule-refusals.js";
2
2
  /**
3
- * How much of a request body, header set or cookie set WAF reads.
3
+ * How much of a header set or a cookie set WAF reads.
4
4
  *
5
- * Real WAF stops at 8 KB for a web ACL as it is created here. A CloudFront
6
- * association can raise the body limit, which is settled where associations
7
- * are, so this is the one figure until then.
5
+ * Real WAF stops at 8 KB and 200 entries for both, whatever the web ACL is in
6
+ * front of. A body is the component whose limit varies by resource type, and
7
+ * `simWafBodyInspectionLimitBytes` carries that one.
8
8
  */
9
- export const simWafInspectionLimitBytes = 8192;
9
+ export const simWafHeaderInspectionLimitBytes = 8192;
10
10
  const encoder = new TextEncoder();
11
11
  const decoder = new TextDecoder();
12
12
  /**
@@ -26,24 +26,30 @@ export function requiredSimWafOversizeHandling(handling, ruleName) {
26
26
  * settle the statement without looking, and `CONTINUE` inspects as much as WAF
27
27
  * would have read: whole entries while they fit, and the first entry cut to
28
28
  * the limit when even one does not.
29
+ *
30
+ * The limit is passed in because a body's varies with the resource type the
31
+ * request reached, while a header set and a cookie set are always 8 KB.
29
32
  */
30
- export function simWafFieldContent(candidates, oversizeHandling) {
33
+ export function simWafFieldContent(candidates, oversizeHandling, limitBytes) {
31
34
  const encoded = candidates.map((candidate) => encoder.encode(candidate));
32
35
  const total = encoded.reduce((sum, bytes) => sum + bytes.length, 0);
33
- if (total <= simWafInspectionLimitBytes) {
36
+ if (total <= limitBytes) {
34
37
  return { outcome: "inspect", candidates };
35
38
  }
36
39
  if (oversizeHandling !== "CONTINUE") {
37
40
  return { outcome: oversizeHandling === "MATCH" ? "match" : "noMatch" };
38
41
  }
39
- return { outcome: "inspect", candidates: readWithinLimit(encoded) };
42
+ return {
43
+ outcome: "inspect",
44
+ candidates: readWithinLimit(encoded, limitBytes),
45
+ };
40
46
  }
41
47
  /**
42
48
  * The content WAF would have read before it stopped.
43
49
  */
44
- function readWithinLimit(encoded) {
50
+ function readWithinLimit(encoded, limitBytes) {
45
51
  const read = [];
46
- let budget = simWafInspectionLimitBytes;
52
+ let budget = limitBytes;
47
53
  for (const bytes of encoded) {
48
54
  if (budget === 0) {
49
55
  break;
@@ -1,4 +1,4 @@
1
- import { requiredSimWafOversizeHandling, simWafFieldContent, } from "./sim-waf-field-content.js";
1
+ import { requiredSimWafOversizeHandling, simWafFieldContent, simWafHeaderInspectionLimitBytes, } from "./sim-waf-field-content.js";
2
2
  import { requiredSimWafPatternSelection } from "./sim-waf-match-pattern.js";
3
3
  import { requiredSimWafMatchScope, simWafCookies, simWafHeaderEntries, simWafPatternCandidates, } from "./sim-waf-request-fields.js";
4
4
  import { invalidSimWafRule } from "./sim-waf-rule-refusals.js";
@@ -22,7 +22,7 @@ export function compileSimWafSetField(field, ruleName) {
22
22
  invalidSimWafRule(ruleName, "FieldToMatch names no field to match on");
23
23
  }
24
24
  const oversize = requiredSimWafOversizeHandling(field.Body.OversizeHandling, ruleName);
25
- return (request) => simWafFieldContent(request.body === undefined ? [] : [decoder.decode(request.body)], oversize);
25
+ return (request) => simWafFieldContent(request.body === undefined ? [] : [decoder.decode(request.body)], oversize, request.bodyInspectionLimitBytes);
26
26
  }
27
27
  function entriesReader(input, ruleName, entries) {
28
28
  const matchScope = requiredSimWafMatchScope(input.MatchScope, ruleName);
@@ -32,5 +32,5 @@ function entriesReader(input, ruleName, entries) {
32
32
  entries: entries(request),
33
33
  selection,
34
34
  matchScope,
35
- }), oversize);
35
+ }), oversize, simWafHeaderInspectionLimitBytes);
36
36
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * A resource type whose body inspection limit a web ACL can set.
3
+ *
4
+ * Real WAF keys `AssociationConfig.RequestBody` by resource type, and these
5
+ * three are the ones a web ACL goes in front of here. `APP_RUNNER_SERVICE` and
6
+ * `VERIFIED_ACCESS_INSTANCE` are keys AWS takes for resources this simulation
7
+ * has no association for.
8
+ */
9
+ export type SimWafBodyInspectionResourceType = "CLOUDFRONT" | "API_GATEWAY" | "COGNITO_USER_POOL";
10
+ /**
11
+ * How much of a request body WAF reads for a resource type given no
12
+ * `AssociationConfig`.
13
+ *
14
+ * CloudFront, API Gateway and Cognito all default to 16 KB. A load balancer
15
+ * and an AppSync API are fixed at 8 KB, and a web ACL cannot be put in front
16
+ * of either one here.
17
+ */
18
+ export declare const simWafBodyInspectionLimitBytes = 16384;
19
+ /**
20
+ * One resource type's entry under `AssociationConfig.RequestBody`.
21
+ */
22
+ export interface SimWafRequestBodyConfigInput {
23
+ readonly DefaultSizeInspectionLimit?: string | undefined;
24
+ }
25
+ /**
26
+ * The `AssociationConfig` a web ACL is written with.
27
+ */
28
+ export interface SimWafAssociationConfigInput {
29
+ readonly RequestBody?: Readonly<Record<string, SimWafRequestBodyConfigInput | undefined>> | undefined;
30
+ }
31
+ /**
32
+ * How much of a request body a web ACL's rules read, by resource type.
33
+ *
34
+ * A web ACL holds one of these whether or not it was written with an
35
+ * `AssociationConfig`, and a resource type the config left out reads the
36
+ * default 16 KB.
37
+ */
38
+ export declare class SimWafBodyInspectionLimits {
39
+ private readonly limits;
40
+ private constructor();
41
+ /**
42
+ * Read the limits an `AssociationConfig` sets, refusing anything WAF would
43
+ * refuse and anything this simulation cannot apply.
44
+ */
45
+ static read(input: SimWafAssociationConfigInput | undefined): SimWafBodyInspectionLimits;
46
+ /**
47
+ * How many bytes of a body a request reaching one resource type is inspected
48
+ * for.
49
+ *
50
+ * A request evaluated against a web ACL that no resource holds names no
51
+ * resource type, and reads the default.
52
+ */
53
+ bytesFor(resourceType: SimWafBodyInspectionResourceType | undefined): number;
54
+ }
@@ -0,0 +1,92 @@
1
+ import { SimWafInvalidParameterException, SimWafUnsimulatedInputException, } from "../error/sim-wafv2.error.js";
2
+ /**
3
+ * How much of a request body WAF reads for a resource type given no
4
+ * `AssociationConfig`.
5
+ *
6
+ * CloudFront, API Gateway and Cognito all default to 16 KB. A load balancer
7
+ * and an AppSync API are fixed at 8 KB, and a web ACL cannot be put in front
8
+ * of either one here.
9
+ */
10
+ export const simWafBodyInspectionLimitBytes = 16_384;
11
+ /**
12
+ * The four sizes `DefaultSizeInspectionLimit` names, in bytes.
13
+ */
14
+ const inspectionLimits = new Map([
15
+ ["KB_16", 16_384],
16
+ ["KB_32", 32_768],
17
+ ["KB_48", 49_152],
18
+ ["KB_64", 65_536],
19
+ ]);
20
+ const simulatedResourceTypes = [
21
+ "CLOUDFRONT",
22
+ "API_GATEWAY",
23
+ "COGNITO_USER_POOL",
24
+ ];
25
+ /**
26
+ * How much of a request body a web ACL's rules read, by resource type.
27
+ *
28
+ * A web ACL holds one of these whether or not it was written with an
29
+ * `AssociationConfig`, and a resource type the config left out reads the
30
+ * default 16 KB.
31
+ */
32
+ export class SimWafBodyInspectionLimits {
33
+ limits;
34
+ constructor(limits) {
35
+ this.limits = limits;
36
+ }
37
+ /**
38
+ * Read the limits an `AssociationConfig` sets, refusing anything WAF would
39
+ * refuse and anything this simulation cannot apply.
40
+ */
41
+ static read(input) {
42
+ const configured = Object.entries(input?.RequestBody ?? {});
43
+ const limits = new Map();
44
+ for (const [resourceType, config] of configured) {
45
+ limits.set(simulatedResourceType(resourceType), inspectionLimit(resourceType, config));
46
+ }
47
+ return new SimWafBodyInspectionLimits(limits);
48
+ }
49
+ /**
50
+ * How many bytes of a body a request reaching one resource type is inspected
51
+ * for.
52
+ *
53
+ * A request evaluated against a web ACL that no resource holds names no
54
+ * resource type, and reads the default.
55
+ */
56
+ bytesFor(resourceType) {
57
+ if (resourceType === undefined) {
58
+ return simWafBodyInspectionLimitBytes;
59
+ }
60
+ return this.limits.get(resourceType) ?? simWafBodyInspectionLimitBytes;
61
+ }
62
+ }
63
+ /**
64
+ * Hold a `RequestBody` key to the resource types this simulation associates.
65
+ */
66
+ function simulatedResourceType(resourceType) {
67
+ const simulated = simulatedResourceTypes.find((candidate) => candidate === resourceType);
68
+ if (simulated === undefined) {
69
+ throw new SimWafUnsimulatedInputException(`AssociationConfig sets the body inspection limit for ${resourceType} ` +
70
+ `resources, and ${simulatedResourceTypes.join(" and ")} are the ` +
71
+ `types a web ACL goes in front of in Yulin`);
72
+ }
73
+ return simulated;
74
+ }
75
+ /**
76
+ * Read one resource type's `DefaultSizeInspectionLimit`.
77
+ *
78
+ * An entry carrying no size is refused the same way one carrying a size WAF
79
+ * has no setting for is. A template writes this part of a web ACL by hand, and
80
+ * an entry that says nothing about the limit it is there to set is a mistake
81
+ * worth reporting as one.
82
+ */
83
+ function inspectionLimit(resourceType, config) {
84
+ const limit = config?.DefaultSizeInspectionLimit;
85
+ const bytes = limit === undefined ? undefined : inspectionLimits.get(limit);
86
+ if (bytes === undefined) {
87
+ throw new SimWafInvalidParameterException(`Error reason: The DefaultSizeInspectionLimit ${String(limit)} is one ` +
88
+ `of ${inspectionLimits.keys().toArray().join(", ")}, field: ` +
89
+ `ASSOCIATION_CONFIG, parameter: ${resourceType}`);
90
+ }
91
+ return bytes;
92
+ }
@@ -1,4 +1,5 @@
1
1
  import { SimWafAction } from "./sim-waf-action.js";
2
+ import type { SimWafAssociationConfigInput } from "./sim-waf-association-config.js";
2
3
  import type { SimWafActionInput } from "./sim-waf-action.type.js";
3
4
  import type { SimWafCustomResponseBodies } from "./sim-waf-custom-response.type.js";
4
5
  import type { SimWafRuleInput } from "./sim-waf-rule.type.js";
@@ -11,6 +12,7 @@ export interface SimWafWebAclConfiguration {
11
12
  readonly customResponseBodies?: SimWafCustomResponseBodies | undefined;
12
13
  readonly visibilityConfig?: unknown;
13
14
  readonly description?: string | undefined;
15
+ readonly associationConfig?: SimWafAssociationConfigInput | undefined;
14
16
  }
15
17
  /**
16
18
  * Read the action a request no rule claims is given.
@@ -1,6 +1,7 @@
1
1
  import { type SimWafDecision } from "../evaluate/sim-waf-decision.js";
2
2
  import type { SimWafInspectedRequest } from "../evaluate/sim-waf-inspected-request.js";
3
3
  import { SimWafResource, type SimWafResourceProperties } from "../resource/sim-waf-resource.js";
4
+ import { type SimWafBodyInspectionResourceType } from "./sim-waf-association-config.js";
4
5
  import type { SimWafWebAclRuleScope } from "./sim-waf-rule.type.js";
5
6
  import { type SimWafWebAclConfiguration } from "./sim-waf-web-acl-configuration.js";
6
7
  interface SimWafWebAclProperties extends SimWafResourceProperties, SimWafWebAclRuleScope {
@@ -43,6 +44,14 @@ export declare class SimWafWebAcl extends SimWafResource {
43
44
  * refuses an update keeps the rules it had rather than being left with none.
44
45
  */
45
46
  reconfigure(configuration: SimWafWebAclConfiguration, lockToken: string | undefined): void;
47
+ /**
48
+ * How many bytes of a request body this web ACL reads in front of one
49
+ * resource type.
50
+ *
51
+ * `AssociationConfig` raises it per resource type, and a web ACL written
52
+ * without one reads the 16 KB default everything it protects has.
53
+ */
54
+ bodyInspectionLimitBytes(resourceType: SimWafBodyInspectionResourceType | undefined): number;
46
55
  /**
47
56
  * Decide what happens to one request.
48
57
  */
@@ -1,6 +1,7 @@
1
1
  import { simWafDecision, } from "../evaluate/sim-waf-decision.js";
2
2
  import { simWafEvaluateRules } from "../evaluate/sim-waf-evaluate-rules.js";
3
3
  import { SimWafResource, } from "../resource/sim-waf-resource.js";
4
+ import { SimWafBodyInspectionLimits, } from "./sim-waf-association-config.js";
4
5
  import { compileSimWafWebAclRules } from "./sim-waf-rules.js";
5
6
  import { simWafWebAclCapacity } from "./sim-waf-web-acl-capacity.js";
6
7
  import { readSimWafDefaultAction, } from "./sim-waf-web-acl-configuration.js";
@@ -29,6 +30,7 @@ export class SimWafWebAcl extends SimWafResource {
29
30
  #defaultAction;
30
31
  #rules;
31
32
  #capacity;
33
+ #bodyInspectionLimits;
32
34
  constructor(properties) {
33
35
  super("webacl", properties);
34
36
  this.#scope = properties;
@@ -36,6 +38,7 @@ export class SimWafWebAcl extends SimWafResource {
36
38
  this.#defaultAction = readSimWafDefaultAction(properties.configuration);
37
39
  this.#rules = compileSimWafWebAclRules(properties.configuration, this.#scope);
38
40
  this.#capacity = simWafWebAclCapacity(properties.configuration.rules);
41
+ this.#bodyInspectionLimits = SimWafBodyInspectionLimits.read(properties.configuration.associationConfig);
39
42
  this.labelNamespace =
40
43
  `awswaf:${properties.accountRegionScope.accountId}:webacl:` +
41
44
  `${properties.name}:`;
@@ -61,12 +64,24 @@ export class SimWafWebAcl extends SimWafResource {
61
64
  reconfigure(configuration, lockToken) {
62
65
  const defaultAction = readSimWafDefaultAction(configuration);
63
66
  const rules = compileSimWafWebAclRules(configuration, this.#scope);
67
+ const bodyInspectionLimits = SimWafBodyInspectionLimits.read(configuration.associationConfig);
64
68
  this.takeLock(lockToken);
65
69
  this.replaceDescription(configuration.description);
66
70
  this.#configuration = configuration;
67
71
  this.#defaultAction = defaultAction;
68
72
  this.#rules = rules;
69
73
  this.#capacity = simWafWebAclCapacity(configuration.rules);
74
+ this.#bodyInspectionLimits = bodyInspectionLimits;
75
+ }
76
+ /**
77
+ * How many bytes of a request body this web ACL reads in front of one
78
+ * resource type.
79
+ *
80
+ * `AssociationConfig` raises it per resource type, and a web ACL written
81
+ * without one reads the 16 KB default everything it protects has.
82
+ */
83
+ bodyInspectionLimitBytes(resourceType) {
84
+ return this.#bodyInspectionLimits.bytesFor(resourceType);
70
85
  }
71
86
  /**
72
87
  * Decide what happens to one request.
@@ -173,9 +173,22 @@ resource, and `CreateWebACL` here refuses it too.
173
173
  Matching is case sensitive, as it is on AWS. A rule that means to ignore case says so with a
174
174
  `LOWERCASE` transformation and a lower case search string.
175
175
 
176
- WAF stops reading a body, a header set or a cookie set at 8 KB. The rule's `OversizeHandling` says
177
- what content past that point counts as. `MATCH` and `NO_MATCH` settle the statement without looking,
178
- and `CONTINUE` inspects as much as WAF would have read.
176
+ WAF stops reading a header set or a cookie set at 8 KB. A body runs to 16 KB, the figure
177
+ CloudFront, API Gateway and Cognito all send for inspection, and a web ACL raises it to 32, 48 or 64
178
+ KB with `AssociationConfig`:
179
+
180
+ ```typescript
181
+ AssociationConfig: {
182
+ RequestBody: {
183
+ CLOUDFRONT: { DefaultSizeInspectionLimit: "KB_64" },
184
+ },
185
+ },
186
+ ```
187
+
188
+ The key is the resource type the raised limit applies to, and `CLOUDFRONT`, `API_GATEWAY` and
189
+ `COGNITO_USER_POOL` are the three a web ACL goes in front of here. The rule's `OversizeHandling`
190
+ says what content past the limit counts as. `MATCH` and `NO_MATCH` settle the statement without
191
+ looking, and `CONTINUE` inspects as much as WAF would have read.
179
192
 
180
193
  ## Rate limiting
181
194
 
@@ -1363,8 +1376,9 @@ fields to match. The `Captcha` and `Challenge` actions are refused, along with t
1363
1376
  `ChallengeConfig` and `TokenDomains` that configure them, because a browser has to answer them.
1364
1377
 
1365
1378
  Tags, logging, sampled requests and CloudWatch metrics for a web ACL are not simulated.
1366
- `AssociationConfig`, `DataProtectionConfig`, `OnSourceDDoSProtectionConfig` and `ApplicationConfig`
1367
- are refused for the same reason, each naming what it would have configured.
1379
+ `DataProtectionConfig`, `OnSourceDDoSProtectionConfig` and `ApplicationConfig` are refused for the
1380
+ same reason, each naming what it would have configured. An `AssociationConfig` naming a resource
1381
+ type this simulation has no association for is refused too.
1368
1382
 
1369
1383
  ## Supported operations
1370
1384
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/yulin",
3
- "version": "1.21.11",
3
+ "version": "1.21.12",
4
4
  "description": "AWS system behaviour simulation for isolated unit testing",
5
5
  "repository": "https://github.com/KensioSoftware/yulin",
6
6
  "homepage": "https://yulinsim.dev/",