@kensio/yulin 1.21.10 → 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.
- package/dist/serve/payload-2/sim-payload-2-endpoint.d.ts +9 -0
- package/dist/serve/payload-2/sim-payload-2-request-context.js +1 -1
- package/dist/service/apigatewayv2/api/sim-http-api-lambda-proxy.factory.d.ts +6 -0
- package/dist/service/apigatewayv2/api/sim-http-api-lambda-proxy.factory.js +2 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-format.d.ts +8 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-format.js +36 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-request.d.ts +53 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-request.js +1 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.d.ts +26 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.js +44 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.type.d.ts +21 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.type.js +1 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-stream-name.d.ts +13 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-stream-name.js +23 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-variables.d.ts +17 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-variables.js +86 -0
- package/dist/service/apigatewayv2/api/stage/sim-http-api-stage.d.ts +9 -0
- package/dist/service/apigatewayv2/api/stage/sim-http-api-stage.js +9 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-access-log-settings-properties.d.ts +24 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-access-log-settings-properties.js +30 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-stage-properties.d.ts +1 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-stage-properties.js +10 -4
- package/dist/service/apigatewayv2/command/stage/sim-http-api-access-log-settings-input.d.ts +15 -0
- package/dist/service/apigatewayv2/command/stage/sim-http-api-access-log-settings-input.js +33 -0
- package/dist/service/apigatewayv2/command/stage/sim-http-api-stage-commands.js +4 -0
- package/dist/service/apigatewayv2/command/stage/stage.command.d.ts +2 -0
- package/dist/service/apigatewayv2/serve/auth/sim-http-api-route-authorize-input.d.ts +6 -0
- package/dist/service/apigatewayv2/serve/sim-api-gateway-v2-controller.d.ts +13 -15
- package/dist/service/apigatewayv2/serve/sim-api-gateway-v2-controller.js +26 -60
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log-record.d.ts +31 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log-record.js +88 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log.d.ts +43 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log.js +72 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-endpoint.js +1 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-input.d.ts +22 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-input.js +1 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-invocation.d.ts +5 -22
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-invocation.js +17 -20
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-outcome.d.ts +27 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-outcome.js +13 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-may-invoke.d.ts +19 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-may-invoke.js +19 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serve-pipeline.d.ts +27 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serve-pipeline.js +75 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-served.d.ts +22 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-served.js +1 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serving.d.ts +12 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serving.js +1 -0
- package/dist/service/cloudfront/controller/web-acl/sim-cf-web-acl-guard.js +1 -0
- package/dist/service/logs/group/sim-logs-arn.d.ts +15 -0
- package/dist/service/logs/group/sim-logs-arn.js +33 -0
- package/dist/service/wafv2/association/sim-waf-associations.js +1 -1
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.js +1 -0
- package/dist/service/wafv2/command/web-acl/sim-waf-web-acl-output.js +1 -0
- package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.js +0 -6
- package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.js +1 -0
- package/dist/service/wafv2/command/web-acl/web-acl.command.d.ts +3 -1
- package/dist/service/wafv2/evaluate/sim-waf-evaluation-request.d.ts +8 -0
- package/dist/service/wafv2/evaluate/sim-waf-inspected-request.d.ts +14 -1
- package/dist/service/wafv2/evaluate/sim-waf-inspected-request.js +7 -1
- package/dist/service/wafv2/index.d.ts +2 -1
- package/dist/service/wafv2/index.js +2 -1
- package/dist/service/wafv2/managed/sim-waf-managed-request.js +1 -2
- package/dist/service/wafv2/sim-wafv2.js +2 -1
- package/dist/service/wafv2/statement/sim-waf-field-content.d.ts +9 -6
- package/dist/service/wafv2/statement/sim-waf-field-content.js +16 -10
- package/dist/service/wafv2/statement/sim-waf-set-field.js +3 -3
- package/dist/service/wafv2/web-acl/sim-waf-association-config.d.ts +54 -0
- package/dist/service/wafv2/web-acl/sim-waf-association-config.js +92 -0
- package/dist/service/wafv2/web-acl/sim-waf-web-acl-configuration.d.ts +2 -0
- package/dist/service/wafv2/web-acl/sim-waf-web-acl.d.ts +9 -0
- package/dist/service/wafv2/web-acl/sim-waf-web-acl.js +15 -0
- package/docs/services/apigatewayv2/README.md +162 -6
- package/docs/services/wafv2/README.md +19 -5
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SimHttpApiMatch } from "../api/sim-http-api-match.js";
|
|
2
|
+
import type { SimHttpApi } from "../api/sim-http-api.js";
|
|
3
|
+
import type { SimHttpApiFunctionTarget } from "./sim-http-api-function-target.js";
|
|
4
|
+
interface SimHttpApiMayInvokeInput {
|
|
5
|
+
readonly api: SimHttpApi;
|
|
6
|
+
readonly match: SimHttpApiMatch;
|
|
7
|
+
readonly request: Request;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Whether the API lacks permission to invoke a function behind one of its
|
|
11
|
+
* routes.
|
|
12
|
+
*
|
|
13
|
+
* The route the request matched is supplied as the source ARN, so a permission
|
|
14
|
+
* granted for one route does not open another. This is the API's own question
|
|
15
|
+
* rather than the client's, whose was already answered by the route's
|
|
16
|
+
* authorization.
|
|
17
|
+
*/
|
|
18
|
+
export declare function simHttpApiMayNotInvoke(input: SimHttpApiMayInvokeInput, target: SimHttpApiFunctionTarget): boolean;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SimHttpApiExecuteApiArn } from "../api/sim-http-api-execute-api-arn.js";
|
|
2
|
+
import { SimHttpApiInvokeAuthorizer } from "./auth/sim-http-api-invoke-authorizer.js";
|
|
3
|
+
/**
|
|
4
|
+
* Whether the API lacks permission to invoke a function behind one of its
|
|
5
|
+
* routes.
|
|
6
|
+
*
|
|
7
|
+
* The route the request matched is supplied as the source ARN, so a permission
|
|
8
|
+
* granted for one route does not open another. This is the API's own question
|
|
9
|
+
* rather than the client's, whose was already answered by the route's
|
|
10
|
+
* authorization.
|
|
11
|
+
*/
|
|
12
|
+
export function simHttpApiMayNotInvoke(input, target) {
|
|
13
|
+
const { api, match, request } = input;
|
|
14
|
+
return new SimHttpApiInvokeAuthorizer({ iam: target.iam }).authorize({
|
|
15
|
+
api,
|
|
16
|
+
target,
|
|
17
|
+
sourceArn: SimHttpApiExecuteApiArn.forMatchedRoute(api, match, request.method),
|
|
18
|
+
}).isDenied;
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SimAwsServiceRequest } from "../../../serve/controller/sim-service-controller.js";
|
|
2
|
+
import type { SimApiGatewayV2Router } from "./sim-api-gateway-v2-router.js";
|
|
3
|
+
import type { SimHttpApiServed, SimHttpApiServedRequest } from "./sim-http-api-served.js";
|
|
4
|
+
interface SimHttpApiServePipelineProperties {
|
|
5
|
+
readonly router: SimApiGatewayV2Router;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Takes one request the resolver matched to a stage through the three things
|
|
9
|
+
* that stand between it and a response.
|
|
10
|
+
*
|
|
11
|
+
* The stage's throttle is asked first. A flood of requests to a throttled
|
|
12
|
+
* route invokes neither the authorizer nor the integration, and AWS publishes
|
|
13
|
+
* no order between the two. The client's own authorization comes next, so a
|
|
14
|
+
* request with no credentials is refused whether or not the integration
|
|
15
|
+
* behind the route would work. What each step decided is carried out with the
|
|
16
|
+
* response, because the stage's access log describes the request afterwards
|
|
17
|
+
* and a refused request is the case that log exists for.
|
|
18
|
+
*/
|
|
19
|
+
export declare class SimHttpApiServePipeline {
|
|
20
|
+
#private;
|
|
21
|
+
constructor(properties: SimHttpApiServePipelineProperties);
|
|
22
|
+
/**
|
|
23
|
+
* Serve one request, and report what each step of serving it decided.
|
|
24
|
+
*/
|
|
25
|
+
run(serving: SimHttpApiServedRequest, serviceRequest: SimAwsServiceRequest): Promise<SimHttpApiServed>;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { SimHttpApiRouteAuthorizer } from "./auth/sim-http-api-route-authorizer.js";
|
|
2
|
+
import { SimApiGatewayV2ErrorResponse } from "./sim-api-gateway-v2-error-response.js";
|
|
3
|
+
import { SimHttpApiIntegrationInvocation } from "./sim-http-api-integration-invocation.js";
|
|
4
|
+
import { SimHttpApiRefusalResponse } from "./sim-http-api-refusal-response.js";
|
|
5
|
+
/**
|
|
6
|
+
* Takes one request the resolver matched to a stage through the three things
|
|
7
|
+
* that stand between it and a response.
|
|
8
|
+
*
|
|
9
|
+
* The stage's throttle is asked first. A flood of requests to a throttled
|
|
10
|
+
* route invokes neither the authorizer nor the integration, and AWS publishes
|
|
11
|
+
* no order between the two. The client's own authorization comes next, so a
|
|
12
|
+
* request with no credentials is refused whether or not the integration
|
|
13
|
+
* behind the route would work. What each step decided is carried out with the
|
|
14
|
+
* response, because the stage's access log describes the request afterwards
|
|
15
|
+
* and a refused request is the case that log exists for.
|
|
16
|
+
*/
|
|
17
|
+
export class SimHttpApiServePipeline {
|
|
18
|
+
#router;
|
|
19
|
+
#routeAuthorizer;
|
|
20
|
+
#integration;
|
|
21
|
+
#errorResponse = new SimApiGatewayV2ErrorResponse();
|
|
22
|
+
#refusalResponse = new SimHttpApiRefusalResponse();
|
|
23
|
+
constructor(properties) {
|
|
24
|
+
this.#router = properties.router;
|
|
25
|
+
// The clock is the router's, so the event timestamps and the token expiry
|
|
26
|
+
// checks belong to the same simulation.
|
|
27
|
+
this.#routeAuthorizer = new SimHttpApiRouteAuthorizer({
|
|
28
|
+
clock: properties.router.simAws,
|
|
29
|
+
functions: properties.router,
|
|
30
|
+
});
|
|
31
|
+
this.#integration = new SimHttpApiIntegrationInvocation({
|
|
32
|
+
router: properties.router,
|
|
33
|
+
clock: properties.router.simAws,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Serve one request, and report what each step of serving it decided.
|
|
38
|
+
*/
|
|
39
|
+
async run(serving, serviceRequest) {
|
|
40
|
+
const { request } = serviceRequest;
|
|
41
|
+
const { api, match, domainName, rawPath, requestId } = serving;
|
|
42
|
+
// What the authorizer's event and the integration's event both describe.
|
|
43
|
+
const asked = { api, match, request, domainName, rawPath, requestId };
|
|
44
|
+
// The throttle takes a token from the route's bucket, and a route whose
|
|
45
|
+
// bucket is empty is answered here. Neither the authorizer nor the
|
|
46
|
+
// integration runs for it, and the stage's access log is the only place
|
|
47
|
+
// the refusal is recorded.
|
|
48
|
+
if (!match.stage.admits(match.route.routeKey)) {
|
|
49
|
+
return { response: this.#errorResponse.tooManyRequests() };
|
|
50
|
+
}
|
|
51
|
+
const authorization = await this.#routeAuthorizer.authorize({
|
|
52
|
+
...asked,
|
|
53
|
+
caller: serviceRequest.caller,
|
|
54
|
+
iam: this.#router.iamFor(api),
|
|
55
|
+
});
|
|
56
|
+
// A refusal is carried out alongside its response, because the access log
|
|
57
|
+
// line reports what the authorizer said. An unmet route scope, an
|
|
58
|
+
// `AWS_IAM` route IAM did not allow, and a Lambda authorizer that said no
|
|
59
|
+
// all arrive here.
|
|
60
|
+
if (!authorization.admitted) {
|
|
61
|
+
return {
|
|
62
|
+
response: this.#refusalResponse.build(authorization),
|
|
63
|
+
authorization,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const clock = this.#router.simAws;
|
|
67
|
+
const invokedAt = clock.now().getTime();
|
|
68
|
+
const outcome = await this.#integration.invoke({ ...asked, authorization });
|
|
69
|
+
const integration = {
|
|
70
|
+
...outcome,
|
|
71
|
+
integrationLatency: clock.now().getTime() - invokedAt,
|
|
72
|
+
};
|
|
73
|
+
return { response: integration.response, authorization, integration };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SimHttpApiAuthorization } from "../api/authorizer/sim-http-api-authorization.js";
|
|
2
|
+
import type { SimHttpApiIntegrationOutcome } from "./sim-http-api-integration-outcome.js";
|
|
3
|
+
import type { SimHttpApiServing } from "./sim-http-api-serving.js";
|
|
4
|
+
/**
|
|
5
|
+
* What one request through the endpoint produced, gathered as it happened so
|
|
6
|
+
* that the stage's access log can describe it afterwards.
|
|
7
|
+
*
|
|
8
|
+
* A request the stage's throttle refused has neither an authorization nor an
|
|
9
|
+
* integration, and one an authorizer refused has an authorization alone.
|
|
10
|
+
*/
|
|
11
|
+
export interface SimHttpApiServed {
|
|
12
|
+
readonly response: Response;
|
|
13
|
+
readonly authorization?: SimHttpApiAuthorization | undefined;
|
|
14
|
+
readonly integration?: SimHttpApiIntegrationOutcome | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A serving the controller has stamped with the id this request is logged and
|
|
18
|
+
* reported under, which every path below it then names.
|
|
19
|
+
*/
|
|
20
|
+
export interface SimHttpApiServedRequest extends SimHttpApiServing {
|
|
21
|
+
readonly requestId: string;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -21,6 +21,18 @@ export interface SimHttpApiServing {
|
|
|
21
21
|
* carrying.
|
|
22
22
|
*/
|
|
23
23
|
readonly rawPath: string;
|
|
24
|
+
/**
|
|
25
|
+
* The id this request is logged and reported under, settled by the
|
|
26
|
+
* controller before anything runs. The resolver leaves it out, and the
|
|
27
|
+
* controller adds it to the serving it passes on.
|
|
28
|
+
*/
|
|
29
|
+
readonly requestId?: string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The API mapping base path this request matched, for a request that
|
|
32
|
+
* reached a custom domain. It is the empty string for a mapping serving the
|
|
33
|
+
* root of its domain, and absent for the generated endpoint.
|
|
34
|
+
*/
|
|
35
|
+
readonly basePathMatched?: string | undefined;
|
|
24
36
|
}
|
|
25
37
|
/**
|
|
26
38
|
* What an HTTP API endpoint decided about one request before any of it ran.
|
|
@@ -33,3 +33,18 @@ export declare function simLogsAnyLogGroupArn(scope: SimAwsAccountRegionScope):
|
|
|
33
33
|
* The ARN of a log stream inside a log group.
|
|
34
34
|
*/
|
|
35
35
|
export declare function simLogsLogStreamArn(scope: SimAwsAccountRegionScope, logGroupName: string, logStreamName: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* The account, region and group name a log group ARN carries, or undefined
|
|
38
|
+
* for a string that is not one.
|
|
39
|
+
*
|
|
40
|
+
* Both forms are read. `DescribeLogGroups` reports `logGroupArn` without a
|
|
41
|
+
* trailing wildcard, while the `arn` field and CDK's `logGroup.logGroupArn`
|
|
42
|
+
* both end in `:*`, and a template naming either means the same group. A log
|
|
43
|
+
* group name cannot contain a colon, so what follows `log-group:` is the name
|
|
44
|
+
* up to an optional trailing `:*`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function simLogsParsedLogGroupArn(arn: string): {
|
|
47
|
+
readonly accountId: string;
|
|
48
|
+
readonly regionName: string;
|
|
49
|
+
readonly logGroupName: string;
|
|
50
|
+
} | undefined;
|
|
@@ -42,3 +42,36 @@ export function simLogsAnyLogGroupArn(scope) {
|
|
|
42
42
|
export function simLogsLogStreamArn(scope, logGroupName, logStreamName) {
|
|
43
43
|
return `${simLogsLogGroupArn(scope, logGroupName)}:log-stream:${logStreamName}`;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The account, region and group name a log group ARN carries, or undefined
|
|
47
|
+
* for a string that is not one.
|
|
48
|
+
*
|
|
49
|
+
* Both forms are read. `DescribeLogGroups` reports `logGroupArn` without a
|
|
50
|
+
* trailing wildcard, while the `arn` field and CDK's `logGroup.logGroupArn`
|
|
51
|
+
* both end in `:*`, and a template naming either means the same group. A log
|
|
52
|
+
* group name cannot contain a colon, so what follows `log-group:` is the name
|
|
53
|
+
* up to an optional trailing `:*`.
|
|
54
|
+
*/
|
|
55
|
+
export function simLogsParsedLogGroupArn(arn) {
|
|
56
|
+
const [prefix, partition, service, region, account, resourceType, ...rest] = arn.split(":");
|
|
57
|
+
if (prefix !== "arn" ||
|
|
58
|
+
service !== "logs" ||
|
|
59
|
+
resourceType !== "log-group" ||
|
|
60
|
+
!isPresent(partition) ||
|
|
61
|
+
!isPresent(region) ||
|
|
62
|
+
!isPresent(account)) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const [logGroupName, wildcard, ...extra] = rest;
|
|
66
|
+
if (logGroupName === undefined ||
|
|
67
|
+
logGroupName.length === 0 ||
|
|
68
|
+
extra.length > 0 ||
|
|
69
|
+
(wildcard !== undefined && wildcard !== "*")) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return { accountId: account, regionName: region, logGroupName };
|
|
73
|
+
}
|
|
74
|
+
/** Whether an ARN component was written at all. */
|
|
75
|
+
function isPresent(component) {
|
|
76
|
+
return component !== undefined && component.length > 0;
|
|
77
|
+
}
|
|
@@ -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
|
/**
|
|
@@ -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",
|
|
@@ -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?:
|
|
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 {
|
|
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 {
|
|
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,
|
|
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
|
-
|
|
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
|
|
18
|
+
* How much of a header set or a cookie set WAF reads.
|
|
19
19
|
*
|
|
20
|
-
* Real WAF stops at 8 KB
|
|
21
|
-
*
|
|
22
|
-
*
|
|
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
|
|
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
|
|
3
|
+
* How much of a header set or a cookie set WAF reads.
|
|
4
4
|
*
|
|
5
|
-
* Real WAF stops at 8 KB
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
|
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 <=
|
|
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 {
|
|
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 =
|
|
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
|
+
}
|