'''
# Google reCAPTCHA API Gateway REST API authorizer

This construct provides an API Gateway REST API authorizer that uses Google's reCAPTCHA service to detect abusive
traffic and allow or deny access to the API methods.

It currently only supports v3 of the reCAPTCHA service.

## Installation

### TypeScript / JavaScript

`npm install cdk-recaptcha-authorizer`

or

`yarn add cdk-recaptcha-authorizer`

### Python

`pip install cdk-recaptcha-authorizer`

### Java

```xml
<dependency>
    <groupId>com.engineal.cdk</groupId>
    <artifactId>cdk-recaptcha-authorizer</artifactId>
</dependency>
```

### C# / .Net

`dotnet add package EngineAL.CDK.RecaptchaAuthorizer`

## Usage

See https://developers.google.com/recaptcha/docs/v3 for how to integrate reCAPTCHA in your client code. When
your client code executes the reCAPTCHA client, the returned token from the Google reCAPTCHA client library
should be included in the API Gateway request in the `X-reCAPTCHA-Token` header.

The `RecaptchaAuthorizer` can be used similarly to the `TokenAuthorizer` and `RequestAuthorizer` that are
provided by the `aws-cdk-lib/aws-apigateway` package. It accepts 3 properties:

* `scoreThreshold` (default: 0.5) is the threshold below which requests will be denied.
* `allowedActions` is a list of allowed actions. When your frontend executes the reCAPTCHA client, it provides
  an action name. The reCAPTCHA authorizer will verify this action is allowed and deny a request if the action
  is not in this list.
* `reCaptchaSecretKey` is a `SecretKey` that provides the reCAPTCHA secret key to the reCAPTCHA authorizer.
  See [Secret Key](secret-key).

The following code attaches the reCAPTCHA authorizer to the 'GET' method of the root resource.

```python
const authorizer = new RecaptchaAuthorizer(this, 'reCaptchaAuthorizer', {
    allowedActions: ['my-action'],
    reCaptchaSecretKey: SecretKey.fromPlainText('my-secret-key')
});

api.root.addMethod('GET', new apigateway.MockIntegration(), {
    authorizer
});
```

Authorizers can also be passed via the `defaultMethodOptions` property within the RestApi construct or the
Method construct. Unless explicitly overridden, the specified defaults will be applied across all Methods
across the RestApi or across all Resources, depending on where the defaults were specified.

### Secret Key

The lambda requires the secret key generated by the Google reCAPTCHA Admin Console. You can provide it using
3 methods: plain text, AWS SSM Parameter Store, or AWS Secrets Manager.

#### Plain text

```python
SecretKey.fromPlainText('my-secret-key')
```

#### SSM Parameter Store

```python
const parameter = ssm.StringParameter.fromStringParameterName(this, 'TestParameter', 'test-secret-key');
SecretKey.fromSsmParameter(parameter)
```

#### Secrets Manager

```python
const secretArn = `arn:${Stack.of(this).partition}:secretsmanager:${Stack.of(this).region}:${Stack.of(this).account}:secret:test-secret`;
const secret = secretsmanager.Secret.fromSecretArn(this, 'TestSecret', secretArn);
SecretKey.fromSecretsManager(secret)
```

This also supports JSON secrets, and you can specify an optional field to use:.

```python
const secretArn = `arn:${Stack.of(this).partition}:secretsmanager:${Stack.of(this).region}:${Stack.of(this).account}:secret:test-secret`;
const secret = secretsmanager.Secret.fromSecretArn(this, 'TestSecret', secretArn);
SecretKey.fromSecretsManager(secret, 'my-secret-field')
```

### Useful commands

* `npm run build`   compile the project
* `npm run watch`   watch for changes and compile as needed
* `npm run package` generates libraries for all languages
* `npm run test`    perform the jest unit tests

## License

Copyright 2023 Aaron Lucia

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

```
   http://www.apache.org/licenses/LICENSE-2.0
```

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
import abc
import builtins
import datetime
import enum
import typing

import jsii
import publication
import typing_extensions

from typeguard import check_type

from ._jsii import *

import aws_cdk.aws_apigateway as _aws_cdk_aws_apigateway_ceddda9d
import aws_cdk.aws_iam as _aws_cdk_aws_iam_ceddda9d
import aws_cdk.aws_lambda as _aws_cdk_aws_lambda_ceddda9d
import aws_cdk.aws_logs as _aws_cdk_aws_logs_ceddda9d
import aws_cdk.aws_secretsmanager as _aws_cdk_aws_secretsmanager_ceddda9d
import aws_cdk.aws_ssm as _aws_cdk_aws_ssm_ceddda9d
import constructs as _constructs_77d1e7e8


@jsii.implements(_aws_cdk_aws_apigateway_ceddda9d.IAuthorizer)
class RecaptchaAuthorizer(
    _aws_cdk_aws_apigateway_ceddda9d.Authorizer,
    metaclass=jsii.JSIIMeta,
    jsii_type="cdk-recaptcha-authorizer.RecaptchaAuthorizer",
):
    '''(experimental) Request-based lambda authorizer that authorizes requests using Google's reCaptcha API.

    :stability: experimental
    :resource: AWS::ApiGateway::Authorizer
    '''

    def __init__(
        self,
        scope: _constructs_77d1e7e8.Construct,
        id: builtins.str,
        *,
        allowed_actions: typing.Sequence[builtins.str],
        re_captcha_secret_key: "SecretKey",
        log_retention: typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays] = None,
        score_threshold: typing.Optional[jsii.Number] = None,
        tracing: typing.Optional[_aws_cdk_aws_lambda_ceddda9d.Tracing] = None,
    ) -> None:
        '''
        :param scope: -
        :param id: -
        :param allowed_actions: (experimental) The actions to be allowed by this authorizer.
        :param re_captcha_secret_key: (experimental) The reCaptcha API secret key.
        :param log_retention: (experimental) The number of days log events are kept in CloudWatch Logs. When updating this property, unsetting it doesn't remove the log retention policy. To remove the retention policy, set the value to ``INFINITE``. Default: logs.RetentionDays.INFINITE
        :param score_threshold: (experimental) The minimum score threshold to allow by this authorizer. Default: 0.5
        :param tracing: (experimental) Enable AWS X-Ray Tracing for Lambda Function. Default: Tracing.Disabled

        :stability: experimental
        '''
        if __debug__:
            type_hints = typing.get_type_hints(_typecheckingstub__d97e9548f0b67aa2cda75ffe6ac47f48c0856efdb4142f2dcda199a52ceea48b)
            check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
            check_type(argname="argument id", value=id, expected_type=type_hints["id"])
        props = RecaptchaAuthorizerProps(
            allowed_actions=allowed_actions,
            re_captcha_secret_key=re_captcha_secret_key,
            log_retention=log_retention,
            score_threshold=score_threshold,
            tracing=tracing,
        )

        jsii.create(self.__class__, self, [scope, id, props])

    @builtins.property
    @jsii.member(jsii_name="authorizerId")
    def authorizer_id(self) -> builtins.str:
        '''(experimental) The authorizer ID.

        :stability: experimental
        :attribute: true
        '''
        return typing.cast(builtins.str, jsii.get(self, "authorizerId"))

    @builtins.property
    @jsii.member(jsii_name="authorizationType")
    def authorization_type(
        self,
    ) -> typing.Optional[_aws_cdk_aws_apigateway_ceddda9d.AuthorizationType]:
        '''(experimental) The authorization type of this authorizer.

        :stability: experimental
        '''
        return typing.cast(typing.Optional[_aws_cdk_aws_apigateway_ceddda9d.AuthorizationType], jsii.get(self, "authorizationType"))


@jsii.data_type(
    jsii_type="cdk-recaptcha-authorizer.RecaptchaAuthorizerProps",
    jsii_struct_bases=[],
    name_mapping={
        "allowed_actions": "allowedActions",
        "re_captcha_secret_key": "reCaptchaSecretKey",
        "log_retention": "logRetention",
        "score_threshold": "scoreThreshold",
        "tracing": "tracing",
    },
)
class RecaptchaAuthorizerProps:
    def __init__(
        self,
        *,
        allowed_actions: typing.Sequence[builtins.str],
        re_captcha_secret_key: "SecretKey",
        log_retention: typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays] = None,
        score_threshold: typing.Optional[jsii.Number] = None,
        tracing: typing.Optional[_aws_cdk_aws_lambda_ceddda9d.Tracing] = None,
    ) -> None:
        '''
        :param allowed_actions: (experimental) The actions to be allowed by this authorizer.
        :param re_captcha_secret_key: (experimental) The reCaptcha API secret key.
        :param log_retention: (experimental) The number of days log events are kept in CloudWatch Logs. When updating this property, unsetting it doesn't remove the log retention policy. To remove the retention policy, set the value to ``INFINITE``. Default: logs.RetentionDays.INFINITE
        :param score_threshold: (experimental) The minimum score threshold to allow by this authorizer. Default: 0.5
        :param tracing: (experimental) Enable AWS X-Ray Tracing for Lambda Function. Default: Tracing.Disabled

        :stability: experimental
        '''
        if __debug__:
            type_hints = typing.get_type_hints(_typecheckingstub__3868f6ed0009e1f38a699b298f577498a45cec9c7bafb80148ce25222f19b824)
            check_type(argname="argument allowed_actions", value=allowed_actions, expected_type=type_hints["allowed_actions"])
            check_type(argname="argument re_captcha_secret_key", value=re_captcha_secret_key, expected_type=type_hints["re_captcha_secret_key"])
            check_type(argname="argument log_retention", value=log_retention, expected_type=type_hints["log_retention"])
            check_type(argname="argument score_threshold", value=score_threshold, expected_type=type_hints["score_threshold"])
            check_type(argname="argument tracing", value=tracing, expected_type=type_hints["tracing"])
        self._values: typing.Dict[builtins.str, typing.Any] = {
            "allowed_actions": allowed_actions,
            "re_captcha_secret_key": re_captcha_secret_key,
        }
        if log_retention is not None:
            self._values["log_retention"] = log_retention
        if score_threshold is not None:
            self._values["score_threshold"] = score_threshold
        if tracing is not None:
            self._values["tracing"] = tracing

    @builtins.property
    def allowed_actions(self) -> typing.List[builtins.str]:
        '''(experimental) The actions to be allowed by this authorizer.

        :stability: experimental
        '''
        result = self._values.get("allowed_actions")
        assert result is not None, "Required property 'allowed_actions' is missing"
        return typing.cast(typing.List[builtins.str], result)

    @builtins.property
    def re_captcha_secret_key(self) -> "SecretKey":
        '''(experimental) The reCaptcha API secret key.

        :stability: experimental
        '''
        result = self._values.get("re_captcha_secret_key")
        assert result is not None, "Required property 're_captcha_secret_key' is missing"
        return typing.cast("SecretKey", result)

    @builtins.property
    def log_retention(
        self,
    ) -> typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays]:
        '''(experimental) The number of days log events are kept in CloudWatch Logs.

        When updating this property, unsetting it doesn't
        remove the log retention policy. To remove the retention policy, set the value to ``INFINITE``.

        :default: logs.RetentionDays.INFINITE

        :stability: experimental
        '''
        result = self._values.get("log_retention")
        return typing.cast(typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays], result)

    @builtins.property
    def score_threshold(self) -> typing.Optional[jsii.Number]:
        '''(experimental) The minimum score threshold to allow by this authorizer.

        :default: 0.5

        :stability: experimental
        '''
        result = self._values.get("score_threshold")
        return typing.cast(typing.Optional[jsii.Number], result)

    @builtins.property
    def tracing(self) -> typing.Optional[_aws_cdk_aws_lambda_ceddda9d.Tracing]:
        '''(experimental) Enable AWS X-Ray Tracing for Lambda Function.

        :default: Tracing.Disabled

        :stability: experimental
        '''
        result = self._values.get("tracing")
        return typing.cast(typing.Optional[_aws_cdk_aws_lambda_ceddda9d.Tracing], result)

    def __eq__(self, rhs: typing.Any) -> builtins.bool:
        return isinstance(rhs, self.__class__) and rhs._values == self._values

    def __ne__(self, rhs: typing.Any) -> builtins.bool:
        return not (rhs == self)

    def __repr__(self) -> str:
        return "RecaptchaAuthorizerProps(%s)" % ", ".join(
            k + "=" + repr(v) for k, v in self._values.items()
        )


class SecretKey(
    metaclass=jsii.JSIIAbstractClass,
    jsii_type="cdk-recaptcha-authorizer.SecretKey",
):
    '''(experimental) A reCaptcha secret key.

    :stability: experimental
    '''

    def __init__(self) -> None:
        '''
        :stability: experimental
        '''
        jsii.create(self.__class__, self, [])

    @jsii.member(jsii_name="fromPlainText")
    @builtins.classmethod
    def from_plain_text(cls, secret_key: builtins.str) -> "SecretKey":
        '''
        :param secret_key: The secret key in plain text.

        :return: a secret key from a string in plain text.

        :stability: experimental
        '''
        if __debug__:
            type_hints = typing.get_type_hints(_typecheckingstub__71add4a92a0d21f638b99df390d0fbc84a0c409859f4744d83ba5060dc892b1e)
            check_type(argname="argument secret_key", value=secret_key, expected_type=type_hints["secret_key"])
        return typing.cast("SecretKey", jsii.sinvoke(cls, "fromPlainText", [secret_key]))

    @jsii.member(jsii_name="fromSecretsManager")
    @builtins.classmethod
    def from_secrets_manager(
        cls,
        secret_key_secret: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
        field: typing.Optional[builtins.str] = None,
    ) -> "SecretKey":
        '''
        :param secret_key_secret: The secret in which the secret key is stored.
        :param field: the name of the field with the value that you want to use as the secret key. Only values in JSON format are supported. If you do not specify a JSON field, then the full content of the secret is used.

        :return: a secret key from a secret stored in AWS Secrets Manager.

        :stability: experimental
        '''
        if __debug__:
            type_hints = typing.get_type_hints(_typecheckingstub__269f3744d504f5c56c05444234cd61e07b1dceb2ccef6252dd2aadff1cbabe5e)
            check_type(argname="argument secret_key_secret", value=secret_key_secret, expected_type=type_hints["secret_key_secret"])
            check_type(argname="argument field", value=field, expected_type=type_hints["field"])
        return typing.cast("SecretKey", jsii.sinvoke(cls, "fromSecretsManager", [secret_key_secret, field]))

    @jsii.member(jsii_name="fromSsmParameter")
    @builtins.classmethod
    def from_ssm_parameter(
        cls,
        secret_key_parameter: _aws_cdk_aws_ssm_ceddda9d.IParameter,
    ) -> "SecretKey":
        '''
        :param secret_key_parameter: The parameter in which the secret key is stored.

        :return: a secret key from a parameter stored in AWS Systems Manager Parameter Store.

        :stability: experimental
        '''
        if __debug__:
            type_hints = typing.get_type_hints(_typecheckingstub__c1736e1064e2480b9a0cddd731c76bb411766baacea859ad283981c72fe87ce0)
            check_type(argname="argument secret_key_parameter", value=secret_key_parameter, expected_type=type_hints["secret_key_parameter"])
        return typing.cast("SecretKey", jsii.sinvoke(cls, "fromSsmParameter", [secret_key_parameter]))

    @jsii.member(jsii_name="grantRead")
    @abc.abstractmethod
    def grant_read(
        self,
        grantee: _aws_cdk_aws_iam_ceddda9d.IGrantable,
    ) -> _aws_cdk_aws_iam_ceddda9d.Grant:
        '''(experimental) Grants reading the secret to a principal.

        :param grantee: -

        :stability: experimental
        '''
        ...

    @builtins.property
    @jsii.member(jsii_name="environment")
    @abc.abstractmethod
    def environment(self) -> typing.Mapping[builtins.str, builtins.str]:
        '''(experimental) Key-value pairs that should be added as environment variables to the Lambda.

        :stability: experimental
        '''
        ...

    @builtins.property
    @jsii.member(jsii_name="secretKeyType")
    @abc.abstractmethod
    def secret_key_type(self) -> builtins.str:
        '''(experimental) The type of secret key.

        :stability: experimental
        '''
        ...


class _SecretKeyProxy(SecretKey):
    @jsii.member(jsii_name="grantRead")
    def grant_read(
        self,
        grantee: _aws_cdk_aws_iam_ceddda9d.IGrantable,
    ) -> _aws_cdk_aws_iam_ceddda9d.Grant:
        '''(experimental) Grants reading the secret to a principal.

        :param grantee: -

        :stability: experimental
        '''
        if __debug__:
            type_hints = typing.get_type_hints(_typecheckingstub__1af1d671f7fd12e3ede2c6f7c3898e19c2a6620903932f892798ebe43f353246)
            check_type(argname="argument grantee", value=grantee, expected_type=type_hints["grantee"])
        return typing.cast(_aws_cdk_aws_iam_ceddda9d.Grant, jsii.invoke(self, "grantRead", [grantee]))

    @builtins.property
    @jsii.member(jsii_name="environment")
    def environment(self) -> typing.Mapping[builtins.str, builtins.str]:
        '''(experimental) Key-value pairs that should be added as environment variables to the Lambda.

        :stability: experimental
        '''
        return typing.cast(typing.Mapping[builtins.str, builtins.str], jsii.get(self, "environment"))

    @builtins.property
    @jsii.member(jsii_name="secretKeyType")
    def secret_key_type(self) -> builtins.str:
        '''(experimental) The type of secret key.

        :stability: experimental
        '''
        return typing.cast(builtins.str, jsii.get(self, "secretKeyType"))

# Adding a "__jsii_proxy_class__(): typing.Type" function to the abstract class
typing.cast(typing.Any, SecretKey).__jsii_proxy_class__ = lambda : _SecretKeyProxy


__all__ = [
    "RecaptchaAuthorizer",
    "RecaptchaAuthorizerProps",
    "SecretKey",
]

publication.publish()

def _typecheckingstub__d97e9548f0b67aa2cda75ffe6ac47f48c0856efdb4142f2dcda199a52ceea48b(
    scope: _constructs_77d1e7e8.Construct,
    id: builtins.str,
    *,
    allowed_actions: typing.Sequence[builtins.str],
    re_captcha_secret_key: SecretKey,
    log_retention: typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays] = None,
    score_threshold: typing.Optional[jsii.Number] = None,
    tracing: typing.Optional[_aws_cdk_aws_lambda_ceddda9d.Tracing] = None,
) -> None:
    """Type checking stubs"""
    pass

def _typecheckingstub__3868f6ed0009e1f38a699b298f577498a45cec9c7bafb80148ce25222f19b824(
    *,
    allowed_actions: typing.Sequence[builtins.str],
    re_captcha_secret_key: SecretKey,
    log_retention: typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays] = None,
    score_threshold: typing.Optional[jsii.Number] = None,
    tracing: typing.Optional[_aws_cdk_aws_lambda_ceddda9d.Tracing] = None,
) -> None:
    """Type checking stubs"""
    pass

def _typecheckingstub__71add4a92a0d21f638b99df390d0fbc84a0c409859f4744d83ba5060dc892b1e(
    secret_key: builtins.str,
) -> None:
    """Type checking stubs"""
    pass

def _typecheckingstub__269f3744d504f5c56c05444234cd61e07b1dceb2ccef6252dd2aadff1cbabe5e(
    secret_key_secret: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
    field: typing.Optional[builtins.str] = None,
) -> None:
    """Type checking stubs"""
    pass

def _typecheckingstub__c1736e1064e2480b9a0cddd731c76bb411766baacea859ad283981c72fe87ce0(
    secret_key_parameter: _aws_cdk_aws_ssm_ceddda9d.IParameter,
) -> None:
    """Type checking stubs"""
    pass

def _typecheckingstub__1af1d671f7fd12e3ede2c6f7c3898e19c2a6620903932f892798ebe43f353246(
    grantee: _aws_cdk_aws_iam_ceddda9d.IGrantable,
) -> None:
    """Type checking stubs"""
    pass
