capo-codecommit 0.1.0__py3-none-any.whl
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.
- capo_codecommit/__init__.py +70 -0
- capo_codecommit/_async.py +25 -0
- capo_codecommit/_auth/_identity.py +16 -0
- capo_codecommit/_auth/_providers.py +886 -0
- capo_codecommit/_auth/_signers.py +88 -0
- capo_codecommit/_auth/_sigv4.py +434 -0
- capo_codecommit/_auth/_zapros_handler.py +80 -0
- capo_codecommit/_iter.py +113 -0
- capo_codecommit/_operations/code_commit_20150413/associate_approval_rule_template_with_repository.py +178 -0
- capo_codecommit/_operations/code_commit_20150413/batch_associate_approval_rule_template_with_repositories.py +195 -0
- capo_codecommit/_operations/code_commit_20150413/batch_describe_merge_conflicts.py +252 -0
- capo_codecommit/_operations/code_commit_20150413/batch_disassociate_approval_rule_template_from_repositories.py +195 -0
- capo_codecommit/_operations/code_commit_20150413/batch_get_commits.py +196 -0
- capo_codecommit/_operations/code_commit_20150413/batch_get_repositories.py +185 -0
- capo_codecommit/_operations/code_commit_20150413/create_approval_rule_template.py +177 -0
- capo_codecommit/_operations/code_commit_20150413/create_branch.py +184 -0
- capo_codecommit/_operations/code_commit_20150413/create_commit.py +335 -0
- capo_codecommit/_operations/code_commit_20150413/create_pull_request.py +270 -0
- capo_codecommit/_operations/code_commit_20150413/create_pull_request_approval_rule.py +217 -0
- capo_codecommit/_operations/code_commit_20150413/create_repository.py +230 -0
- capo_codecommit/_operations/code_commit_20150413/create_unreferenced_merge_commit.py +325 -0
- capo_codecommit/_operations/code_commit_20150413/delete_approval_rule_template.py +156 -0
- capo_codecommit/_operations/code_commit_20150413/delete_branch.py +197 -0
- capo_codecommit/_operations/code_commit_20150413/delete_comment_content.py +162 -0
- capo_codecommit/_operations/code_commit_20150413/delete_file.py +247 -0
- capo_codecommit/_operations/code_commit_20150413/delete_pull_request_approval_rule.py +201 -0
- capo_codecommit/_operations/code_commit_20150413/delete_repository.py +178 -0
- capo_codecommit/_operations/code_commit_20150413/describe_merge_conflicts.py +261 -0
- capo_codecommit/_operations/code_commit_20150413/describe_pull_request_events.py +208 -0
- capo_codecommit/_operations/code_commit_20150413/disassociate_approval_rule_template_from_repository.py +173 -0
- capo_codecommit/_operations/code_commit_20150413/evaluate_pull_request_approval_rules.py +197 -0
- capo_codecommit/_operations/code_commit_20150413/get_approval_rule_template.py +157 -0
- capo_codecommit/_operations/code_commit_20150413/get_blob.py +197 -0
- capo_codecommit/_operations/code_commit_20150413/get_branch.py +193 -0
- capo_codecommit/_operations/code_commit_20150413/get_comment.py +183 -0
- capo_codecommit/_operations/code_commit_20150413/get_comment_reactions.py +177 -0
- capo_codecommit/_operations/code_commit_20150413/get_comments_for_compared_commit.py +207 -0
- capo_codecommit/_operations/code_commit_20150413/get_comments_for_pull_request.py +227 -0
- capo_codecommit/_operations/code_commit_20150413/get_commit.py +193 -0
- capo_codecommit/_operations/code_commit_20150413/get_differences.py +222 -0
- capo_codecommit/_operations/code_commit_20150413/get_file.py +208 -0
- capo_codecommit/_operations/code_commit_20150413/get_folder.py +206 -0
- capo_codecommit/_operations/code_commit_20150413/get_merge_commit.py +208 -0
- capo_codecommit/_operations/code_commit_20150413/get_merge_conflicts.py +257 -0
- capo_codecommit/_operations/code_commit_20150413/get_merge_options.py +226 -0
- capo_codecommit/_operations/code_commit_20150413/get_pull_request.py +182 -0
- capo_codecommit/_operations/code_commit_20150413/get_pull_request_approval_states.py +192 -0
- capo_codecommit/_operations/code_commit_20150413/get_pull_request_override_state.py +191 -0
- capo_codecommit/_operations/code_commit_20150413/get_repository.py +182 -0
- capo_codecommit/_operations/code_commit_20150413/get_repository_triggers.py +182 -0
- capo_codecommit/_operations/code_commit_20150413/list_approval_rule_templates.py +152 -0
- capo_codecommit/_operations/code_commit_20150413/list_associated_approval_rule_templates_for_repository.py +194 -0
- capo_codecommit/_operations/code_commit_20150413/list_branches.py +187 -0
- capo_codecommit/_operations/code_commit_20150413/list_file_commit_history.py +212 -0
- capo_codecommit/_operations/code_commit_20150413/list_pull_requests.py +210 -0
- capo_codecommit/_operations/code_commit_20150413/list_repositories.py +161 -0
- capo_codecommit/_operations/code_commit_20150413/list_repositories_for_approval_rule_template.py +194 -0
- capo_codecommit/_operations/code_commit_20150413/list_tags_for_resource.py +162 -0
- capo_codecommit/_operations/code_commit_20150413/merge_branches_by_fast_forward.py +236 -0
- capo_codecommit/_operations/code_commit_20150413/merge_branches_by_squash.py +339 -0
- capo_codecommit/_operations/code_commit_20150413/merge_branches_by_three_way.py +339 -0
- capo_codecommit/_operations/code_commit_20150413/merge_pull_request_by_fast_forward.py +237 -0
- capo_codecommit/_operations/code_commit_20150413/merge_pull_request_by_squash.py +335 -0
- capo_codecommit/_operations/code_commit_20150413/merge_pull_request_by_three_way.py +335 -0
- capo_codecommit/_operations/code_commit_20150413/override_pull_request_approval_rules.py +192 -0
- capo_codecommit/_operations/code_commit_20150413/post_comment_for_compared_commit.py +258 -0
- capo_codecommit/_operations/code_commit_20150413/post_comment_for_pull_request.py +278 -0
- capo_codecommit/_operations/code_commit_20150413/post_comment_reply.py +184 -0
- capo_codecommit/_operations/code_commit_20150413/put_comment_reaction.py +149 -0
- capo_codecommit/_operations/code_commit_20150413/put_file.py +288 -0
- capo_codecommit/_operations/code_commit_20150413/put_repository_triggers.py +247 -0
- capo_codecommit/_operations/code_commit_20150413/tag_resource.py +160 -0
- capo_codecommit/_operations/code_commit_20150413/test_repository_triggers.py +249 -0
- capo_codecommit/_operations/code_commit_20150413/untag_resource.py +160 -0
- capo_codecommit/_operations/code_commit_20150413/update_approval_rule_template_content.py +172 -0
- capo_codecommit/_operations/code_commit_20150413/update_approval_rule_template_description.py +164 -0
- capo_codecommit/_operations/code_commit_20150413/update_approval_rule_template_name.py +162 -0
- capo_codecommit/_operations/code_commit_20150413/update_comment.py +177 -0
- capo_codecommit/_operations/code_commit_20150413/update_default_branch.py +171 -0
- capo_codecommit/_operations/code_commit_20150413/update_pull_request_approval_rule_content.py +222 -0
- capo_codecommit/_operations/code_commit_20150413/update_pull_request_approval_state.py +197 -0
- capo_codecommit/_operations/code_commit_20150413/update_pull_request_description.py +167 -0
- capo_codecommit/_operations/code_commit_20150413/update_pull_request_status.py +198 -0
- capo_codecommit/_operations/code_commit_20150413/update_pull_request_title.py +176 -0
- capo_codecommit/_operations/code_commit_20150413/update_repository_description.py +161 -0
- capo_codecommit/_operations/code_commit_20150413/update_repository_encryption_key.py +196 -0
- capo_codecommit/_operations/code_commit_20150413/update_repository_name.py +136 -0
- capo_codecommit/_pagination.py +21 -0
- capo_codecommit/_protocol/__init__.py +1 -0
- capo_codecommit/_protocol/errors.py +93 -0
- capo_codecommit/_protocol/eventstream.py +238 -0
- capo_codecommit/_protocol/serialize.py +47 -0
- capo_codecommit/_protocol/xml.py +33 -0
- capo_codecommit/_rule_engine/__init__.py +0 -0
- capo_codecommit/_rule_engine/_aws_partition.py +160 -0
- capo_codecommit/_rule_engine/_endpoint_rule_set.py +138 -0
- capo_codecommit/_rule_engine/_endpoint_runtime.py +389 -0
- capo_codecommit/_services/_aws_config.py +160 -0
- capo_codecommit/_services/_pipeline.py +198 -0
- capo_codecommit/_services/async_code_commit.py +6077 -0
- capo_codecommit/_services/code_commit.py +5990 -0
- capo_codecommit/errors/__init__.py +562 -0
- capo_codecommit/errors/_base.py +94 -0
- capo_codecommit/errors/actor_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/approval_rule_content_required_exception.py +54 -0
- capo_codecommit/errors/approval_rule_does_not_exist_exception.py +54 -0
- capo_codecommit/errors/approval_rule_name_already_exists_exception.py +54 -0
- capo_codecommit/errors/approval_rule_name_required_exception.py +54 -0
- capo_codecommit/errors/approval_rule_template_content_required_exception.py +60 -0
- capo_codecommit/errors/approval_rule_template_does_not_exist_exception.py +56 -0
- capo_codecommit/errors/approval_rule_template_in_use_exception.py +54 -0
- capo_codecommit/errors/approval_rule_template_name_already_exists_exception.py +60 -0
- capo_codecommit/errors/approval_rule_template_name_required_exception.py +56 -0
- capo_codecommit/errors/approval_state_required_exception.py +54 -0
- capo_codecommit/errors/author_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/before_commit_id_and_after_commit_id_are_same_exception.py +60 -0
- capo_codecommit/errors/blob_id_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/blob_id_required_exception.py +52 -0
- capo_codecommit/errors/branch_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/branch_name_exists_exception.py +52 -0
- capo_codecommit/errors/branch_name_is_tag_name_exception.py +52 -0
- capo_codecommit/errors/branch_name_required_exception.py +52 -0
- capo_codecommit/errors/cannot_delete_approval_rule_from_template_exception.py +60 -0
- capo_codecommit/errors/cannot_modify_approval_rule_from_template_exception.py +60 -0
- capo_codecommit/errors/client_request_token_required_exception.py +54 -0
- capo_codecommit/errors/comment_content_required_exception.py +54 -0
- capo_codecommit/errors/comment_content_size_limit_exceeded_exception.py +56 -0
- capo_codecommit/errors/comment_deleted_exception.py +52 -0
- capo_codecommit/errors/comment_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/comment_id_required_exception.py +52 -0
- capo_codecommit/errors/comment_not_created_by_caller_exception.py +54 -0
- capo_codecommit/errors/commit_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/commit_id_does_not_exist_exception.py +54 -0
- capo_codecommit/errors/commit_id_required_exception.py +52 -0
- capo_codecommit/errors/commit_ids_limit_exceeded_exception.py +54 -0
- capo_codecommit/errors/commit_ids_list_required_exception.py +54 -0
- capo_codecommit/errors/commit_message_length_exceeded_exception.py +54 -0
- capo_codecommit/errors/commit_required_exception.py +52 -0
- capo_codecommit/errors/concurrent_reference_update_exception.py +54 -0
- capo_codecommit/errors/default_branch_cannot_be_deleted_exception.py +54 -0
- capo_codecommit/errors/directory_name_conflicts_with_file_name_exception.py +58 -0
- capo_codecommit/errors/encryption_integrity_checks_failed_exception.py +56 -0
- capo_codecommit/errors/encryption_key_access_denied_exception.py +54 -0
- capo_codecommit/errors/encryption_key_disabled_exception.py +54 -0
- capo_codecommit/errors/encryption_key_invalid_id_exception.py +54 -0
- capo_codecommit/errors/encryption_key_invalid_usage_exception.py +54 -0
- capo_codecommit/errors/encryption_key_not_found_exception.py +54 -0
- capo_codecommit/errors/encryption_key_required_exception.py +54 -0
- capo_codecommit/errors/encryption_key_unavailable_exception.py +54 -0
- capo_codecommit/errors/file_content_and_source_file_specified_exception.py +56 -0
- capo_codecommit/errors/file_content_required_exception.py +52 -0
- capo_codecommit/errors/file_content_size_limit_exceeded_exception.py +54 -0
- capo_codecommit/errors/file_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/file_entry_required_exception.py +52 -0
- capo_codecommit/errors/file_mode_required_exception.py +52 -0
- capo_codecommit/errors/file_name_conflicts_with_directory_name_exception.py +58 -0
- capo_codecommit/errors/file_path_conflicts_with_submodule_path_exception.py +58 -0
- capo_codecommit/errors/file_too_large_exception.py +52 -0
- capo_codecommit/errors/folder_content_size_limit_exceeded_exception.py +54 -0
- capo_codecommit/errors/folder_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/idempotency_parameter_mismatch_exception.py +54 -0
- capo_codecommit/errors/invalid_actor_arn_exception.py +52 -0
- capo_codecommit/errors/invalid_approval_rule_content_exception.py +54 -0
- capo_codecommit/errors/invalid_approval_rule_name_exception.py +54 -0
- capo_codecommit/errors/invalid_approval_rule_template_content_exception.py +58 -0
- capo_codecommit/errors/invalid_approval_rule_template_description_exception.py +60 -0
- capo_codecommit/errors/invalid_approval_rule_template_name_exception.py +56 -0
- capo_codecommit/errors/invalid_approval_state_exception.py +54 -0
- capo_codecommit/errors/invalid_author_arn_exception.py +52 -0
- capo_codecommit/errors/invalid_blob_id_exception.py +52 -0
- capo_codecommit/errors/invalid_branch_name_exception.py +52 -0
- capo_codecommit/errors/invalid_client_request_token_exception.py +54 -0
- capo_codecommit/errors/invalid_comment_id_exception.py +52 -0
- capo_codecommit/errors/invalid_commit_exception.py +52 -0
- capo_codecommit/errors/invalid_commit_id_exception.py +52 -0
- capo_codecommit/errors/invalid_conflict_detail_level_exception.py +54 -0
- capo_codecommit/errors/invalid_conflict_resolution_exception.py +54 -0
- capo_codecommit/errors/invalid_conflict_resolution_strategy_exception.py +56 -0
- capo_codecommit/errors/invalid_continuation_token_exception.py +54 -0
- capo_codecommit/errors/invalid_deletion_parameter_exception.py +54 -0
- capo_codecommit/errors/invalid_description_exception.py +52 -0
- capo_codecommit/errors/invalid_destination_commit_specifier_exception.py +56 -0
- capo_codecommit/errors/invalid_email_exception.py +52 -0
- capo_codecommit/errors/invalid_file_location_exception.py +52 -0
- capo_codecommit/errors/invalid_file_mode_exception.py +52 -0
- capo_codecommit/errors/invalid_file_position_exception.py +52 -0
- capo_codecommit/errors/invalid_max_conflict_files_exception.py +54 -0
- capo_codecommit/errors/invalid_max_merge_hunks_exception.py +54 -0
- capo_codecommit/errors/invalid_max_results_exception.py +52 -0
- capo_codecommit/errors/invalid_merge_option_exception.py +52 -0
- capo_codecommit/errors/invalid_order_exception.py +52 -0
- capo_codecommit/errors/invalid_override_status_exception.py +54 -0
- capo_codecommit/errors/invalid_parent_commit_id_exception.py +54 -0
- capo_codecommit/errors/invalid_path_exception.py +52 -0
- capo_codecommit/errors/invalid_pull_request_event_type_exception.py +54 -0
- capo_codecommit/errors/invalid_pull_request_id_exception.py +54 -0
- capo_codecommit/errors/invalid_pull_request_status_exception.py +54 -0
- capo_codecommit/errors/invalid_pull_request_status_update_exception.py +54 -0
- capo_codecommit/errors/invalid_reaction_user_arn_exception.py +54 -0
- capo_codecommit/errors/invalid_reaction_value_exception.py +54 -0
- capo_codecommit/errors/invalid_reference_name_exception.py +54 -0
- capo_codecommit/errors/invalid_relative_file_version_enum_exception.py +54 -0
- capo_codecommit/errors/invalid_replacement_content_exception.py +54 -0
- capo_codecommit/errors/invalid_replacement_type_exception.py +54 -0
- capo_codecommit/errors/invalid_repository_description_exception.py +54 -0
- capo_codecommit/errors/invalid_repository_name_exception.py +54 -0
- capo_codecommit/errors/invalid_repository_trigger_branch_name_exception.py +58 -0
- capo_codecommit/errors/invalid_repository_trigger_custom_data_exception.py +58 -0
- capo_codecommit/errors/invalid_repository_trigger_destination_arn_exception.py +60 -0
- capo_codecommit/errors/invalid_repository_trigger_events_exception.py +54 -0
- capo_codecommit/errors/invalid_repository_trigger_name_exception.py +54 -0
- capo_codecommit/errors/invalid_repository_trigger_region_exception.py +54 -0
- capo_codecommit/errors/invalid_resource_arn_exception.py +52 -0
- capo_codecommit/errors/invalid_revision_id_exception.py +52 -0
- capo_codecommit/errors/invalid_rule_content_sha256_exception.py +54 -0
- capo_codecommit/errors/invalid_sort_by_exception.py +52 -0
- capo_codecommit/errors/invalid_source_commit_specifier_exception.py +54 -0
- capo_codecommit/errors/invalid_system_tag_usage_exception.py +54 -0
- capo_codecommit/errors/invalid_tag_keys_list_exception.py +52 -0
- capo_codecommit/errors/invalid_tags_map_exception.py +52 -0
- capo_codecommit/errors/invalid_target_branch_exception.py +52 -0
- capo_codecommit/errors/invalid_target_exception.py +52 -0
- capo_codecommit/errors/invalid_targets_exception.py +52 -0
- capo_codecommit/errors/invalid_title_exception.py +52 -0
- capo_codecommit/errors/manual_merge_required_exception.py +52 -0
- capo_codecommit/errors/maximum_branches_exceeded_exception.py +54 -0
- capo_codecommit/errors/maximum_conflict_resolution_entries_exceeded_exception.py +60 -0
- capo_codecommit/errors/maximum_file_content_to_load_exceeded_exception.py +56 -0
- capo_codecommit/errors/maximum_file_entries_exceeded_exception.py +54 -0
- capo_codecommit/errors/maximum_items_to_compare_exceeded_exception.py +54 -0
- capo_codecommit/errors/maximum_number_of_approvals_exceeded_exception.py +56 -0
- capo_codecommit/errors/maximum_open_pull_requests_exceeded_exception.py +56 -0
- capo_codecommit/errors/maximum_repository_names_exceeded_exception.py +54 -0
- capo_codecommit/errors/maximum_repository_triggers_exceeded_exception.py +56 -0
- capo_codecommit/errors/maximum_rule_templates_associated_with_repository_exception.py +60 -0
- capo_codecommit/errors/merge_option_required_exception.py +52 -0
- capo_codecommit/errors/multiple_conflict_resolution_entries_exception.py +56 -0
- capo_codecommit/errors/multiple_repositories_in_pull_request_exception.py +56 -0
- capo_codecommit/errors/name_length_exceeded_exception.py +52 -0
- capo_codecommit/errors/no_change_exception.py +52 -0
- capo_codecommit/errors/number_of_rule_templates_exceeded_exception.py +54 -0
- capo_codecommit/errors/number_of_rules_exceeded_exception.py +54 -0
- capo_codecommit/errors/operation_not_allowed_exception.py +52 -0
- capo_codecommit/errors/override_already_set_exception.py +52 -0
- capo_codecommit/errors/override_status_required_exception.py +54 -0
- capo_codecommit/errors/parent_commit_does_not_exist_exception.py +54 -0
- capo_codecommit/errors/parent_commit_id_outdated_exception.py +54 -0
- capo_codecommit/errors/parent_commit_id_required_exception.py +54 -0
- capo_codecommit/errors/path_does_not_exist_exception.py +52 -0
- capo_codecommit/errors/path_required_exception.py +52 -0
- capo_codecommit/errors/pull_request_already_closed_exception.py +54 -0
- capo_codecommit/errors/pull_request_approval_rules_not_satisfied_exception.py +60 -0
- capo_codecommit/errors/pull_request_cannot_be_approved_by_author_exception.py +60 -0
- capo_codecommit/errors/pull_request_does_not_exist_exception.py +54 -0
- capo_codecommit/errors/pull_request_id_required_exception.py +54 -0
- capo_codecommit/errors/pull_request_status_required_exception.py +54 -0
- capo_codecommit/errors/put_file_entry_conflict_exception.py +54 -0
- capo_codecommit/errors/reaction_limit_exceeded_exception.py +54 -0
- capo_codecommit/errors/reaction_value_required_exception.py +54 -0
- capo_codecommit/errors/reference_does_not_exist_exception.py +54 -0
- capo_codecommit/errors/reference_name_required_exception.py +54 -0
- capo_codecommit/errors/reference_type_not_supported_exception.py +54 -0
- capo_codecommit/errors/replacement_content_required_exception.py +54 -0
- capo_codecommit/errors/replacement_type_required_exception.py +54 -0
- capo_codecommit/errors/repository_does_not_exist_exception.py +54 -0
- capo_codecommit/errors/repository_limit_exceeded_exception.py +54 -0
- capo_codecommit/errors/repository_name_exists_exception.py +54 -0
- capo_codecommit/errors/repository_name_required_exception.py +54 -0
- capo_codecommit/errors/repository_names_required_exception.py +54 -0
- capo_codecommit/errors/repository_not_associated_with_pull_request_exception.py +60 -0
- capo_codecommit/errors/repository_trigger_branch_name_list_required_exception.py +60 -0
- capo_codecommit/errors/repository_trigger_destination_arn_required_exception.py +60 -0
- capo_codecommit/errors/repository_trigger_events_list_required_exception.py +60 -0
- capo_codecommit/errors/repository_trigger_name_required_exception.py +54 -0
- capo_codecommit/errors/repository_triggers_list_required_exception.py +54 -0
- capo_codecommit/errors/resource_arn_required_exception.py +52 -0
- capo_codecommit/errors/restricted_source_file_exception.py +54 -0
- capo_codecommit/errors/revision_id_required_exception.py +52 -0
- capo_codecommit/errors/revision_not_current_exception.py +52 -0
- capo_codecommit/errors/same_file_content_exception.py +52 -0
- capo_codecommit/errors/same_path_request_exception.py +52 -0
- capo_codecommit/errors/source_and_destination_are_same_exception.py +54 -0
- capo_codecommit/errors/source_file_or_content_required_exception.py +54 -0
- capo_codecommit/errors/tag_keys_list_required_exception.py +52 -0
- capo_codecommit/errors/tag_policy_exception.py +52 -0
- capo_codecommit/errors/tags_map_required_exception.py +52 -0
- capo_codecommit/errors/target_required_exception.py +52 -0
- capo_codecommit/errors/targets_required_exception.py +52 -0
- capo_codecommit/errors/tip_of_source_reference_is_different_exception.py +56 -0
- capo_codecommit/errors/tips_divergence_exceeded_exception.py +54 -0
- capo_codecommit/errors/title_required_exception.py +52 -0
- capo_codecommit/errors/too_many_tags_exception.py +52 -0
- capo_codecommit/py.typed +0 -0
- capo_codecommit/types/_prelude/blob.py +12 -0
- capo_codecommit/types/_prelude/timestamp.py +17 -0
- capo_codecommit/types/account_id.py +5 -0
- capo_codecommit/types/additional_data.py +5 -0
- capo_codecommit/types/approval.py +47 -0
- capo_codecommit/types/approval_list.py +29 -0
- capo_codecommit/types/approval_rule.py +125 -0
- capo_codecommit/types/approval_rule_content.py +5 -0
- capo_codecommit/types/approval_rule_event_metadata.py +48 -0
- capo_codecommit/types/approval_rule_id.py +5 -0
- capo_codecommit/types/approval_rule_name.py +5 -0
- capo_codecommit/types/approval_rule_overridden_event_metadata.py +47 -0
- capo_codecommit/types/approval_rule_template.py +117 -0
- capo_codecommit/types/approval_rule_template_content.py +5 -0
- capo_codecommit/types/approval_rule_template_description.py +5 -0
- capo_codecommit/types/approval_rule_template_id.py +5 -0
- capo_codecommit/types/approval_rule_template_name.py +5 -0
- capo_codecommit/types/approval_rule_template_name_list.py +19 -0
- capo_codecommit/types/approval_rules_list.py +29 -0
- capo_codecommit/types/approval_rules_not_satisfied_list.py +19 -0
- capo_codecommit/types/approval_rules_satisfied_list.py +19 -0
- capo_codecommit/types/approval_state.py +17 -0
- capo_codecommit/types/approval_state_changed_event_metadata.py +47 -0
- capo_codecommit/types/approved.py +5 -0
- capo_codecommit/types/arn.py +5 -0
- capo_codecommit/types/associate_approval_rule_template_with_repository_input.py +49 -0
- capo_codecommit/types/batch_associate_approval_rule_template_with_repositories_error.py +46 -0
- capo_codecommit/types/batch_associate_approval_rule_template_with_repositories_errors_list.py +43 -0
- capo_codecommit/types/batch_associate_approval_rule_template_with_repositories_input.py +61 -0
- capo_codecommit/types/batch_associate_approval_rule_template_with_repositories_output.py +73 -0
- capo_codecommit/types/batch_describe_merge_conflicts_error.py +51 -0
- capo_codecommit/types/batch_describe_merge_conflicts_errors.py +39 -0
- capo_codecommit/types/batch_describe_merge_conflicts_input.py +151 -0
- capo_codecommit/types/batch_describe_merge_conflicts_output.py +94 -0
- capo_codecommit/types/batch_disassociate_approval_rule_template_from_repositories_error.py +48 -0
- capo_codecommit/types/batch_disassociate_approval_rule_template_from_repositories_errors_list.py +43 -0
- capo_codecommit/types/batch_disassociate_approval_rule_template_from_repositories_input.py +63 -0
- capo_codecommit/types/batch_disassociate_approval_rule_template_from_repositories_output.py +75 -0
- capo_codecommit/types/batch_get_commits_error.py +42 -0
- capo_codecommit/types/batch_get_commits_errors_list.py +35 -0
- capo_codecommit/types/batch_get_commits_input.py +51 -0
- capo_codecommit/types/batch_get_commits_output.py +61 -0
- capo_codecommit/types/batch_get_repositories_error.py +63 -0
- capo_codecommit/types/batch_get_repositories_error_code_enum.py +21 -0
- capo_codecommit/types/batch_get_repositories_errors_list.py +39 -0
- capo_codecommit/types/batch_get_repositories_input.py +45 -0
- capo_codecommit/types/batch_get_repositories_output.py +84 -0
- capo_codecommit/types/blob.py +15 -0
- capo_codecommit/types/blob_metadata.py +42 -0
- capo_codecommit/types/branch_info.py +35 -0
- capo_codecommit/types/branch_name.py +5 -0
- capo_codecommit/types/branch_name_list.py +17 -0
- capo_codecommit/types/caller_reactions.py +17 -0
- capo_codecommit/types/capital_boolean.py +5 -0
- capo_codecommit/types/change_type_enum.py +18 -0
- capo_codecommit/types/client_request_token.py +5 -0
- capo_codecommit/types/clone_url_http.py +5 -0
- capo_codecommit/types/clone_url_ssh.py +5 -0
- capo_codecommit/types/comment.py +147 -0
- capo_codecommit/types/comment_id.py +5 -0
- capo_codecommit/types/comments.py +29 -0
- capo_codecommit/types/comments_for_compared_commit.py +84 -0
- capo_codecommit/types/comments_for_compared_commit_data.py +39 -0
- capo_codecommit/types/comments_for_pull_request.py +91 -0
- capo_codecommit/types/comments_for_pull_request_data.py +37 -0
- capo_codecommit/types/commit.py +92 -0
- capo_codecommit/types/commit_id.py +5 -0
- capo_codecommit/types/commit_ids_input_list.py +17 -0
- capo_codecommit/types/commit_name.py +5 -0
- capo_codecommit/types/commit_objects_list.py +29 -0
- capo_codecommit/types/conflict.py +57 -0
- capo_codecommit/types/conflict_detail_level_type_enum.py +17 -0
- capo_codecommit/types/conflict_metadata.py +149 -0
- capo_codecommit/types/conflict_metadata_list.py +33 -0
- capo_codecommit/types/conflict_resolution.py +84 -0
- capo_codecommit/types/conflict_resolution_strategy_type_enum.py +19 -0
- capo_codecommit/types/conflicts.py +29 -0
- capo_codecommit/types/content.py +5 -0
- capo_codecommit/types/count.py +5 -0
- capo_codecommit/types/create_approval_rule_template_input.py +58 -0
- capo_codecommit/types/create_approval_rule_template_output.py +47 -0
- capo_codecommit/types/create_branch_input.py +47 -0
- capo_codecommit/types/create_commit_input.py +134 -0
- capo_codecommit/types/create_commit_output.py +87 -0
- capo_codecommit/types/create_pull_request_approval_rule_input.py +55 -0
- capo_codecommit/types/create_pull_request_approval_rule_output.py +43 -0
- capo_codecommit/types/create_pull_request_input.py +63 -0
- capo_codecommit/types/create_pull_request_output.py +41 -0
- capo_codecommit/types/create_repository_input.py +62 -0
- capo_codecommit/types/create_repository_output.py +42 -0
- capo_codecommit/types/create_unreferenced_merge_commit_input.py +166 -0
- capo_codecommit/types/create_unreferenced_merge_commit_output.py +34 -0
- capo_codecommit/types/creation_date.py +20 -0
- capo_codecommit/types/date.py +5 -0
- capo_codecommit/types/delete_approval_rule_template_input.py +35 -0
- capo_codecommit/types/delete_approval_rule_template_output.py +35 -0
- capo_codecommit/types/delete_branch_input.py +39 -0
- capo_codecommit/types/delete_branch_output.py +38 -0
- capo_codecommit/types/delete_comment_content_input.py +31 -0
- capo_codecommit/types/delete_comment_content_output.py +36 -0
- capo_codecommit/types/delete_file_entries.py +33 -0
- capo_codecommit/types/delete_file_entry.py +31 -0
- capo_codecommit/types/delete_file_input.py +84 -0
- capo_codecommit/types/delete_file_output.py +53 -0
- capo_codecommit/types/delete_pull_request_approval_rule_input.py +43 -0
- capo_codecommit/types/delete_pull_request_approval_rule_output.py +33 -0
- capo_codecommit/types/delete_repository_input.py +31 -0
- capo_codecommit/types/delete_repository_output.py +28 -0
- capo_codecommit/types/describe_merge_conflicts_input.py +136 -0
- capo_codecommit/types/describe_merge_conflicts_output.py +93 -0
- capo_codecommit/types/describe_pull_request_events_input.py +75 -0
- capo_codecommit/types/describe_pull_request_events_output.py +54 -0
- capo_codecommit/types/description.py +5 -0
- capo_codecommit/types/difference.py +73 -0
- capo_codecommit/types/difference_list.py +29 -0
- capo_codecommit/types/disassociate_approval_rule_template_from_repository_input.py +49 -0
- capo_codecommit/types/email.py +5 -0
- capo_codecommit/types/error_code.py +5 -0
- capo_codecommit/types/error_message.py +5 -0
- capo_codecommit/types/evaluate_pull_request_approval_rules_input.py +43 -0
- capo_codecommit/types/evaluate_pull_request_approval_rules_output.py +41 -0
- capo_codecommit/types/evaluation.py +79 -0
- capo_codecommit/types/event_date.py +20 -0
- capo_codecommit/types/exception_name.py +5 -0
- capo_codecommit/types/file.py +60 -0
- capo_codecommit/types/file_content.py +15 -0
- capo_codecommit/types/file_list.py +29 -0
- capo_codecommit/types/file_metadata.py +54 -0
- capo_codecommit/types/file_mode_type_enum.py +18 -0
- capo_codecommit/types/file_modes.py +76 -0
- capo_codecommit/types/file_paths.py +17 -0
- capo_codecommit/types/file_size.py +5 -0
- capo_codecommit/types/file_sizes.py +43 -0
- capo_codecommit/types/file_version.py +70 -0
- capo_codecommit/types/files_metadata.py +29 -0
- capo_codecommit/types/folder.py +41 -0
- capo_codecommit/types/folder_list.py +29 -0
- capo_codecommit/types/get_approval_rule_template_input.py +35 -0
- capo_codecommit/types/get_approval_rule_template_output.py +47 -0
- capo_codecommit/types/get_blob_input.py +39 -0
- capo_codecommit/types/get_blob_output.py +37 -0
- capo_codecommit/types/get_branch_input.py +35 -0
- capo_codecommit/types/get_branch_output.py +36 -0
- capo_codecommit/types/get_comment_input.py +31 -0
- capo_codecommit/types/get_comment_output.py +36 -0
- capo_codecommit/types/get_comment_reactions_input.py +52 -0
- capo_codecommit/types/get_comment_reactions_output.py +54 -0
- capo_codecommit/types/get_comments_for_compared_commit_input.py +63 -0
- capo_codecommit/types/get_comments_for_compared_commit_output.py +49 -0
- capo_codecommit/types/get_comments_for_pull_request_input.py +67 -0
- capo_codecommit/types/get_comments_for_pull_request_output.py +49 -0
- capo_codecommit/types/get_commit_input.py +39 -0
- capo_codecommit/types/get_commit_output.py +37 -0
- capo_codecommit/types/get_differences_input.py +74 -0
- capo_codecommit/types/get_differences_output.py +47 -0
- capo_codecommit/types/get_file_input.py +46 -0
- capo_codecommit/types/get_file_output.py +90 -0
- capo_codecommit/types/get_folder_input.py +46 -0
- capo_codecommit/types/get_folder_output.py +115 -0
- capo_codecommit/types/get_merge_commit_input.py +92 -0
- capo_codecommit/types/get_merge_commit_output.py +46 -0
- capo_codecommit/types/get_merge_conflicts_input.py +126 -0
- capo_codecommit/types/get_merge_conflicts_output.py +85 -0
- capo_codecommit/types/get_merge_options_input.py +92 -0
- capo_codecommit/types/get_merge_options_output.py +65 -0
- capo_codecommit/types/get_pull_request_approval_states_input.py +43 -0
- capo_codecommit/types/get_pull_request_approval_states_output.py +36 -0
- capo_codecommit/types/get_pull_request_input.py +31 -0
- capo_codecommit/types/get_pull_request_output.py +41 -0
- capo_codecommit/types/get_pull_request_override_state_input.py +43 -0
- capo_codecommit/types/get_pull_request_override_state_output.py +36 -0
- capo_codecommit/types/get_repository_input.py +31 -0
- capo_codecommit/types/get_repository_output.py +42 -0
- capo_codecommit/types/get_repository_triggers_input.py +33 -0
- capo_codecommit/types/get_repository_triggers_output.py +51 -0
- capo_codecommit/types/hunk_content.py +5 -0
- capo_codecommit/types/is_binary_file.py +40 -0
- capo_codecommit/types/is_comment_deleted.py +5 -0
- capo_codecommit/types/is_content_conflict.py +5 -0
- capo_codecommit/types/is_file_mode_conflict.py +5 -0
- capo_codecommit/types/is_hunk_conflict.py +5 -0
- capo_codecommit/types/is_mergeable.py +5 -0
- capo_codecommit/types/is_merged.py +5 -0
- capo_codecommit/types/is_move.py +5 -0
- capo_codecommit/types/is_object_type_conflict.py +5 -0
- capo_codecommit/types/keep_empty_folders.py +5 -0
- capo_codecommit/types/kms_key_id.py +5 -0
- capo_codecommit/types/last_modified_date.py +20 -0
- capo_codecommit/types/limit.py +5 -0
- capo_codecommit/types/line_number.py +5 -0
- capo_codecommit/types/list_approval_rule_templates_input.py +35 -0
- capo_codecommit/types/list_approval_rule_templates_output.py +49 -0
- capo_codecommit/types/list_associated_approval_rule_templates_for_repository_input.py +51 -0
- capo_codecommit/types/list_associated_approval_rule_templates_for_repository_output.py +53 -0
- capo_codecommit/types/list_branches_input.py +38 -0
- capo_codecommit/types/list_branches_output.py +45 -0
- capo_codecommit/types/list_file_commit_history_request.py +62 -0
- capo_codecommit/types/list_file_commit_history_response.py +50 -0
- capo_codecommit/types/list_pull_requests_input.py +73 -0
- capo_codecommit/types/list_pull_requests_output.py +50 -0
- capo_codecommit/types/list_repositories_for_approval_rule_template_input.py +51 -0
- capo_codecommit/types/list_repositories_for_approval_rule_template_output.py +53 -0
- capo_codecommit/types/list_repositories_input.py +58 -0
- capo_codecommit/types/list_repositories_output.py +49 -0
- capo_codecommit/types/list_tags_for_resource_input.py +38 -0
- capo_codecommit/types/list_tags_for_resource_output.py +43 -0
- capo_codecommit/types/location.py +56 -0
- capo_codecommit/types/max_results.py +5 -0
- capo_codecommit/types/merge_branches_by_fast_forward_input.py +59 -0
- capo_codecommit/types/merge_branches_by_fast_forward_output.py +34 -0
- capo_codecommit/types/merge_branches_by_squash_input.py +151 -0
- capo_codecommit/types/merge_branches_by_squash_output.py +34 -0
- capo_codecommit/types/merge_branches_by_three_way_input.py +151 -0
- capo_codecommit/types/merge_branches_by_three_way_output.py +34 -0
- capo_codecommit/types/merge_hunk.py +78 -0
- capo_codecommit/types/merge_hunk_detail.py +41 -0
- capo_codecommit/types/merge_hunks.py +29 -0
- capo_codecommit/types/merge_metadata.py +64 -0
- capo_codecommit/types/merge_operations.py +54 -0
- capo_codecommit/types/merge_option_type_enum.py +18 -0
- capo_codecommit/types/merge_options.py +35 -0
- capo_codecommit/types/merge_pull_request_by_fast_forward_input.py +50 -0
- capo_codecommit/types/merge_pull_request_by_fast_forward_output.py +38 -0
- capo_codecommit/types/merge_pull_request_by_squash_input.py +142 -0
- capo_codecommit/types/merge_pull_request_by_squash_output.py +37 -0
- capo_codecommit/types/merge_pull_request_by_three_way_input.py +142 -0
- capo_codecommit/types/merge_pull_request_by_three_way_output.py +37 -0
- capo_codecommit/types/message.py +5 -0
- capo_codecommit/types/mode.py +5 -0
- capo_codecommit/types/name.py +5 -0
- capo_codecommit/types/next_token.py +5 -0
- capo_codecommit/types/number_of_conflicts.py +5 -0
- capo_codecommit/types/object_id.py +5 -0
- capo_codecommit/types/object_size.py +5 -0
- capo_codecommit/types/object_type_enum.py +19 -0
- capo_codecommit/types/object_types.py +68 -0
- capo_codecommit/types/order_enum.py +17 -0
- capo_codecommit/types/origin_approval_rule_template.py +39 -0
- capo_codecommit/types/overridden.py +5 -0
- capo_codecommit/types/override_pull_request_approval_rules_input.py +65 -0
- capo_codecommit/types/override_status.py +17 -0
- capo_codecommit/types/parent_list.py +17 -0
- capo_codecommit/types/path.py +5 -0
- capo_codecommit/types/position.py +5 -0
- capo_codecommit/types/post_comment_for_compared_commit_input.py +81 -0
- capo_codecommit/types/post_comment_for_compared_commit_output.py +84 -0
- capo_codecommit/types/post_comment_for_pull_request_input.py +94 -0
- capo_codecommit/types/post_comment_for_pull_request_output.py +91 -0
- capo_codecommit/types/post_comment_reply_input.py +48 -0
- capo_codecommit/types/post_comment_reply_output.py +36 -0
- capo_codecommit/types/pull_request.py +168 -0
- capo_codecommit/types/pull_request_created_event_metadata.py +47 -0
- capo_codecommit/types/pull_request_event.py +218 -0
- capo_codecommit/types/pull_request_event_list.py +35 -0
- capo_codecommit/types/pull_request_event_type.py +24 -0
- capo_codecommit/types/pull_request_id.py +5 -0
- capo_codecommit/types/pull_request_id_list.py +19 -0
- capo_codecommit/types/pull_request_merged_state_changed_event_metadata.py +56 -0
- capo_codecommit/types/pull_request_source_reference_updated_event_metadata.py +51 -0
- capo_codecommit/types/pull_request_status_changed_event_metadata.py +42 -0
- capo_codecommit/types/pull_request_status_enum.py +17 -0
- capo_codecommit/types/pull_request_target.py +81 -0
- capo_codecommit/types/pull_request_target_list.py +35 -0
- capo_codecommit/types/put_comment_reaction_input.py +39 -0
- capo_codecommit/types/put_file_entries.py +29 -0
- capo_codecommit/types/put_file_entry.py +88 -0
- capo_codecommit/types/put_file_input.py +112 -0
- capo_codecommit/types/put_file_output.py +45 -0
- capo_codecommit/types/put_repository_triggers_input.py +53 -0
- capo_codecommit/types/put_repository_triggers_output.py +30 -0
- capo_codecommit/types/reaction_counts_map.py +29 -0
- capo_codecommit/types/reaction_emoji.py +5 -0
- capo_codecommit/types/reaction_for_comment.py +74 -0
- capo_codecommit/types/reaction_short_code.py +5 -0
- capo_codecommit/types/reaction_unicode.py +5 -0
- capo_codecommit/types/reaction_users_list.py +17 -0
- capo_codecommit/types/reaction_value.py +5 -0
- capo_codecommit/types/reaction_value_formats.py +44 -0
- capo_codecommit/types/reactions_for_comment_list.py +35 -0
- capo_codecommit/types/reference_name.py +5 -0
- capo_codecommit/types/relative_file_version_enum.py +17 -0
- capo_codecommit/types/replace_content_entries.py +35 -0
- capo_codecommit/types/replace_content_entry.py +85 -0
- capo_codecommit/types/replacement_type_enum.py +19 -0
- capo_codecommit/types/repository_description.py +5 -0
- capo_codecommit/types/repository_id.py +5 -0
- capo_codecommit/types/repository_metadata.py +126 -0
- capo_codecommit/types/repository_metadata_list.py +35 -0
- capo_codecommit/types/repository_name.py +5 -0
- capo_codecommit/types/repository_name_id_pair.py +35 -0
- capo_codecommit/types/repository_name_id_pair_list.py +35 -0
- capo_codecommit/types/repository_name_list.py +19 -0
- capo_codecommit/types/repository_not_found_list.py +19 -0
- capo_codecommit/types/repository_trigger.py +87 -0
- capo_codecommit/types/repository_trigger_custom_data.py +5 -0
- capo_codecommit/types/repository_trigger_event_enum.py +19 -0
- capo_codecommit/types/repository_trigger_event_list.py +39 -0
- capo_codecommit/types/repository_trigger_execution_failure.py +39 -0
- capo_codecommit/types/repository_trigger_execution_failure_list.py +39 -0
- capo_codecommit/types/repository_trigger_execution_failure_message.py +5 -0
- capo_codecommit/types/repository_trigger_name.py +5 -0
- capo_codecommit/types/repository_trigger_name_list.py +19 -0
- capo_codecommit/types/repository_triggers_configuration_id.py +5 -0
- capo_codecommit/types/repository_triggers_list.py +35 -0
- capo_codecommit/types/resource_arn.py +5 -0
- capo_codecommit/types/revision_children.py +17 -0
- capo_codecommit/types/revision_dag.py +29 -0
- capo_codecommit/types/revision_id.py +5 -0
- capo_codecommit/types/rule_content_sha256.py +5 -0
- capo_codecommit/types/set_file_mode_entries.py +35 -0
- capo_codecommit/types/set_file_mode_entry.py +49 -0
- capo_codecommit/types/sort_by_enum.py +17 -0
- capo_codecommit/types/source_file_specifier.py +39 -0
- capo_codecommit/types/sub_module.py +41 -0
- capo_codecommit/types/sub_module_list.py +29 -0
- capo_codecommit/types/symbolic_link.py +60 -0
- capo_codecommit/types/symbolic_link_list.py +29 -0
- capo_codecommit/types/tag_key.py +5 -0
- capo_codecommit/types/tag_keys_list.py +17 -0
- capo_codecommit/types/tag_resource_input.py +45 -0
- capo_codecommit/types/tag_value.py +5 -0
- capo_codecommit/types/tags_map.py +28 -0
- capo_codecommit/types/target.py +47 -0
- capo_codecommit/types/target_list.py +29 -0
- capo_codecommit/types/test_repository_triggers_input.py +53 -0
- capo_codecommit/types/test_repository_triggers_output.py +63 -0
- capo_codecommit/types/title.py +5 -0
- capo_codecommit/types/untag_resource_input.py +47 -0
- capo_codecommit/types/update_approval_rule_template_content_input.py +54 -0
- capo_codecommit/types/update_approval_rule_template_content_output.py +46 -0
- capo_codecommit/types/update_approval_rule_template_description_input.py +47 -0
- capo_codecommit/types/update_approval_rule_template_description_output.py +47 -0
- capo_codecommit/types/update_approval_rule_template_name_input.py +46 -0
- capo_codecommit/types/update_approval_rule_template_name_output.py +47 -0
- capo_codecommit/types/update_comment_input.py +39 -0
- capo_codecommit/types/update_comment_output.py +36 -0
- capo_codecommit/types/update_default_branch_input.py +41 -0
- capo_codecommit/types/update_pull_request_approval_rule_content_input.py +62 -0
- capo_codecommit/types/update_pull_request_approval_rule_content_output.py +43 -0
- capo_codecommit/types/update_pull_request_approval_state_input.py +63 -0
- capo_codecommit/types/update_pull_request_description_input.py +43 -0
- capo_codecommit/types/update_pull_request_description_output.py +43 -0
- capo_codecommit/types/update_pull_request_status_input.py +57 -0
- capo_codecommit/types/update_pull_request_status_output.py +43 -0
- capo_codecommit/types/update_pull_request_title_input.py +41 -0
- capo_codecommit/types/update_pull_request_title_output.py +41 -0
- capo_codecommit/types/update_repository_description_input.py +42 -0
- capo_codecommit/types/update_repository_encryption_key_input.py +43 -0
- capo_codecommit/types/update_repository_encryption_key_output.py +41 -0
- capo_codecommit/types/update_repository_name_input.py +38 -0
- capo_codecommit/types/user_info.py +42 -0
- capo_codecommit-0.1.0.dist-info/METADATA +101 -0
- capo_codecommit-0.1.0.dist-info/RECORD +649 -0
- capo_codecommit-0.1.0.dist-info/WHEEL +5 -0
- capo_codecommit-0.1.0.dist-info/licenses/LICENSE +21 -0
- capo_codecommit-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any, Generic, TypeVar
|
|
5
|
+
|
|
6
|
+
from zapros import Request
|
|
7
|
+
|
|
8
|
+
from capo_codecommit._auth._identity import Credentials, Identity
|
|
9
|
+
from capo_codecommit._auth._providers import IdentityProvider
|
|
10
|
+
from capo_codecommit._auth._sigv4 import SigV4AuthContext, sign_sigv4
|
|
11
|
+
|
|
12
|
+
IdentityT = TypeVar("IdentityT", bound="Identity")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Signer(ABC, Generic[IdentityT]):
|
|
16
|
+
"""Per-request request signer. Holds an IdentityProvider plus static config."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, provider: IdentityProvider[IdentityT]) -> None:
|
|
19
|
+
self.provider = provider
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
async def asign(self, req: Request) -> Request: ...
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def sign(self, req: Request) -> Request: ...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SigV4Signer(Signer[Credentials]):
|
|
28
|
+
"""aws.auth#sigv4 — AWS Signature Version 4.
|
|
29
|
+
|
|
30
|
+
The full auth scheme (``name`` variant, ``signingName``, ``signingRegion``,
|
|
31
|
+
encoding/normalization flags) is provided by the caller — either from the
|
|
32
|
+
endpoint rule-set's ``authSchemes`` property or built by the generated
|
|
33
|
+
``get_signer`` from operation defaults.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self, provider: IdentityProvider[Credentials], *, auth_scheme: dict[str, Any]
|
|
38
|
+
) -> None:
|
|
39
|
+
super().__init__(provider)
|
|
40
|
+
self._auth_scheme = auth_scheme
|
|
41
|
+
|
|
42
|
+
async def asign(self, req: Request) -> Request:
|
|
43
|
+
creds = await self.provider.aresolve_identity()
|
|
44
|
+
ctx: SigV4AuthContext = {
|
|
45
|
+
"type": "sig_v4",
|
|
46
|
+
"access_key_id": creds["access_key"],
|
|
47
|
+
"secret_access_key": creds["secret_key"],
|
|
48
|
+
"session_token": creds.get("session_token"),
|
|
49
|
+
"signing_region": self._auth_scheme["signingRegion"],
|
|
50
|
+
"signing_name": self._auth_scheme["signingName"],
|
|
51
|
+
"disable_double_encoding": self._auth_scheme.get(
|
|
52
|
+
"disableDoubleEncoding", False
|
|
53
|
+
),
|
|
54
|
+
"disable_normalize_path": self._auth_scheme.get(
|
|
55
|
+
"disableNormalizePath", False
|
|
56
|
+
),
|
|
57
|
+
}
|
|
58
|
+
if req.body is None:
|
|
59
|
+
body: bytes | None = b""
|
|
60
|
+
elif isinstance(req.body, bytes):
|
|
61
|
+
body = req.body
|
|
62
|
+
else:
|
|
63
|
+
body = None
|
|
64
|
+
return sign_sigv4(req, ctx, body)
|
|
65
|
+
|
|
66
|
+
def sign(self, req: Request) -> Request:
|
|
67
|
+
creds = self.provider.resolve_identity()
|
|
68
|
+
ctx: SigV4AuthContext = {
|
|
69
|
+
"type": "sig_v4",
|
|
70
|
+
"access_key_id": creds["access_key"],
|
|
71
|
+
"secret_access_key": creds["secret_key"],
|
|
72
|
+
"session_token": creds.get("session_token"),
|
|
73
|
+
"signing_region": self._auth_scheme["signingRegion"],
|
|
74
|
+
"signing_name": self._auth_scheme["signingName"],
|
|
75
|
+
"disable_double_encoding": self._auth_scheme.get(
|
|
76
|
+
"disableDoubleEncoding", False
|
|
77
|
+
),
|
|
78
|
+
"disable_normalize_path": self._auth_scheme.get(
|
|
79
|
+
"disableNormalizePath", False
|
|
80
|
+
),
|
|
81
|
+
}
|
|
82
|
+
if req.body is None:
|
|
83
|
+
body: bytes | None = b""
|
|
84
|
+
elif isinstance(req.body, bytes):
|
|
85
|
+
body = req.body
|
|
86
|
+
else:
|
|
87
|
+
body = None
|
|
88
|
+
return sign_sigv4(req, ctx, body)
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"""AWS Signature Version 4 — single-chunk signing.
|
|
2
|
+
|
|
3
|
+
Reference:
|
|
4
|
+
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
|
|
5
|
+
|
|
6
|
+
Verified byte-for-byte against ``botocore.auth.S3SigV4Auth`` / ``SigV4Auth``
|
|
7
|
+
across S3 GET/PUT/POST, query-string, session-token, and non-S3 (IAM)
|
|
8
|
+
canonicalization paths.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import datetime as _dt
|
|
14
|
+
import functools
|
|
15
|
+
import hashlib
|
|
16
|
+
import hmac
|
|
17
|
+
import re
|
|
18
|
+
from typing import Any, Literal, TypedDict
|
|
19
|
+
from urllib.parse import quote, unquote
|
|
20
|
+
|
|
21
|
+
import zapros
|
|
22
|
+
from pywhatwgurl import URLSearchParams
|
|
23
|
+
from zapros import Headers, Request
|
|
24
|
+
from zapros._utils import get_host_header_value
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def build_sigv4_auth_scheme(
|
|
28
|
+
signing_name: str, region: str | None, endpoint_scheme: dict[str, Any] | None = None
|
|
29
|
+
) -> dict[str, Any] | None:
|
|
30
|
+
"""Return the sigv4 auth scheme for ``signing_name``/``region``, with the
|
|
31
|
+
endpoint rule set's matching ``authSchemes`` entry overlaid on top.
|
|
32
|
+
|
|
33
|
+
The rule set only *modifies* signing properties of the resolved scheme
|
|
34
|
+
(Smithy rules engine, ``authSchemes``): keys it carries win, keys it omits
|
|
35
|
+
keep the operation defaults — IAM's global endpoint names only
|
|
36
|
+
``signingRegion``, for instance. Returns None when no signing region is
|
|
37
|
+
known from either source.
|
|
38
|
+
"""
|
|
39
|
+
scheme: dict[str, Any] = {
|
|
40
|
+
"name": "sigv4",
|
|
41
|
+
"signingName": signing_name,
|
|
42
|
+
"signingRegion": region,
|
|
43
|
+
"disableDoubleEncoding": False,
|
|
44
|
+
"disableNormalizePath": False,
|
|
45
|
+
}
|
|
46
|
+
if endpoint_scheme:
|
|
47
|
+
scheme.update(endpoint_scheme)
|
|
48
|
+
if scheme.get("signingRegion") is None:
|
|
49
|
+
return None
|
|
50
|
+
return scheme
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SigV4AuthContext(TypedDict):
|
|
54
|
+
type: Literal["sig_v4"]
|
|
55
|
+
access_key_id: str
|
|
56
|
+
secret_access_key: str
|
|
57
|
+
session_token: str | None
|
|
58
|
+
signing_region: str
|
|
59
|
+
signing_name: str
|
|
60
|
+
# Rules-engine sigv4 auth-scheme flags (False = standard SigV4: normalize
|
|
61
|
+
# dot segments, double-encode the path). S3-family endpoint rulesets set
|
|
62
|
+
# ``disableDoubleEncoding`` so the path is signed exactly as sent.
|
|
63
|
+
disable_double_encoding: bool
|
|
64
|
+
disable_normalize_path: bool
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
_SIGV4_ALGORITHM = "AWS4-HMAC-SHA256"
|
|
68
|
+
_EMPTY_PAYLOAD_SHA256 = hashlib.sha256(b"").hexdigest()
|
|
69
|
+
|
|
70
|
+
# Headers excluded from the signed-headers set. Mirrors botocore's denylist:
|
|
71
|
+
# these are hop-by-hop / mutable in transit, so signing them would break
|
|
72
|
+
# proxies or duplicate values already added by the transport layer.
|
|
73
|
+
_UNSIGNED_HEADERS = frozenset(
|
|
74
|
+
{
|
|
75
|
+
"authorization",
|
|
76
|
+
"cache-control",
|
|
77
|
+
"connection",
|
|
78
|
+
"expect",
|
|
79
|
+
"from",
|
|
80
|
+
"keep-alive",
|
|
81
|
+
"max-forwards",
|
|
82
|
+
"pragma",
|
|
83
|
+
"referer",
|
|
84
|
+
"te",
|
|
85
|
+
"trailer",
|
|
86
|
+
"transfer-encoding",
|
|
87
|
+
"upgrade",
|
|
88
|
+
"user-agent",
|
|
89
|
+
"x-amzn-trace-id",
|
|
90
|
+
"content-length",
|
|
91
|
+
"accept",
|
|
92
|
+
"accept-encoding",
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
_MULTI_SPACE = re.compile(r" +")
|
|
97
|
+
|
|
98
|
+
# Services that require the payload hash to travel in ``x-amz-content-sha256``.
|
|
99
|
+
# Other services sign the hash into the canonical request without sending it.
|
|
100
|
+
_S3_SIGNING_NAMES = frozenset({"s3", "s3express", "s3-outposts", "s3-object-lambda"})
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _uri_encode(value: str) -> str:
|
|
104
|
+
"""RFC 3986 percent-encoding using only the unreserved set as safe."""
|
|
105
|
+
return quote(value, safe="-_.~")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _remove_dot_segments(path: str) -> str:
|
|
109
|
+
"""RFC 3986 §5.2.4 dot-segment removal (mirrors botocore's normalize_url_path)."""
|
|
110
|
+
segments: list[str] = []
|
|
111
|
+
for seg in path.split("/"):
|
|
112
|
+
if not seg or seg == ".":
|
|
113
|
+
continue
|
|
114
|
+
if seg == "..":
|
|
115
|
+
if segments:
|
|
116
|
+
segments.pop()
|
|
117
|
+
else:
|
|
118
|
+
segments.append(seg)
|
|
119
|
+
first = "/" if path.startswith("/") else ""
|
|
120
|
+
last = "/" if path.endswith("/") and segments else ""
|
|
121
|
+
return first + "/".join(segments) + last
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _canonical_path(path: str, *, double_encode: bool, normalize: bool) -> str:
|
|
125
|
+
"""Build CanonicalURI.
|
|
126
|
+
|
|
127
|
+
Per the SigV4 spec, every segment is URI-encoded; standard services
|
|
128
|
+
normalize dot segments and URI-encode each segment **twice**. The
|
|
129
|
+
rules-engine ``disableNormalizePath`` / ``disableDoubleEncoding`` flags
|
|
130
|
+
turn those steps off — S3-family services set both, so the path is
|
|
131
|
+
signed exactly as provided.
|
|
132
|
+
"""
|
|
133
|
+
if not path:
|
|
134
|
+
return "/"
|
|
135
|
+
if not path.startswith("/"):
|
|
136
|
+
path = "/" + path
|
|
137
|
+
if normalize:
|
|
138
|
+
path = _remove_dot_segments(path)
|
|
139
|
+
if not double_encode:
|
|
140
|
+
return path
|
|
141
|
+
decoded = unquote(path)
|
|
142
|
+
first = quote(decoded, safe="/~")
|
|
143
|
+
return quote(first, safe="/~")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _canonical_query(query: str) -> str:
|
|
147
|
+
"""Build CanonicalQueryString from a raw query string (with or without ``?``)."""
|
|
148
|
+
if not query:
|
|
149
|
+
return ""
|
|
150
|
+
if query.startswith("?"):
|
|
151
|
+
query = query[1:]
|
|
152
|
+
if not query:
|
|
153
|
+
return ""
|
|
154
|
+
sp = URLSearchParams(query)
|
|
155
|
+
encoded = sorted((_uri_encode(k), _uri_encode(v)) for k, v in sp.entries())
|
|
156
|
+
return "&".join(f"{k}={v}" for k, v in encoded)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _trim_header_value(value: str) -> str:
|
|
160
|
+
"""Trim leading/trailing whitespace and collapse internal whitespace runs.
|
|
161
|
+
|
|
162
|
+
Spec note: the canonical form treats sequential whitespace inside an
|
|
163
|
+
unquoted value as a single space. We do not parse quoted-string syntax;
|
|
164
|
+
the conservative collapse is correct for every header AWS actually signs.
|
|
165
|
+
"""
|
|
166
|
+
return _MULTI_SPACE.sub(" ", value.strip())
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _canonical_headers(headers: Headers) -> tuple[str, str]:
|
|
170
|
+
"""Return ``(canonical_headers, signed_headers)``."""
|
|
171
|
+
grouped: dict[str, list[str]] = {}
|
|
172
|
+
for name in headers:
|
|
173
|
+
lname = name.lower()
|
|
174
|
+
if lname in _UNSIGNED_HEADERS:
|
|
175
|
+
continue
|
|
176
|
+
grouped[lname] = [_trim_header_value(v) for v in headers.getall(name)]
|
|
177
|
+
|
|
178
|
+
signed = sorted(grouped)
|
|
179
|
+
canonical = "".join(f"{name}:{','.join(grouped[name])}\n" for name in signed)
|
|
180
|
+
return canonical, ";".join(signed)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _build_canonical_request(
|
|
184
|
+
*,
|
|
185
|
+
method: str,
|
|
186
|
+
path: str,
|
|
187
|
+
query: str,
|
|
188
|
+
headers: Headers,
|
|
189
|
+
payload_hash: str,
|
|
190
|
+
double_encode: bool,
|
|
191
|
+
normalize: bool,
|
|
192
|
+
) -> tuple[str, str]:
|
|
193
|
+
canonical_uri = _canonical_path(
|
|
194
|
+
path, double_encode=double_encode, normalize=normalize
|
|
195
|
+
)
|
|
196
|
+
canonical_query = _canonical_query(query)
|
|
197
|
+
canonical_headers, signed_headers = _canonical_headers(headers)
|
|
198
|
+
canonical_request = (
|
|
199
|
+
f"{method}\n"
|
|
200
|
+
f"{canonical_uri}\n"
|
|
201
|
+
f"{canonical_query}\n"
|
|
202
|
+
f"{canonical_headers}\n"
|
|
203
|
+
f"{signed_headers}\n"
|
|
204
|
+
f"{payload_hash}"
|
|
205
|
+
)
|
|
206
|
+
return canonical_request, signed_headers
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@functools.lru_cache(maxsize=8)
|
|
210
|
+
def _derive_signing_key(secret: str, date: str, region: str, service: str) -> bytes:
|
|
211
|
+
# The key depends only on the UTC date stamp (not the full timestamp),
|
|
212
|
+
# so it is reused for every request in the same day/region/service.
|
|
213
|
+
k_date = hmac.new(
|
|
214
|
+
b"AWS4" + secret.encode("utf-8"), date.encode("ascii"), hashlib.sha256
|
|
215
|
+
).digest()
|
|
216
|
+
k_region = hmac.new(k_date, region.encode("utf-8"), hashlib.sha256).digest()
|
|
217
|
+
k_service = hmac.new(k_region, service.encode("utf-8"), hashlib.sha256).digest()
|
|
218
|
+
return hmac.new(k_service, b"aws4_request", hashlib.sha256).digest()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _amz_now() -> _dt.datetime:
|
|
222
|
+
return _dt.datetime.now(_dt.timezone.utc)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _canonical_query_from_pairs(pairs: list[tuple[str, str]]) -> str:
|
|
226
|
+
"""CanonicalQueryString from raw (unencoded) key/value pairs."""
|
|
227
|
+
encoded = sorted((_uri_encode(k), _uri_encode(v)) for k, v in pairs)
|
|
228
|
+
return "&".join(f"{k}={v}" for k, v in encoded)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def sign_sigv4(
|
|
232
|
+
request: Request,
|
|
233
|
+
ctx: SigV4AuthContext,
|
|
234
|
+
body: bytes | None,
|
|
235
|
+
) -> Request:
|
|
236
|
+
"""Return a new ``Request`` carrying SigV4 single-chunk auth headers.
|
|
237
|
+
|
|
238
|
+
Pass ``body=None`` to sign with ``UNSIGNED-PAYLOAD`` (streaming requests).
|
|
239
|
+
The original ``request.body`` is forwarded unchanged in that case.
|
|
240
|
+
"""
|
|
241
|
+
service = ctx["signing_name"]
|
|
242
|
+
region = ctx["signing_region"]
|
|
243
|
+
|
|
244
|
+
headers = request.headers.copy()
|
|
245
|
+
|
|
246
|
+
# X-Amz-Date — honor caller-supplied value (allows deterministic tests).
|
|
247
|
+
existing_date = headers.get("X-Amz-Date")
|
|
248
|
+
if existing_date:
|
|
249
|
+
amz_date = existing_date
|
|
250
|
+
date_stamp = amz_date[:8]
|
|
251
|
+
else:
|
|
252
|
+
now = _amz_now()
|
|
253
|
+
amz_date = now.strftime("%Y%m%dT%H%M%SZ")
|
|
254
|
+
date_stamp = now.strftime("%Y%m%d")
|
|
255
|
+
headers["X-Amz-Date"] = amz_date
|
|
256
|
+
|
|
257
|
+
# Payload hash. For S3-family services, x-amz-content-sha256 is mandatory
|
|
258
|
+
# and must be set BEFORE computing the canonical request (it gets signed).
|
|
259
|
+
payload_hash = headers.get("X-Amz-Content-SHA256")
|
|
260
|
+
if payload_hash is None:
|
|
261
|
+
if body is None:
|
|
262
|
+
payload_hash = "UNSIGNED-PAYLOAD"
|
|
263
|
+
else:
|
|
264
|
+
payload_hash = (
|
|
265
|
+
hashlib.sha256(body).hexdigest() if body else _EMPTY_PAYLOAD_SHA256
|
|
266
|
+
)
|
|
267
|
+
if service in _S3_SIGNING_NAMES:
|
|
268
|
+
headers["X-Amz-Content-SHA256"] = payload_hash
|
|
269
|
+
|
|
270
|
+
# Session token (STS / assumed-role credentials).
|
|
271
|
+
session_token = ctx.get("session_token")
|
|
272
|
+
if session_token:
|
|
273
|
+
headers["X-Amz-Security-Token"] = session_token
|
|
274
|
+
|
|
275
|
+
# Host header is added by Request.__init__ from the URL; defensive fallback.
|
|
276
|
+
if "host" not in headers and request.url.hostname:
|
|
277
|
+
headers["Host"] = get_host_header_value(request.url)
|
|
278
|
+
|
|
279
|
+
canonical_request, signed_headers = _build_canonical_request(
|
|
280
|
+
method=request.method.upper(),
|
|
281
|
+
path=request.url.pathname,
|
|
282
|
+
query=request.url.search,
|
|
283
|
+
headers=headers,
|
|
284
|
+
payload_hash=payload_hash,
|
|
285
|
+
double_encode=not ctx["disable_double_encoding"],
|
|
286
|
+
normalize=not ctx["disable_normalize_path"],
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
credential_scope = f"{date_stamp}/{region}/{service}/aws4_request"
|
|
290
|
+
string_to_sign = (
|
|
291
|
+
f"{_SIGV4_ALGORITHM}\n"
|
|
292
|
+
f"{amz_date}\n"
|
|
293
|
+
f"{credential_scope}\n"
|
|
294
|
+
f"{hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()}"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
signing_key = _derive_signing_key(
|
|
298
|
+
ctx["secret_access_key"], date_stamp, region, service
|
|
299
|
+
)
|
|
300
|
+
signature = hmac.new(
|
|
301
|
+
signing_key, string_to_sign.encode("utf-8"), hashlib.sha256
|
|
302
|
+
).hexdigest()
|
|
303
|
+
|
|
304
|
+
headers["Authorization"] = (
|
|
305
|
+
f"{_SIGV4_ALGORITHM} "
|
|
306
|
+
f"Credential={ctx['access_key_id']}/{credential_scope},"
|
|
307
|
+
f"SignedHeaders={signed_headers},"
|
|
308
|
+
f"Signature={signature}"
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
effective_body = body if body is not None else request.body
|
|
312
|
+
if effective_body is not None:
|
|
313
|
+
return Request(
|
|
314
|
+
request.url,
|
|
315
|
+
request.method,
|
|
316
|
+
headers,
|
|
317
|
+
body=effective_body,
|
|
318
|
+
context=request.context,
|
|
319
|
+
)
|
|
320
|
+
return Request(request.url, request.method, headers, context=request.context)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def presign_sigv4(
|
|
324
|
+
request: Request,
|
|
325
|
+
ctx: SigV4AuthContext,
|
|
326
|
+
*,
|
|
327
|
+
expires_in: int = 3600,
|
|
328
|
+
now: _dt.datetime | None = None,
|
|
329
|
+
) -> Request:
|
|
330
|
+
"""Return a new ``Request`` whose URL carries SigV4 query-string auth.
|
|
331
|
+
|
|
332
|
+
The signature travels in the URL (``X-Amz-*`` query params), so the result
|
|
333
|
+
is usable standalone (browser, curl). Payload is signed as
|
|
334
|
+
``UNSIGNED-PAYLOAD``, so the body is not bound by the signature.
|
|
335
|
+
|
|
336
|
+
``expires_in`` is the validity window in seconds; range 1..604800 (7 days),
|
|
337
|
+
bounded by the max lifetime of the derived signing key.
|
|
338
|
+
"""
|
|
339
|
+
if not 1 <= expires_in <= 604800:
|
|
340
|
+
raise ValueError(f"expires_in must be in [1, 604800], got {expires_in}")
|
|
341
|
+
|
|
342
|
+
sign_time = now or _amz_now()
|
|
343
|
+
if sign_time.tzinfo is None:
|
|
344
|
+
raise ValueError("now must be timezone-aware (UTC)")
|
|
345
|
+
|
|
346
|
+
service = ctx["signing_name"]
|
|
347
|
+
region = ctx["signing_region"]
|
|
348
|
+
|
|
349
|
+
amz_date = sign_time.strftime("%Y%m%dT%H%M%SZ")
|
|
350
|
+
date_stamp = sign_time.strftime("%Y%m%d")
|
|
351
|
+
credential_scope = f"{date_stamp}/{region}/{service}/aws4_request"
|
|
352
|
+
|
|
353
|
+
# Canonical headers: host is mandatory; anything else already on the request
|
|
354
|
+
# is signed too (and must then be sent alongside the URL). Strip the headers
|
|
355
|
+
# that belong in the query string to avoid header/query value conflicts
|
|
356
|
+
# (which AWS rejects as InvalidRequest).
|
|
357
|
+
headers = request.headers.copy()
|
|
358
|
+
for h in (
|
|
359
|
+
"Authorization",
|
|
360
|
+
"X-Amz-Date",
|
|
361
|
+
"X-Amz-Content-SHA256",
|
|
362
|
+
"X-Amz-Security-Token",
|
|
363
|
+
):
|
|
364
|
+
if h in headers:
|
|
365
|
+
del headers[h]
|
|
366
|
+
if "host" not in headers and request.url.hostname:
|
|
367
|
+
headers["Host"] = get_host_header_value(request.url)
|
|
368
|
+
|
|
369
|
+
canonical_headers, signed_headers = _canonical_headers(headers)
|
|
370
|
+
|
|
371
|
+
# Signed query params (raw values). X-Amz-Signature is appended afterwards.
|
|
372
|
+
amz_params: list[tuple[str, str]] = [
|
|
373
|
+
("X-Amz-Algorithm", _SIGV4_ALGORITHM),
|
|
374
|
+
("X-Amz-Credential", f"{ctx['access_key_id']}/{credential_scope}"),
|
|
375
|
+
("X-Amz-Date", amz_date),
|
|
376
|
+
("X-Amz-Expires", str(expires_in)),
|
|
377
|
+
("X-Amz-SignedHeaders", signed_headers),
|
|
378
|
+
]
|
|
379
|
+
session_token = ctx.get("session_token")
|
|
380
|
+
if session_token:
|
|
381
|
+
# S3 and most services require the token inside the canonical query.
|
|
382
|
+
# (A few — e.g. iotdevicegateway — want it appended post-signature
|
|
383
|
+
# instead; handle those as a special case if you ever target them.)
|
|
384
|
+
amz_params.append(("X-Amz-Security-Token", session_token))
|
|
385
|
+
|
|
386
|
+
existing = list(URLSearchParams(request.url.search).entries())
|
|
387
|
+
canonical_query = _canonical_query_from_pairs(existing + amz_params)
|
|
388
|
+
|
|
389
|
+
canonical_uri = _canonical_path(
|
|
390
|
+
request.url.pathname,
|
|
391
|
+
double_encode=not ctx["disable_double_encoding"],
|
|
392
|
+
normalize=not ctx["disable_normalize_path"],
|
|
393
|
+
)
|
|
394
|
+
canonical_request = (
|
|
395
|
+
f"{request.method.upper()}\n"
|
|
396
|
+
f"{canonical_uri}\n"
|
|
397
|
+
f"{canonical_query}\n"
|
|
398
|
+
f"{canonical_headers}\n"
|
|
399
|
+
f"{signed_headers}\n"
|
|
400
|
+
f"UNSIGNED-PAYLOAD"
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
string_to_sign = (
|
|
404
|
+
f"{_SIGV4_ALGORITHM}\n"
|
|
405
|
+
f"{amz_date}\n"
|
|
406
|
+
f"{credential_scope}\n"
|
|
407
|
+
f"{hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()}"
|
|
408
|
+
)
|
|
409
|
+
signing_key = _derive_signing_key(
|
|
410
|
+
ctx["secret_access_key"], date_stamp, region, service
|
|
411
|
+
)
|
|
412
|
+
signature = hmac.new(
|
|
413
|
+
signing_key, string_to_sign.encode("utf-8"), hashlib.sha256
|
|
414
|
+
).hexdigest()
|
|
415
|
+
|
|
416
|
+
# X-Amz-Signature is hex (no encoding needed) and is NOT part of the
|
|
417
|
+
# canonical query. The sorted canonical query doubles as the URL query.
|
|
418
|
+
final_query = f"{canonical_query}&X-Amz-Signature={signature}"
|
|
419
|
+
|
|
420
|
+
url = request.url
|
|
421
|
+
fragment = url.hash or ""
|
|
422
|
+
presigned_href = zapros.URL(
|
|
423
|
+
f"{url.protocol}//{url.host}{url.pathname}?{final_query}{fragment}"
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
if request.body is not None:
|
|
427
|
+
return Request(
|
|
428
|
+
presigned_href,
|
|
429
|
+
request.method,
|
|
430
|
+
headers,
|
|
431
|
+
body=request.body,
|
|
432
|
+
context=request.context,
|
|
433
|
+
)
|
|
434
|
+
return Request(presigned_href, request.method, headers, context=request.context)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from typing import Optional, cast
|
|
2
|
+
|
|
3
|
+
from zapros import (
|
|
4
|
+
AsyncBaseHandler,
|
|
5
|
+
AsyncBaseMiddleware,
|
|
6
|
+
AsyncSyncMismatchError,
|
|
7
|
+
BaseHandler,
|
|
8
|
+
BaseMiddleware,
|
|
9
|
+
Request,
|
|
10
|
+
)
|
|
11
|
+
from zapros._models import Response
|
|
12
|
+
|
|
13
|
+
from ._signers import Signer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def ensure_async_handler(
|
|
17
|
+
handler: AsyncBaseHandler | BaseHandler,
|
|
18
|
+
) -> AsyncBaseHandler:
|
|
19
|
+
if isinstance(handler, AsyncBaseHandler):
|
|
20
|
+
return handler
|
|
21
|
+
raise AsyncSyncMismatchError(
|
|
22
|
+
"Handler was expected to be an AsyncBaseHandler, but it is not."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def ensure_sync_handler(
|
|
27
|
+
handler: AsyncBaseHandler | BaseHandler,
|
|
28
|
+
) -> BaseHandler:
|
|
29
|
+
if isinstance(handler, BaseHandler):
|
|
30
|
+
return handler
|
|
31
|
+
raise AsyncSyncMismatchError(
|
|
32
|
+
"Handler was expected to be a BaseHandler, but it is not."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def strip_accept_encoding(request: Request) -> Request:
|
|
37
|
+
"""Drop the ``Accept-Encoding`` zapros adds to every request.
|
|
38
|
+
|
|
39
|
+
Like the AWS SDKs, the client never asks for transport compression: a
|
|
40
|
+
response body must be the service's actual bytes so ``Content-Length``,
|
|
41
|
+
checksums and ``Range`` stay coherent and a ``Content-Encoding`` on it is
|
|
42
|
+
always stored metadata (an S3 object's), never something to undo. Removing
|
|
43
|
+
the header before signing also keeps it out of the canonical request, where
|
|
44
|
+
a proxy rewriting it in flight would break the signature.
|
|
45
|
+
"""
|
|
46
|
+
if "accept-encoding" in request.headers:
|
|
47
|
+
del request.headers["Accept-Encoding"]
|
|
48
|
+
return request
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class AuthMiddleware(BaseMiddleware, AsyncBaseMiddleware):
|
|
52
|
+
"""Sign the outgoing request using the Signer placed in ``context["signer"]``.
|
|
53
|
+
|
|
54
|
+
The generated ``get_signer`` in each operation module resolves the
|
|
55
|
+
effective auth scheme to a concrete :class:`Signer` and threads it
|
|
56
|
+
through ``request.context`` before dispatch. This middleware does the
|
|
57
|
+
actual signing; ``None`` means the operation opted out via
|
|
58
|
+
``@optionalAuth`` and the request passes through unsigned. Either way
|
|
59
|
+
``Accept-Encoding`` is stripped first (see :func:`strip_accept_encoding`).
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, next_handler: BaseHandler | AsyncBaseHandler) -> None:
|
|
63
|
+
self.next = cast(BaseHandler, next_handler)
|
|
64
|
+
self.async_next = cast(AsyncBaseHandler, next_handler)
|
|
65
|
+
|
|
66
|
+
def handle(self, request: Request) -> Response:
|
|
67
|
+
next_handler = ensure_sync_handler(self.next)
|
|
68
|
+
request = strip_accept_encoding(request)
|
|
69
|
+
signer = cast(Optional[Signer], request.context.get("signer"))
|
|
70
|
+
if signer is not None:
|
|
71
|
+
request = signer.sign(request)
|
|
72
|
+
return next_handler.handle(request)
|
|
73
|
+
|
|
74
|
+
async def ahandle(self, request: Request) -> Response:
|
|
75
|
+
next_handler = ensure_async_handler(self.async_next)
|
|
76
|
+
request = strip_accept_encoding(request)
|
|
77
|
+
signer = cast(Optional[Signer], request.context.get("signer"))
|
|
78
|
+
if signer is not None:
|
|
79
|
+
request = await signer.asign(request)
|
|
80
|
+
return await next_handler.ahandle(request)
|