diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 03196caee29f..b6367cb06f9b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,9 +15,9 @@ /.kokoro/ @GoogleCloudPlatform/python-samples-owners /* @GoogleCloudPlatform/python-samples-owners -/appengine/**/* @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers -/appengine/standard/django/**/* @glasnt @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers -/appengine/flexible/django_cloudsql/**/* @glasnt @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers +/appengine/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers +/appengine/standard/django/**/* @glasnt @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers +/appengine/flexible/django_cloudsql/**/* @glasnt @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers /appengine/standard_python3/spanner/* @GoogleCloudPlatform/api-spanner-python @GoogleCloudPlatform/python-samples-reviewers /asset/**/* @GoogleCloudPlatform/python-samples-reviewers /auth/**/* @arithmetic1728 @GoogleCloudPlatform/python-samples-reviewers @@ -35,7 +35,7 @@ /composer/**/* @leahecole @rachael-ds @GoogleCloudPlatform/cloud-dpes-composer @GoogleCloudPlatform/python-samples-reviewers /compute/**/* @m-strzelczyk @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers /container/**/* @GoogleCloudPlatform/dee-platform-ops @GoogleCloudPlatform/python-samples-reviewers -/containeranalysis/**/* @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers +/containeranalysis/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers /contentwarehouse/**/* @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/python-samples-reviewers /data-science-onramp/ @leahecole @bradmiro @GoogleCloudPlatform/python-samples-reviewers /datacatalog/**/* @GoogleCloudPlatform/python-samples-reviewers @@ -49,10 +49,10 @@ /documentai/**/* @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/python-samples-reviewers /endpoints/**/* @GoogleCloudPlatform/python-samples-reviewers /enterpriseknowledgegraph/**/* @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/python-samples-reviewers -/eventarc/**/* @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers +/eventarc/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers /error_reporting/**/* @GoogleCloudPlatform/python-samples-reviewers /firestore/**/* @GoogleCloudPlatform/cloud-native-db-dpes @GoogleCloudPlatform/python-samples-reviewers -/functions/**/* @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers +/functions/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers /functions/spanner/* @GoogleCloudPlatform/api-spanner-python @GoogleCloudPlatform/python-samples-reviewers /healthcare/**/* @noerog @GoogleCloudPlatform/python-samples-reviewers /iam/api-client/**/* @GoogleCloudPlatform/python-samples-reviewers @@ -78,10 +78,11 @@ /profiler/**/* @GoogleCloudPlatform/python-samples-reviewers /pubsub/**/* @anguillanneuf @hongalex @GoogleCloudPlatform/python-samples-reviewers /pubsublite/**/* @anguillanneuf @hongalex @GoogleCloudPlatform/python-samples-reviewers +/recaptcha_enterprise/**/* @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers /retail/**/* @GoogleCloudPlatform/cloud-retail-team @GoogleCloudPlatform/python-samples-reviewers -/run/**/* @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers -/run/django/**/* @glasnt @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers -/secretmanager/**/* @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers +/run/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers +/run/django/**/* @glasnt @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers +/secretmanager/**/* @GoogleCloudPlatform/torus-dpe @GoogleCloudPlatform/python-samples-reviewers /securitycenter/**/* @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers /speech/**/* @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/python-samples-reviewers /storage/**/* @GoogleCloudPlatform/cloud-storage-dpes @GoogleCloudPlatform/python-samples-reviewers diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index bbb22a359a4f..adeb54e5a232 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -156,6 +156,7 @@ assign_issues_by: - 'api: cloudkms' - 'api: secretmanager' - 'api: privateca' + - 'api: recaptchaenterprise' to: - GoogleCloudPlatform/dee-infra - labels: diff --git a/recaptcha_enterprise/snippets/annotate_assessment.py b/recaptcha_enterprise/snippets/annotate_assessment.py new file mode 100644 index 000000000000..7760d636cbc4 --- /dev/null +++ b/recaptcha_enterprise/snippets/annotate_assessment.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_annotate_assessment] +from google.cloud import recaptchaenterprise_v1 + + +def annotate_assessment(project_id: str, assessment_id: str) -> None: + """Pre-requisite: Create an assessment before annotating. + Annotate an assessment to provide feedback on the correctness of recaptcha prediction. + Args: + project_id: Google Cloud Project ID + assessment_id: Value of the 'name' field returned from the create_assessment() call. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + assessment_name = f"projects/{project_id}/assessments/{assessment_id}" + # Build the annotation request. + # For more info on when/how to annotate, see: + # https://cloud.google.com/recaptcha-enterprise/docs/annotate-assessment#when_to_annotate + request = recaptchaenterprise_v1.AnnotateAssessmentRequest() + request.name = assessment_name + request.annotation = request.Annotation.FRAUDULENT + request.reasons = [request.Reason.FAILED_TWO_FACTOR] + + # Empty response is sent back. + client.annotate_assessment(request) + print("Annotated response sent successfully ! ") + + +# [END recaptcha_enterprise_annotate_assessment] diff --git a/recaptcha_enterprise/snippets/create_assessment.py b/recaptcha_enterprise/snippets/create_assessment.py new file mode 100644 index 000000000000..14adf019c799 --- /dev/null +++ b/recaptcha_enterprise/snippets/create_assessment.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_create_assessment] + +from google.cloud import recaptchaenterprise_v1 +from google.cloud.recaptchaenterprise_v1 import Assessment + + +def create_assessment( + project_id: str, recaptcha_site_key: str, token: str, recaptcha_action: str +) -> Assessment: + """Create an assessment to analyze the risk of a UI action. + Args: + project_id: GCloud Project ID + recaptcha_site_key: Site key obtained by registering a domain/app to use recaptcha services. + token: The token obtained from the client on passing the recaptchaSiteKey. + recaptcha_action: Action name corresponding to the token. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Set the properties of the event to be tracked. + event = recaptchaenterprise_v1.Event() + event.site_key = recaptcha_site_key + event.token = token + + assessment = recaptchaenterprise_v1.Assessment() + assessment.event = event + + project_name = f"projects/{project_id}" + + # Build the assessment request. + request = recaptchaenterprise_v1.CreateAssessmentRequest() + request.assessment = assessment + request.parent = project_name + + response = client.create_assessment(request) + + # Check if the token is valid. + if not response.token_properties.valid: + print( + "The CreateAssessment call failed because the token was " + + "invalid for for the following reasons: " + + str(response.token_properties.invalid_reason) + ) + return + + # Check if the expected action was executed. + if response.token_properties.action != recaptcha_action: + print( + "The action attribute in your reCAPTCHA tag does" + + "not match the action you are expecting to score" + ) + return + else: + # Get the risk score and the reason(s) + # For more information on interpreting the assessment, + # see: https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment + for reason in response.risk_analysis.reasons: + print(reason) + print( + "The reCAPTCHA score for this token is: " + + str(response.risk_analysis.score) + ) + # Get the assessment name (id). Use this to annotate the assessment. + assessment_name = client.parse_assessment_path(response.name).get("assessment") + print(f"Assessment name: {assessment_name}") + return response + + +# [END recaptcha_enterprise_create_assessment] diff --git a/recaptcha_enterprise/snippets/create_site_key.py b/recaptcha_enterprise/snippets/create_site_key.py new file mode 100644 index 000000000000..faf9bbbe2517 --- /dev/null +++ b/recaptcha_enterprise/snippets/create_site_key.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_create_site_key] +from google.cloud import recaptchaenterprise_v1 + + +def create_site_key(project_id: str, domain_name: str) -> str: + """Create reCAPTCHA Site key which binds a domain name to a unique key. + Args: + project_id : GCloud Project ID. + domain_name: Specify the domain name in which the reCAPTCHA should be activated. + """ + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Set the type of the reCAPTCHA to be displayed. + # For different types, see: https://cloud.google.com/recaptcha-enterprise/docs/keys + web_settings = recaptchaenterprise_v1.WebKeySettings() + web_settings.allowed_domains.append(domain_name) + web_settings.allow_amp_traffic = False + web_settings.integration_type = web_settings.IntegrationType.SCORE + + key = recaptchaenterprise_v1.Key() + key.display_name = "any descriptive name for the key" + key.web_settings = web_settings + + # Create the request. + request = recaptchaenterprise_v1.CreateKeyRequest() + request.parent = f"projects/{project_id}" + request.key = key + + # Get the name of the created reCAPTCHA site key. + response = client.create_key(request) + recaptcha_site_key = response.name.rsplit("/", maxsplit=1)[1] + print("reCAPTCHA Site key created successfully. Site Key: " + recaptcha_site_key) + return recaptcha_site_key + + +# [END recaptcha_enterprise_create_site_key] + +if __name__ == "__main__": + import google.auth + import google.auth.exceptions + + # TODO(developer): Replace the below variables before running + try: + default_project_id = google.auth.default()[1] + domain_name = "localhost" + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + create_site_key(default_project_id, domain_name) diff --git a/recaptcha_enterprise/snippets/delete_site_key.py b/recaptcha_enterprise/snippets/delete_site_key.py new file mode 100644 index 000000000000..4dbd039f960a --- /dev/null +++ b/recaptcha_enterprise/snippets/delete_site_key.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_delete_site_key] +from google.cloud import recaptchaenterprise_v1 + + +def delete_site_key(project_id: str, recaptcha_site_key: str) -> None: + """Delete the given reCAPTCHA site key present under the project ID. + + Args: + project_id : GCloud Project ID. + recaptcha_site_key: Specify the key ID to be deleted. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Construct the key details. + key_name = f"projects/{project_id}/keys/{recaptcha_site_key}" + + # Set the project ID and reCAPTCHA site key. + request = recaptchaenterprise_v1.DeleteKeyRequest() + request.name = key_name + + client.delete_key(request) + print("reCAPTCHA Site key deleted successfully ! ") + + +# [END recaptcha_enterprise_delete_site_key] + + +if __name__ == "__main__": + import google.auth + import google.auth.exceptions + + # TODO(developer): Replace the below variables before running + try: + default_project_id = google.auth.default()[1] + recaptcha_site_key = "recaptcha_site_key" + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + delete_site_key(default_project_id, recaptcha_site_key) diff --git a/recaptcha_enterprise/snippets/get_metrics.py b/recaptcha_enterprise/snippets/get_metrics.py new file mode 100644 index 000000000000..8238329d9c9a --- /dev/null +++ b/recaptcha_enterprise/snippets/get_metrics.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_get_metrics_site_key] +from google.cloud import recaptchaenterprise_v1 + + +def get_metrics(project_id: str, recaptcha_site_key: str) -> None: + """Get metrics specific to a recaptcha site key. + E.g: score bucket count for a key or number of + times the checkbox key failed/ passed etc., + Args: + project_id: Google Cloud Project ID. + recaptcha_site_key: Specify the site key to get metrics. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + metrics_name = f"projects/{project_id}/keys/{recaptcha_site_key}/metrics" + request = recaptchaenterprise_v1.GetMetricsRequest() + request.name = metrics_name + + response = client.get_metrics(request) + + # Retrieve the metrics you want from the key. + # If the site key is checkbox type: then use response.challenge_metrics + # instead of response.score_metrics + for day_metric in response.score_metrics: + # Each 'day_metric' is in the granularity of one day. + score_bucket_count = day_metric.overall_metrics.score_buckets + print(score_bucket_count) + + print(f"Retrieved the bucket count for score based key: {recaptcha_site_key}") + + +# [END recaptcha_enterprise_get_metrics_site_key] diff --git a/recaptcha_enterprise/snippets/get_site_key.py b/recaptcha_enterprise/snippets/get_site_key.py new file mode 100644 index 000000000000..c27fba5e2819 --- /dev/null +++ b/recaptcha_enterprise/snippets/get_site_key.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_get_site_key] +from google.cloud import recaptchaenterprise_v1 + + +def get_site_key(project_id: str, recaptcha_site_key: str) -> None: + """ + Get the reCAPTCHA site key present under the project ID. + + Args: + project_id: GCloud Project ID. + recaptcha_site_key: Specify the site key to get the details. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Construct the key details. + key_name = f"projects/{project_id}/keys/{recaptcha_site_key}" + + request = recaptchaenterprise_v1.GetKeyRequest() + request.name = key_name + + key = client.get_key(request) + print("Successfully obtained the key !" + key.name) + + +# [END recaptcha_enterprise_get_site_key] + + +if __name__ == "__main__": + import google.auth + import google.auth.exceptions + + # TODO(developer): Replace the below variables before running + try: + default_project_id = google.auth.default()[1] + recaptcha_site_key = "recaptcha_site_key" + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + get_site_key(default_project_id, recaptcha_site_key) diff --git a/recaptcha_enterprise/snippets/list_site_keys.py b/recaptcha_enterprise/snippets/list_site_keys.py new file mode 100644 index 000000000000..c865184dfa06 --- /dev/null +++ b/recaptcha_enterprise/snippets/list_site_keys.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_list_site_keys] +from google.cloud import recaptchaenterprise_v1 +from google.cloud.recaptchaenterprise_v1.services.recaptcha_enterprise_service.pagers import ( + ListKeysPager, +) + + +def list_site_keys(project_id: str) -> ListKeysPager: + """List all keys present under the given project ID. + + Args: + project_id: GCloud Project ID. + """ + + project_name = f"projects/{project_id}" + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Set the project id to list the keys present in it. + request = recaptchaenterprise_v1.ListKeysRequest() + request.parent = project_name + + response = client.list_keys(request) + print("Listing reCAPTCHA site keys: ") + for i, key in enumerate(response): + print(f"{str(i)}. {key.name}") + + return response + + +# [END recaptcha_enterprise_list_site_keys] + + +if __name__ == "__main__": + import google.auth + import google.auth.exceptions + + # TODO(developer): Replace the below variables before running + try: + default_project_id = google.auth.default()[1] + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + list_site_keys(default_project_id) diff --git a/recaptcha_enterprise/snippets/migrate_site_key.py b/recaptcha_enterprise/snippets/migrate_site_key.py new file mode 100644 index 000000000000..1b4b799e746c --- /dev/null +++ b/recaptcha_enterprise/snippets/migrate_site_key.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_migrate_site_key] +from google.cloud import recaptchaenterprise_v1 + +from list_site_keys import list_site_keys + + +def migrate_site_key(project_id: str, recaptcha_site_key: str) -> None: + """Migrate a key from reCAPTCHA (non-Enterprise) to reCAPTCHA Enterprise. + If you created the key using Admin console: https://www.google.com/recaptcha/admin/site, + then use this API to migrate to reCAPTCHA Enterprise. + For more info, see: https://cloud.google.com/recaptcha-enterprise/docs/migrate-recaptcha + Args: + project_id: Google Cloud Project ID. + recaptcha_site_key: Specify the site key to migrate. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Specify the key name to migrate. + name = f"projects/{project_id}/keys/{recaptcha_site_key}" + request = recaptchaenterprise_v1.MigrateKeyRequest() + request.name = name + + response = client.migrate_key(request) + # To verify if the site key has been migrated, use 'list_site_keys' to check if the + # key is present. + for key in list_site_keys(project_id): + if key.name == response.name: + print(f"Key migrated successfully: {recaptcha_site_key}") + + +# [END recaptcha_enterprise_migrate_site_key] diff --git a/recaptcha_enterprise/snippets/noxfile_config.py b/recaptcha_enterprise/snippets/noxfile_config.py new file mode 100644 index 000000000000..cfbd02d7f9d8 --- /dev/null +++ b/recaptcha_enterprise/snippets/noxfile_config.py @@ -0,0 +1,38 @@ +# Copyright 2021 Google LLC +# +# 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. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be imported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": True, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + # "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + "gcloud_project_env": "BUILD_SPECIFIC_GCLOUD_PROJECT", + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} diff --git a/recaptcha_enterprise/snippets/requirements-test.txt b/recaptcha_enterprise/snippets/requirements-test.txt new file mode 100644 index 000000000000..9381f1f6153f --- /dev/null +++ b/recaptcha_enterprise/snippets/requirements-test.txt @@ -0,0 +1,5 @@ +selenium==4.8.0 +Flask==2.2.2 +pytest==7.2.1 +pytest-flask==1.2.0 +webdriver-manager==3.8.5 \ No newline at end of file diff --git a/recaptcha_enterprise/snippets/requirements.txt b/recaptcha_enterprise/snippets/requirements.txt new file mode 100644 index 000000000000..ed1f9045ed45 --- /dev/null +++ b/recaptcha_enterprise/snippets/requirements.txt @@ -0,0 +1 @@ +google-cloud-recaptcha-enterprise==1.9.0 \ No newline at end of file diff --git a/recaptcha_enterprise/snippets/templates/index.html b/recaptcha_enterprise/snippets/templates/index.html new file mode 100644 index 000000000000..df77d5a43324 --- /dev/null +++ b/recaptcha_enterprise/snippets/templates/index.html @@ -0,0 +1,92 @@ + + + + + + + reCAPTCHA-Enterprise + + + + + +
+ + + + + + + +
+
+ +
+ + \ No newline at end of file diff --git a/recaptcha_enterprise/snippets/test_create_assessment.py b/recaptcha_enterprise/snippets/test_create_assessment.py new file mode 100644 index 000000000000..590351a81357 --- /dev/null +++ b/recaptcha_enterprise/snippets/test_create_assessment.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +import multiprocessing +import os +import re +import time +import typing + +from _pytest.capture import CaptureFixture +from flask import Flask, render_template, url_for +from google.cloud import recaptchaenterprise_v1 +from google.cloud.recaptchaenterprise_v1 import Assessment + +import pytest + +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.webdriver import WebDriver +from selenium.webdriver.common.by import By +from webdriver_manager.chrome import ChromeDriverManager + +from annotate_assessment import annotate_assessment +from create_assessment import create_assessment +from create_site_key import create_site_key +from delete_site_key import delete_site_key + +GOOGLE_CLOUD_PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +DOMAIN_NAME = "localhost" +# Switch the multi-processing style for Python > 3.7: https://github.com/pytest-dev/pytest-flask/issues/104 +multiprocessing.set_start_method("fork") + + +@pytest.fixture(scope="session") +def app() -> Flask: + app = Flask(__name__) + + @app.route("/assess/", methods=["GET"]) + def assess(site_key: str) -> str: + return render_template("index.html", site_key=site_key) + + @app.route("/", methods=["GET"]) + def index() -> str: + return "Helloworld!" + + return app + + +@pytest.fixture(scope="module") +def browser() -> WebDriver: + chrome_options = Options() + chrome_options.add_argument("--no-sandbox") + chrome_options.add_argument("--window-size=1420,1080") + chrome_options.add_argument("--headless") + chrome_options.add_argument("--disable-gpu") + browser = webdriver.Chrome(service=Service(ChromeDriverManager().install()), + options=chrome_options) + yield browser + browser.close() + + +@pytest.fixture(scope="module") +def recaptcha_site_key() -> str: + recaptcha_site_key = create_site_key( + project_id=GOOGLE_CLOUD_PROJECT, domain_name=DOMAIN_NAME + ) + yield recaptcha_site_key + delete_site_key( + project_id=GOOGLE_CLOUD_PROJECT, recaptcha_site_key=recaptcha_site_key + ) + + +@pytest.mark.usefixtures("live_server") +def test_assessment( + capsys: CaptureFixture, recaptcha_site_key: str, browser: WebDriver +) -> None: + # Get token. + token, action = get_token(recaptcha_site_key, browser) + # Create assessment. + assessment_response = assess_token(recaptcha_site_key, token=token, action=action) + score = str(assessment_response.risk_analysis.score) + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + # Parse the assessment_response.name which is of the format: + # {'project': 'my-project-id', 'assessment': 'assessment-id'} + assessment_name = client.parse_assessment_path(assessment_response.name).get( + "assessment" + ) + assert assessment_name != "" + set_score(browser, score) + + # Annotate assessment. + annotate_assessment(project_id=GOOGLE_CLOUD_PROJECT, assessment_id=assessment_name) + out, _ = capsys.readouterr() + assert re.search("Annotated response sent successfully !", out) + + +def get_token(recaptcha_site_key: str, browser: WebDriver) -> typing.Tuple: + browser.get(url_for("assess", site_key=recaptcha_site_key, _external=True)) + time.sleep(5) + + browser.find_element(By.ID, "username").send_keys("username") + browser.find_element(By.ID, "password").send_keys("password") + browser.find_element(By.ID, "recaptchabutton").click() + + # Timeout of 5 seconds + time.sleep(5) + + element = browser.find_element(By.CSS_SELECTOR, "#assessment") + token = element.get_attribute("data-token") + action = element.get_attribute("data-action") + return token, action + + +def assess_token(recaptcha_site_key: str, token: str, action: str) -> Assessment: + return create_assessment( + project_id=GOOGLE_CLOUD_PROJECT, + recaptcha_site_key=recaptcha_site_key, + token=token, + recaptcha_action=action, + ) + + +def set_score(browser: WebDriver, score: str) -> None: + browser.find_element(By.CSS_SELECTOR, "#assessment").send_keys(score) diff --git a/recaptcha_enterprise/snippets/test_site_key.py b/recaptcha_enterprise/snippets/test_site_key.py new file mode 100644 index 000000000000..62b73b41786d --- /dev/null +++ b/recaptcha_enterprise/snippets/test_site_key.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + + +import os +import re + +from _pytest.capture import CaptureFixture +import pytest + +from create_site_key import create_site_key +from delete_site_key import delete_site_key +from get_metrics import get_metrics +from get_site_key import get_site_key +from list_site_keys import list_site_keys +from update_site_key import update_site_key + +# TODO(developer): Replace these variables before running the sample. +GOOGLE_CLOUD_PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +DOMAIN_NAME = "localhost" + + +@pytest.fixture(scope="module") +def recaptcha_site_key() -> str: + recaptcha_site_key = create_site_key( + project_id=GOOGLE_CLOUD_PROJECT, domain_name=DOMAIN_NAME + ) + yield recaptcha_site_key + delete_site_key( + project_id=GOOGLE_CLOUD_PROJECT, recaptcha_site_key=recaptcha_site_key + ) + + +def test_create_site_key(recaptcha_site_key: str) -> None: + assert len(recaptcha_site_key) != 0 + + +def test_list_site_keys(capsys: CaptureFixture, recaptcha_site_key: str) -> None: + list_site_keys(project_id=GOOGLE_CLOUD_PROJECT) + out, _ = capsys.readouterr() + assert re.search(f"keys/{recaptcha_site_key}", out) + + +def test_get_site_key(capsys: CaptureFixture, recaptcha_site_key: str) -> None: + get_site_key(project_id=GOOGLE_CLOUD_PROJECT, recaptcha_site_key=recaptcha_site_key) + out, _ = capsys.readouterr() + assert re.search(f"Successfully obtained the key !.+{recaptcha_site_key}", out) + + +def test_update_site_key(capsys: CaptureFixture, recaptcha_site_key: str) -> None: + update_site_key( + project_id=GOOGLE_CLOUD_PROJECT, + recaptcha_site_key=recaptcha_site_key, + domain_name=DOMAIN_NAME, + ) + out, _ = capsys.readouterr() + assert re.search("reCAPTCHA Site key successfully updated ! ", out) + + +def test_get_metrics(capsys: CaptureFixture, recaptcha_site_key: str) -> None: + get_metrics(project_id=GOOGLE_CLOUD_PROJECT, recaptcha_site_key=recaptcha_site_key) + out, _ = capsys.readouterr() + assert re.search( + f"Retrieved the bucket count for score based key: {recaptcha_site_key}", out + ) diff --git a/recaptcha_enterprise/snippets/update_site_key.py b/recaptcha_enterprise/snippets/update_site_key.py new file mode 100644 index 000000000000..af4533ad969f --- /dev/null +++ b/recaptcha_enterprise/snippets/update_site_key.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# Copyright 2021 Google, Inc +# +# 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. +# +# All Rights Reserved. + +# [START recaptcha_enterprise_update_site_key] +import time + +from google.cloud import recaptchaenterprise_v1 + + +def update_site_key(project_id: str, recaptcha_site_key: str, domain_name: str) -> None: + """ + Update the properties of the given site key present under the project id. + + Args: + project_id: GCloud Project ID. + recaptcha_site_key: Specify the site key. + domain_name: Specify the domain name for which the settings should be updated. + """ + + client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient() + + # Construct the key details. + key_name = f"projects/{project_id}/keys/{recaptcha_site_key}" + + # Set the name and the new settings for the key. + web_settings = recaptchaenterprise_v1.WebKeySettings() + web_settings.allow_amp_traffic = True + web_settings.allowed_domains.append(domain_name) + + key = recaptchaenterprise_v1.Key() + key.display_name = "any descriptive name for the key" + key.name = key_name + key.web_settings = web_settings + + update_key_request = recaptchaenterprise_v1.UpdateKeyRequest() + update_key_request.key = key + client.update_key(update_key_request) + + time.sleep(5) + + # Retrieve the key and check if the property is updated. + get_key_request = recaptchaenterprise_v1.GetKeyRequest() + get_key_request.name = key_name + response = client.get_key(get_key_request) + web_settings = response.web_settings + + # Get the changed property. + if not web_settings.allow_amp_traffic: + print( + "Error! reCAPTCHA Site key property hasn't been updated. Please try again !" + ) + else: + print("reCAPTCHA Site key successfully updated ! ") + + +# [END recaptcha_enterprise_update_site_key] + + +if __name__ == "__main__": + import google.auth + import google.auth.exceptions + + # TODO(developer): Replace the below variables before running + try: + default_project_id = google.auth.default()[1] + recaptcha_site_key = "recaptcha_site_key" + domain_name = "localhost" + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + update_site_key(default_project_id, recaptcha_site_key, domain_name)