├── .github ├── dependabot.yml └── workflows │ ├── nodejs_ci.yaml │ └── python_ci.yaml ├── .gitignore ├── LICENSE ├── README.md ├── nodejs ├── README.md ├── index.js ├── lib │ └── crypto.js ├── package-lock.json ├── package.json └── test │ ├── test_crypto.js │ └── test_index.js ├── python ├── LICENSE ├── Makefile ├── README.md ├── kmscrypt │ ├── __init__.py │ ├── __main__.py │ └── crypto.py ├── poetry.lock ├── py.typed ├── pyproject.toml └── tests │ └── test_crypto.py ├── rust ├── Cargo.toml ├── examples │ ├── decrypt.rs │ └── encrypt.rs └── src │ └── lib.rs └── shell └── aws-kms-crypt.sh /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | # version: 2 7 | # updates: 8 | # - package-ecosystem: "npm" # See documentation for possible values 9 | # directory: "/nodejs/" # Location of package manifests 10 | # schedule: 11 | # interval: "weekly" 12 | # day: "sunday" 13 | # open-pull-requests-limit: 20 14 | # groups: 15 | # production-dependencies: 16 | # dependency-type: "production" 17 | # development-dependencies: 18 | # dependency-type: "development" 19 | # - package-ecosystem: "pip" # See documentation for possible values 20 | # directory: "/python/" # Location of package manifests 21 | # schedule: 22 | # interval: "weekly" 23 | # day: "sunday" 24 | # open-pull-requests-limit: 20 25 | # groups: 26 | # production-dependencies: 27 | # dependency-type: "production" 28 | # development-dependencies: 29 | # dependency-type: "development" 30 | # # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot 31 | # - package-ecosystem: "github-actions" 32 | # directory: "/" 33 | # schedule: 34 | # # Check for updates to GitHub Actions every week 35 | # interval: "weekly" 36 | # day: "sunday" 37 | -------------------------------------------------------------------------------- /.github/workflows/nodejs_ci.yaml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | workflow_dispatch: {} 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | defaults: 11 | run: 12 | working-directory: nodejs 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | node-version: [12.x, 14.x, 16.x] 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | - run: npm ci 29 | - run: npm run build --if-present 30 | - run: npm run test 31 | - run: npm run lint 32 | -------------------------------------------------------------------------------- /.github/workflows/python_ci.yaml: -------------------------------------------------------------------------------- 1 | name: Python CI 2 | 3 | on: 4 | workflow_dispatch: {} 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | defaults: 11 | run: 12 | working-directory: python 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install --upgrade poetry 31 | poetry install 32 | - name: Lint and test 33 | run: | 34 | make -k lint test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output/ 3 | .vscode/ 4 | coverage/ 5 | .tgz 6 | 7 | # general things to ignore 8 | build/ 9 | dist/ 10 | *.egg-info/ 11 | *.egg 12 | *.py[cod] 13 | __pycache__/ 14 | *.so 15 | *~ 16 | 17 | # due to using tox and pytest 18 | .tox 19 | .cache 20 | .mypy_cache 21 | 22 | # coverage.py 23 | .coverage 24 | 25 | target/ 26 | Cargo.lock 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sami Jaktholm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MAINTENANCE DISCONTINUED 2 | 3 | This project is no longer actively maintained. Consider migrating over to [AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html). 4 | 5 | -- 6 | 7 | # aws-kms-crypt 8 | 9 | Library for encrypting and decrypting secrets within the AWS ecosystem. 10 | 11 | * [Features](#features) 12 | * [Installation](#installation) 13 | * [Usage](#usage) 14 | * [General Prerequisites](#usage-general) 15 | * [Shell](#usage-shell) 16 | * [Node](#usage-node) 17 | * [Python](#usage-python) 18 | * [Rust](#usage-rust) 19 | * [How it Works?](#details) 20 | 21 | 22 | 23 | # Features 24 | 25 | * **Interoperable** - Interoperable implementations for Bash, NodeJS, Python and Rust. 26 | * **Secure** - AES encryption with KMS generated data keys ([details](#details)). 27 | * **Simple** - Simple API for encrypting and decrypting sensitive data from all supported languages. 28 | 29 | 30 | 31 | # Installation 32 | 33 | ## Shell 34 | 35 | ``` 36 | curl -LO https://raw.githubusercontent.com/sjakthol/aws-kms-crypt/master/shell/aws-kms-crypt.sh && chmod +x aws-kms-crypt.sh 37 | ``` 38 | 39 | ## NodeJS 40 | ``` 41 | npm install aws-kms-crypt 42 | ``` 43 | 44 | ## Python 45 | ``` 46 | pip install aws-kms-crypt 47 | ``` 48 | 49 | ## Rust 50 | In `cargo.toml` 51 | ``` 52 | [dependencies] 53 | aws_kms_crypt = "0.1.0" 54 | ``` 55 | 56 | 57 | 58 | # Usage 59 | 60 | 61 | 62 | ## General Prerequisites 63 | 64 | All implementations require access to AWS credentials. 65 | 66 | When encrypting data, the credentials must allow the following actions: 67 | 68 | * `kms:GenerateDataKey` 69 | * `kms:GenerateRandom` 70 | 71 | When decrypting data, the credentials must allow the following actions: 72 | 73 | * `kms:Decrypt` 74 | 75 | In both cases, the access can (and should in the case of `kms:Decrypt`) be 76 | further limited with IAM policy conditions (see [here](https://docs.aws.amazon.com/kms/latest/developerguide/policy-conditions.html) 77 | for details). 78 | 79 | 80 | 81 | ## Shell Scripts (Bash) 82 | The shell script at `shell/aws-kms-crypt.sh` provides an interface for shell 83 | scripts to encrypt and decrypt data. The script needs the following commands / 84 | tools to function: 85 | 86 | * `aws` 87 | * `base64` 88 | * `cut` 89 | * `jq` 90 | * `od` 91 | * `openssl` 92 | * `sed` 93 | 94 | ### Encrypting Data 95 | ```bash 96 | # No encryption context 97 | echo -n "secretp4ssw0rd!" | ./aws-kms-crypt.sh encrypt --kms-key-id alias/common > encrypted-plan.json 98 | 99 | # With encryption context 100 | echo -n "secretp4ssw0rd!" | ./aws-kms-crypt.sh encrypt --kms-key-id alias/common --encryption-context type=plan,entity=admins > encrypted-plan.json 101 | ``` 102 | 103 | ### Decrypting Data 104 | ```bash 105 | $ cat encrypted-plan.json | ./aws-kms-crypt.sh decrypt 106 | secretp4ssw0rd! 107 | ``` 108 | 109 | 110 | 111 | ## Node 112 | The `nodejs` directory contains a Node package that implements the KMS based encryption 113 | and decryption functionality. 114 | 115 | A recent version of Node (>= 4) is required. 116 | 117 | ### Encrypting Data 118 | Use the `encrypt()` function of the module to encrypt any stringified data: 119 | ```js 120 | const kmscrypt = require('aws-kms-crypt') 121 | kmscrypt.encrypt('secretp4ssw0rd!', { 122 | key: 'alias/common', // Change your key here 123 | region: 'eu-west-1', // AWS SDK needs to know this 124 | encryptionContext: { purpose: 'automation' } // optional, can be left out 125 | }, function (err, result) { 126 | if (err) { 127 | return console.log('Encryption failed:', err) 128 | } 129 | 130 | console.log(JSON.stringify(result, null, 2)) 131 | // Console output: 132 | // { 133 | // "EncryptedData": "DPQ0OZ8auGY6ohQb/pypAHJTAPaQre7RrEtziIhRgB8=", 134 | // "EncryptedDataKey": "CBZogG5a", 135 | // "EncryptionContext": { 136 | // "purpose": "automation" 137 | // }, 138 | // "Iv": "6f93b293f7f77ddf7525bf43038f01c4" 139 | // } 140 | }) 141 | ``` 142 | 143 | ### Decrypting Data 144 | To decrypt previously encrypted data, feed the parsed JSON document 145 | into the `decrypt()` function of the module: 146 | ```js 147 | const kmscrypt = require('aws-kms-crypt') 148 | kmscrypt.decrypt({ 149 | 'EncryptedData': 'TSHgAb4MYkacM9qtdO5OeLQax6jze3P7+zIeUDpakC4=', 150 | 'EncryptedDataKey': 'KqnVhLZY+8', 151 | 'EncryptionContext': { 152 | 'purpose': 'automation' 153 | }, 154 | 'Iv': '6cfbac80d90df12a6357a8f91b57f907' 155 | }, { region: 'eu-west-1' }, function (err, result) { 156 | if (err) { 157 | return console.log('Encryption failed:', err) 158 | } 159 | 160 | console.log(result) 161 | // => secretp4ssw0rd! 162 | }) 163 | ``` 164 | 165 | 166 | 167 | ## Python 168 | The `python` directory contains a Python package that implements the KMS based encryption 169 | and decryption functionality. It supports Python 3.6 and newer. 170 | 171 | ### Encrypting Data 172 | ```python 173 | import kmscrypt 174 | 175 | res = kmscrypt.encrypt('secretp4ssw0rd!', key_id='alias/common', encryption_context={ 176 | 'purpose': 'automation' 177 | }) 178 | 179 | # res is now a dict of form 180 | # { 181 | # 'EncryptedData': 'Su00srm/ru5kd9DLDvi0EdEjjBGUrRBJ06vUmL8QHUU=', 182 | # 'EncryptedDataKey': 'AQIDAHhyrbU/fP', 183 | # 'EncryptionContext': {'purpose': 'automation'}, 184 | # 'Iv': 'd07acff1e2301c468cd3164b8858e477' 185 | # } 186 | ``` 187 | 188 | ### Decrypting Data 189 | ```python 190 | secret = kmscrypt.decrypt(res) 191 | print(secret) # => b'secretp4ssw0rd!' 192 | ``` 193 | 194 | 195 | 196 | ## Rust 197 | The `rust` directory contains a rust crate that implements KMS based encryption 198 | and decryption functionality. 199 | 200 | ### Encrypting Data 201 | ```rust 202 | extern crate aws_kms_crypt; 203 | extern crate serde_json; 204 | 205 | use std::collections::HashMap; 206 | 207 | fn main() { 208 | let mut encryption_context = HashMap::new(); 209 | encryption_context.insert("entity".to_owned(), "admin".to_owned()); 210 | 211 | let options = aws_kms_crypt::EncryptOptions { 212 | encryption_context: encryption_context, 213 | key: "alias/common".into(), 214 | region: "eu-west-1".into() 215 | }; 216 | 217 | let data = "secret".into(); 218 | let res = aws_kms_crypt::encrypt(&data, &options); 219 | println!("{}", serde_json::to_string(&res.unwrap()).unwrap()); 220 | } 221 | ``` 222 | 223 | ### Decrypting Data 224 | Here's a full example that uses [serde_json](https://crates.io/crates/serde_json) 225 | to deserialize the JSON encoded secret into a struct: 226 | 227 | ```rust 228 | extern crate aws_kms_crypt; 229 | extern crate serde_json; 230 | 231 | fn main() { 232 | let raw = r#"{ 233 | "EncryptedData": "vRhu+D5LrwNctyhxDvUoqL51YH2LclgUKtDz/2Nxy6Y=", 234 | "EncryptedDataKey": "KBFRpvDvpXNXu3e/tTO6Jfi", 235 | "EncryptionContext": { 236 | "entity": "admin" 237 | }, 238 | "Iv": "31bf06a8e0d15a26f1325da6f4f33a9c" 239 | }"#; 240 | 241 | let data: aws_kms_crypt::EncryptedSecret = serde_json::from_str(raw).unwrap(); 242 | let options = aws_kms_crypt::DecryptOptions { 243 | region: "eu-west-1".to_owned() 244 | }; 245 | 246 | let res = aws_kms_crypt::decrypt(&data, &options); 247 | println!("Secret is: {:?}", res.unwrap()); 248 | } 249 | ``` 250 | 251 | 252 | 253 | # How it works? 254 | 255 | ## Encrypting Data 256 | 257 | The following steps are taken when the data is encrypted: 258 | 259 | 1. A random 16 byte initialization vector is generated with the [GenerateRandom](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateRandom.html) KMS API 260 | call (shell) or through a platform-specific randomness API (Node, Python) 261 | 2. A data encryption key for AES-128 algorithm is generated with the [GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)` KMS API call 262 | 3. The input data is encrypted locally with AES-128-CBC algorithm using the plaintext version 263 | of the generated data key together with the generated IV for encryption. 264 | 4. The encrypted data, encrypted data key and the initialization vector is outputted into 265 | a JSON document of following format: 266 | ```json 267 | { 268 | "EncryptedData": "", 269 | "EncryptedDataKey": "", 270 | "EncryptionContext": { 271 | "KeyName1": "1", 272 | "KeyName2": "2" 273 | }, 274 | "Iv": "" 275 | } 276 | ```` 277 | 278 | This JSON output can be saved to a file and stored in (semi) publicly available location 279 | as it does not reveal anything about the encrypted data. 280 | 281 | ## Decrypting the Data 282 | The decryption phase extracts the data from the JSON document the encryption phase 283 | produced and takes the following steps to decrypt the data: 284 | 285 | 1. The encrypted data key is decrypted using the [Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) KMS API call 286 | to retrieve the plaintext data encryption key 287 | 2. The plaintext data key and the IV is used to decrypt the encrypted data locally. 288 | 289 | # Future Work 290 | * Support other algorithms than AES-128-CBC 291 | * Automated testing of interoperability 292 | -------------------------------------------------------------------------------- /nodejs/README.md: -------------------------------------------------------------------------------- 1 | Utility for encrypting and decrypting secrets with the AWS KMS service. 2 | 3 | ## Installation 4 | ``` 5 | npm install aws-kms-crypt 6 | ``` 7 | 8 | ## Usage 9 | Before using the module, you need to ensure that Amazon SDK has access 10 | to AWS credentials that are able to access the KMS key used for encryption 11 | and decryption. 12 | 13 | ### Encrypting Data 14 | 15 | ```js 16 | const kmscrypt = require('aws-kms-crypt') 17 | 18 | // Encrypting data 19 | kmscrypt.encrypt('secretp4ssw0rd!', { 20 | key: 'alias/common', // Your key here 21 | region: 'eu-west-1', // AWS SDK needs to know this 22 | encryptionContext: { purpose: 'automation' } // optional, can be left out 23 | }, function (err, result) { 24 | if (err) { 25 | return console.log('Encryption failed:', err) 26 | } 27 | 28 | // result = { 29 | // "EncryptedData": "DPQ0OZ8auGY6ohQb/pypAHJTAPaQre7RrEtziIhRgB8=", 30 | // "EncryptedDataKey": "CBZogG5a", 31 | // "EncryptionContext": { 32 | // "purpose": "automation" 33 | // }, 34 | // "Iv": "6f93b293f7f77ddf7525bf43038f01c4" 35 | // } 36 | }) 37 | ``` 38 | 39 | ### Decrypting Data 40 | 41 | ```js 42 | const kmscrypt = require('aws-kms-crypt') 43 | 44 | kmscrypt.decrypt({ 45 | 'EncryptedData': 'DPQ0OZ8auGY6ohQb/pypAHJTAPaQre7RrEtziIhRgB8=', 46 | 'EncryptedDataKey': 'CBZogG5a', 47 | 'EncryptionContext': { 48 | 'purpose': 'automation' 49 | }, 50 | 'Iv': '6f93b293f7f77ddf7525bf43038f01c4' 51 | }, { region: 'eu-west-1' }, function (err, result) { 52 | if (err) { 53 | return console.log('Decryption failed:', err) 54 | } 55 | 56 | console.log(result) 57 | // => secretp4ssw0rd! 58 | }) 59 | ``` 60 | -------------------------------------------------------------------------------- /nodejs/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const AWS = require('aws-sdk') 3 | const crypto = require('./lib/crypto') 4 | const nodecrypto = require('crypto') 5 | 6 | const AES_IV_BYTES = 16 7 | const AES_KEY_SPEC = 'AES_128' 8 | 9 | module.exports = { 10 | 11 | /** 12 | * Handler function for the encrypt operation result. 13 | * 14 | * @callback encryptCallback 15 | * @param {Error} err - the reason for a failure (falsy if success) 16 | * @param {Object} result - the result of the operation 17 | * @param {string} result.EncryptedData - the encrypted data (base64 encoded) 18 | * @param {string} result.EncryptedDataKey - encrypted data key (base64 encoded) 19 | * @param {string} result.EncryptionContext - the encryption context 20 | * @param {string} result.Iv - the initialization vector (hex encoded) 21 | */ 22 | 23 | /** 24 | * Encrypts the given data using KMS. 25 | * 26 | * @param {string} data - the data to encrypt 27 | * @param {Object} options - options for this operation 28 | * @param {Object} [options.encryptionContext={}] - encryption context 29 | * @param {string} options.key - KMS key ID, ARN, alias or alias ARN 30 | * @param {string} options.region - AWS region of the key 31 | * @param {encryptCallback} callback 32 | */ 33 | encrypt: (data, options, callback) => { 34 | const kms = new AWS.KMS({ region: options.region }) 35 | const iv = nodecrypto.randomBytes(AES_IV_BYTES) 36 | 37 | kms.generateDataKey({ 38 | EncryptionContext: options.encryptionContext || {}, 39 | KeyId: options.key, 40 | KeySpec: AES_KEY_SPEC 41 | }, function (err, res) { 42 | if (err) { 43 | return callback(err) 44 | } 45 | 46 | let result 47 | try { 48 | const message = Buffer.from(data, 'utf8') 49 | const key = Buffer.from(res.Plaintext, 'base64') 50 | const enc = crypto.encrypt(message, key, iv) 51 | result = { 52 | EncryptedData: enc, 53 | EncryptedDataKey: res.CiphertextBlob.toString('base64'), 54 | EncryptionContext: options.encryptionContext || {}, 55 | Iv: iv.toString('hex') 56 | } 57 | } catch (e) { 58 | return callback(e) 59 | } 60 | 61 | callback(null, result) 62 | }) 63 | }, 64 | 65 | /** 66 | * Handler function for the decrypt operation result. 67 | * 68 | * @callback decryptCallback 69 | * @param {Error} err - the reason for a failure (falsy if success) 70 | * @param {string} result - the decrypted message 71 | */ 72 | 73 | /** 74 | * Decrypts a previously encrypted message. 75 | * 76 | * @param {Object} data - the output of the encryption stage 77 | * @param {string} data.EncryptedData - the encrypted data (base64 encoded) 78 | * @param {string} data.EncryptedDataKey - encrypted data key (base64 encoded) 79 | * @param {string} data.EncryptionContext - the encryption context 80 | * @param {string} data.Iv - the initialization vector (hex encoded) 81 | * @param {Object} options - options for the operation 82 | * @param {string} options.region - AWS region of the key 83 | * @param {decryptCallback} callback 84 | */ 85 | decrypt: (data, options, callback) => { 86 | const kms = new AWS.KMS({ region: options.region }) 87 | kms.decrypt({ 88 | CiphertextBlob: Buffer.from(data.EncryptedDataKey, 'base64'), 89 | EncryptionContext: data.EncryptionContext 90 | }, function (err, res) { 91 | if (err) { 92 | return callback(err) 93 | } 94 | 95 | let result 96 | try { 97 | const key = res.Plaintext 98 | const iv = Buffer.from(data.Iv, 'hex') 99 | const message = Buffer.from(data.EncryptedData, 'base64') 100 | result = crypto.decrypt(message, key, iv) 101 | } catch (e) { 102 | return callback(e) 103 | } 104 | 105 | callback(null, result) 106 | }) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /nodejs/lib/crypto.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const crypto = require('crypto') 4 | 5 | const AES_CBC_IDENTIFIER = 'aes-128-cbc' 6 | const AES_IV_BYTES = 16 7 | const AES_KEY_BYTES = 16 8 | 9 | module.exports = { 10 | /** 11 | * Decrypts the given message using the given key and iv. 12 | * 13 | * @param {Buffer} message the message to decrypt 14 | * @param {Buffer} key the key to decrypt the data with 15 | * @param {Buffer} iv the initialization vector to use 16 | * @return {string} the decrypt message as string 17 | * @throws {Error} if decryption fails or input is invalid 18 | */ 19 | decrypt: (message, key, iv) => { 20 | // Validate the key and iv 21 | module.exports.validateKeyAndIv(key, iv) 22 | 23 | // Sanity check the message 24 | if (!Buffer.isBuffer(message) || message.length === 0) { 25 | throw new Error('Given message is invalid') 26 | } 27 | 28 | // Decrypt the message 29 | const cipher = crypto.createDecipheriv(AES_CBC_IDENTIFIER, key, iv) 30 | return cipher.update(message, undefined, 'utf8') + cipher.final('utf8') 31 | }, 32 | 33 | /** 34 | * Encrypts the given message with the given key and initialization vector. 35 | * 36 | * @param {Buffer} message the message to encrypt 37 | * @param {Buffer} key the key to encrypt the data with 38 | * @param {Buffer} iv the initialization vector to use 39 | * @return {string} the encrypted message as base64 encoded string 40 | * @throws {Error} if encryption fails or input is invalid 41 | */ 42 | encrypt: (message, key, iv) => { 43 | // Validate the key and iv 44 | module.exports.validateKeyAndIv(key, iv) 45 | 46 | // Sanity check the message 47 | if (!Buffer.isBuffer(message) || message.length === 0) { 48 | throw new Error('Given message is invalid') 49 | } 50 | 51 | // Encrypt the message 52 | const cipher = crypto.createCipheriv(AES_CBC_IDENTIFIER, key, iv) 53 | return cipher.update(message, 'utf-8', 'base64') + cipher.final('base64') 54 | }, 55 | 56 | validateKeyAndIv: (key, iv) => { 57 | if (!Buffer.isBuffer(key)) { 58 | throw new TypeError('Encryption key must be a Buffer') 59 | } 60 | 61 | if (!Buffer.isBuffer(iv)) { 62 | throw new TypeError('IV must be a Buffer') 63 | } 64 | 65 | if (key.length !== AES_KEY_BYTES) { 66 | throw new Error('Encryption key must be ' + AES_KEY_BYTES + ' bytes') 67 | } 68 | 69 | if (iv.length !== AES_IV_BYTES) { 70 | throw new Error('IV must be ' + AES_IV_BYTES + ' bytes') 71 | } 72 | 73 | if (iv.compare(key) === 0) { 74 | throw new Error('Key and IV cannot be the same!') 75 | } 76 | 77 | return true 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-kms-crypt", 3 | "version": "0.1.0", 4 | "description": "Utility for encrypting and decrypting secrets with the AWS KMS service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "nyc --all mocha", 8 | "lint": "standard" 9 | }, 10 | "keywords": [ 11 | "aws", 12 | "kms", 13 | "secrets", 14 | "encrypt", 15 | "decrypt", 16 | "tool" 17 | ], 18 | "author": "Sami Jaktholm ", 19 | "license": "MIT", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/sjakthol/aws-kms-crypt" 23 | }, 24 | "devDependencies": { 25 | "chai": "^4.3.4", 26 | "mocha": "^10.0.0", 27 | "nyc": "^15.1.0", 28 | "pre-commit": "^1.2.2", 29 | "sinon": "^15.0.0", 30 | "sinon-chai": "^3.7.0", 31 | "standard": "^17.0.0" 32 | }, 33 | "pre-commit": [ 34 | "lint" 35 | ], 36 | "standard": { 37 | "globals": [ 38 | "it", 39 | "describe" 40 | ] 41 | }, 42 | "dependencies": { 43 | "aws-sdk": "^2.995.0" 44 | }, 45 | "files": [ 46 | "index.js", 47 | "lib/" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /nodejs/test/test_crypto.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | 'use strict' 4 | 5 | const chai = require('chai') 6 | const expect = chai.expect 7 | 8 | const crypto = require('../lib/crypto') 9 | 10 | const TEST_KEY = Buffer.from('00968820dfc11ee7816ac942b3980941', 'hex') 11 | const TEST_IV = Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex') 12 | 13 | const VALIDATION_TEST_CASES = [{ 14 | desc: 'valid input', 15 | input: { 16 | key: Buffer.from('00968820dfc11ee7816ac942b3980941', 'hex'), 17 | iv: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex') 18 | }, 19 | 20 | success: true 21 | }, { 22 | desc: 'non-buffer key', 23 | input: { 24 | key: '00968820dfc11ee7816ac942b3980941', 25 | iv: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex') 26 | }, 27 | 28 | success: false 29 | }, { 30 | desc: 'non-iv key', 31 | input: { 32 | key: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex'), 33 | iv: '00968820dfc11ee7816ac942b3980941' 34 | }, 35 | 36 | success: false 37 | }, { 38 | desc: 'key of wrong length', 39 | input: { 40 | key: Buffer.from('0000', 'hex'), 41 | iv: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex') 42 | }, 43 | 44 | success: false 45 | }, { 46 | desc: 'iv of wrong length', 47 | input: { 48 | key: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex'), 49 | iv: Buffer.from('0000', 'hex') 50 | }, 51 | 52 | success: false 53 | }, { 54 | desc: 'equal iv and key', 55 | input: { 56 | key: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex'), 57 | iv: Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex') 58 | }, 59 | 60 | success: false 61 | }] 62 | 63 | describe('the crypto module', function () { 64 | describe('validateKeyAndIv method', function () { 65 | VALIDATION_TEST_CASES.forEach(test => { 66 | it('should detect ' + test.desc, function () { 67 | if (test.success) { 68 | expect(crypto.validateKeyAndIv(test.input.key, test.input.iv)).to.equal(true) 69 | } else { 70 | expect(() => crypto.validateKeyAndIv(test.input.key, test.input.iv)).to.throw() 71 | } 72 | }) 73 | }) 74 | }) 75 | 76 | describe('encrypt method', function () { 77 | it('throws if message is not a buffer', function () { 78 | expect(() => crypto.encrypt('test', TEST_KEY, TEST_IV)).to.throw() 79 | }) 80 | }) 81 | 82 | describe('decrypt method', function () { 83 | it('throws if message is not a buffer', function () { 84 | expect(() => crypto.decrypt('test', TEST_KEY, TEST_IV)).to.throw() 85 | }) 86 | }) 87 | 88 | it('should be able to decrypt what encrypt outputted', function () { 89 | const message = Buffer.from('test_message', 'utf8') 90 | const enc = crypto.encrypt(message, TEST_KEY, TEST_IV) 91 | const dec = crypto.decrypt(Buffer.from(enc, 'base64'), TEST_KEY, TEST_IV) 92 | expect(dec).to.equal('test_message') 93 | }) 94 | }) 95 | -------------------------------------------------------------------------------- /nodejs/test/test_index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | 'use strict' 4 | 5 | const chai = require('chai') 6 | const expect = chai.expect 7 | const sinon = require('sinon') 8 | const sinonChai = require('sinon-chai') 9 | chai.use(sinonChai) 10 | 11 | const index = require('../index') 12 | const AWS = require('aws-sdk') 13 | AWS.KMS = sinon.stub() 14 | const generateDataKeyStub = AWS.KMS.prototype.generateDataKey = sinon.stub() 15 | const decryptStub = AWS.KMS.prototype.decrypt = sinon.stub() 16 | 17 | const TEST_PLAINTEXT_KEY = Buffer.from('00968820dfc11ee7816ac942b3980941', 'hex') 18 | const TEST_ENCRYPTED_KEY = Buffer.from('e05c35df8681f98b1fcee59bcc8e0d2e', 'hex') 19 | const TEST_DATA = { 20 | EncryptedData: 'mRio/6iZ0C0xCRQrvhAvLIgnPda6Cc/0s8YPyRCkanc=', 21 | EncryptedDataKey: 'AQIDAHhyrbU/fPcQ+a8pJiYC78j8wop4mw1jqy3CZk35', 22 | EncryptionContext: { 23 | entity: 'test' 24 | }, 25 | Iv: '00968820dfc11ee7816ac942b3980941' 26 | } 27 | 28 | describe('the index module', function () { 29 | describe('encrypt function', function () { 30 | afterEach(() => { 31 | generateDataKeyStub.reset() 32 | }) 33 | 34 | it('should encrypt data properly', function (done) { 35 | generateDataKeyStub.yields(undefined, { 36 | CiphertextBlob: TEST_ENCRYPTED_KEY, 37 | Plaintext: TEST_PLAINTEXT_KEY.toString('base64') 38 | }) 39 | 40 | index.encrypt('hello', { key: 'alias/common', region: 'eu-west-1' }, function (err, res) { 41 | expect(err).to.equal(null) 42 | expect(res).to.be.an('object') 43 | expect(res.EncryptedData).to.be.a('string') 44 | expect(res.EncryptedDataKey).to.equal(TEST_ENCRYPTED_KEY.toString('base64')) 45 | expect(res.EncryptionContext).to.deep.equal({}) 46 | expect(res.Iv).to.be.a('string') 47 | 48 | expect(generateDataKeyStub).to.have.been.calledWith({ 49 | KeySpec: 'AES_128', 50 | KeyId: 'alias/common', 51 | EncryptionContext: {} 52 | }) 53 | 54 | done() 55 | }) 56 | }) 57 | 58 | it('should use encryption context properly', function (done) { 59 | generateDataKeyStub.yields(undefined, { 60 | CiphertextBlob: TEST_ENCRYPTED_KEY, 61 | Plaintext: TEST_PLAINTEXT_KEY.toString('base64') 62 | }) 63 | 64 | const opts = { 65 | key: 'alias/common', 66 | region: 'eu-west-1', 67 | encryptionContext: { abc: 'def' } 68 | } 69 | 70 | index.encrypt('hello', opts, function (err, res) { 71 | expect(err).to.equal(null) 72 | expect(res).to.be.an('object') 73 | expect(res.EncryptedData).to.be.a('string') 74 | expect(res.EncryptedDataKey).to.equal(TEST_ENCRYPTED_KEY.toString('base64')) 75 | expect(res.EncryptionContext).to.deep.equal({ abc: 'def' }) 76 | expect(res.Iv).to.be.a('string') 77 | 78 | expect(generateDataKeyStub).to.have.been.calledWith({ 79 | KeySpec: 'AES_128', 80 | KeyId: 'alias/common', 81 | EncryptionContext: { abc: 'def' } 82 | }) 83 | 84 | done() 85 | }) 86 | }) 87 | 88 | it('should call the callback with error if KMS gives an error', function (done) { 89 | generateDataKeyStub.yields(new Error('hello')) 90 | index.encrypt('hello', { key: 'alias/common1', region: 'eu-west-1' }, (err, res) => { 91 | expect(err).to.be.an('error') 92 | expect(res).to.equal(undefined) 93 | done() 94 | }) 95 | }) 96 | }) 97 | 98 | describe('decrypt function', function () { 99 | afterEach(() => { 100 | decryptStub.reset() 101 | }) 102 | 103 | it('should call the callback with error if KMS gives an error', function (done) { 104 | decryptStub.yields(new Error('hello')) 105 | index.decrypt(TEST_DATA, { region: 'eu-west-1' }, (err, res) => { 106 | expect(err).to.be.an('error') 107 | expect(res).to.equal(undefined) 108 | done() 109 | }) 110 | }) 111 | 112 | it('should decrypt data properly', function (done) { 113 | decryptStub.yields(undefined, { 114 | Plaintext: TEST_PLAINTEXT_KEY 115 | }) 116 | 117 | const message = { 118 | EncryptedData: 'aVA+gdKlKhurE791OKA7Cg==', 119 | EncryptedDataKey: '4Fw134aB+YsfzuWbzI4NLg==', 120 | EncryptionContext: {}, 121 | Iv: 'd16490194f8b57bb1c1d6ba8ba10125e' 122 | } 123 | 124 | index.decrypt(message, { region: 'eu-west-1' }, function (err, res) { 125 | expect(err).to.equal(null) 126 | expect(res).to.be.a('string') 127 | expect(res).to.equal('hello') 128 | 129 | expect(decryptStub).to.have.been.calledWith({ 130 | CiphertextBlob: Buffer.from(message.EncryptedDataKey, 'base64'), 131 | EncryptionContext: {} 132 | }) 133 | done() 134 | }) 135 | }) 136 | 137 | it('should use encryption context properly', function (done) { 138 | decryptStub.yields(undefined, { 139 | Plaintext: TEST_PLAINTEXT_KEY 140 | }) 141 | 142 | const message = { 143 | EncryptedData: 'aVA+gdKlKhurE791OKA7Cg==', 144 | EncryptedDataKey: '4Fw134aB+YsfzuWbzI4NLg==', 145 | EncryptionContext: { abc: 'test' }, 146 | Iv: 'd16490194f8b57bb1c1d6ba8ba10125e' 147 | } 148 | 149 | index.decrypt(message, { region: 'eu-west-1' }, function (err, res) { 150 | expect(err).to.equal(null) 151 | expect(res).to.be.a('string') 152 | expect(res).to.equal('hello') 153 | 154 | expect(decryptStub).to.have.been.calledWith({ 155 | CiphertextBlob: Buffer.from(message.EncryptedDataKey, 'base64'), 156 | EncryptionContext: { abc: 'test' } 157 | }) 158 | done() 159 | }) 160 | }) 161 | }) 162 | }) 163 | -------------------------------------------------------------------------------- /python/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2021 Sami Jaktholm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | ## Build targets 2 | .PHONY: lint test format lint-pylint lint-black lint-mypy lint-bandit 3 | test: 4 | poetry run pytest -vv --log-level=DEBUG --cov kmscrypt --cov-report term-missing 5 | 6 | lint: lint-pylint lint-black lint-mypy lint-bandit 7 | lint-pylint: 8 | poetry run pylint --max-line-length=120 --score=n kmscrypt tests 9 | lint-black: 10 | poetry run black --check kmscrypt tests 11 | lint-mypy: 12 | poetry run mypy kmscrypt 13 | lint-bandit: 14 | poetry run bandit -q -r kmscrypt 15 | 16 | format: 17 | poetry run black kmscrypt tests -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | Utility for encrypting and decrypting secrets with the AWS KMS service. 2 | 3 | # Installation 4 | 5 | Install from PyPI with pip 6 | 7 | ```bash 8 | pip install aws-kms-crypt 9 | ``` 10 | 11 | # Usage 12 | 13 | Requires Python 3.8 or newer. 14 | 15 | ```python 16 | import kmscrypt 17 | 18 | # Encrypting Data 19 | >>> result = kmscrypt.encrypt('secretp4ssw0rd!', key_id='alias/common', encryption_context={ 20 | ... 'purpose': 'automation' 21 | ... }) 22 | >>> result 23 | { 24 | "EncryptedDataKey": "AQIDAHhyrbU/fPcQ+a8pJiYC", 25 | "Iv": "689806fe9d571afeffa4c7c24247c766", 26 | "EncryptedData": "YRjZDQ2KzcEAZqUy7SpWWA==", 27 | "EncryptionContext": { 28 | "purpose": "automation" 29 | } 30 | } 31 | 32 | # Decrypting data 33 | >>> kmscrypt.decrypt(result) 34 | b'secretp4ssw0rd!' 35 | ``` 36 | 37 | # Changelog 38 | 39 | ## v3.0.0 (2024-01-31) 40 | 41 | * Dropped Python 3.7 support. 42 | 43 | ## v2.0.0 (2022-09-15) 44 | 45 | * Dropped Python 3.6 support. 46 | 47 | ## v1.0.0 (2021-09-25) 48 | 49 | * Dropped Python 2.7 support. 50 | * Replaced [pycrypto](https://www.dlitz.net/software/pycrypto/) with [cryptography](https://cryptography.io/en/latest/). 51 | 52 | # License 53 | 54 | MIT -------------------------------------------------------------------------------- /python/kmscrypt/__init__.py: -------------------------------------------------------------------------------- 1 | """Library to encrypt and decrypt secrets with AWS KMS.""" 2 | 3 | from kmscrypt.crypto import decrypt, encrypt 4 | -------------------------------------------------------------------------------- /python/kmscrypt/__main__.py: -------------------------------------------------------------------------------- 1 | """Simple CLI to encrypt and decrypt secrets with AWS KMS.""" 2 | 3 | import fileinput 4 | import json 5 | import sys 6 | 7 | from kmscrypt.crypto import decrypt, encrypt 8 | 9 | 10 | def main(): 11 | """CLI entrypoint.""" 12 | data = "".join(list(fileinput.input())) 13 | 14 | try: 15 | parsed = json.loads(data) 16 | except ValueError: 17 | parsed = {} 18 | 19 | if "EncryptedData" in parsed: 20 | print("Decrypting data...", file=sys.stderr) 21 | print(decrypt(parsed)) 22 | else: 23 | print("Encrypting data...", file=sys.stderr) 24 | print(json.dumps(encrypt(data, key_id="alias/common"), indent=2)) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /python/kmscrypt/crypto.py: -------------------------------------------------------------------------------- 1 | """Main module containing encryption and decryption routines.""" 2 | 3 | import base64 4 | import binascii 5 | import os 6 | 7 | from typing import Dict, Final, Optional, Union, TypedDict 8 | 9 | import boto3 10 | import boto3.session 11 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 12 | from cryptography.hazmat.primitives import padding 13 | 14 | 15 | AES_IV_BYTES = 16 16 | AES_KEY_BYTES = 16 # 128 bits 17 | AES_BLOCK_SIZE = 128 # bits 18 | AES_KEY_SPEC: Final = "AES_128" 19 | 20 | 21 | class EncryptedData(TypedDict): 22 | """Dict containing encrypted data and information needed to decrypt it.""" 23 | 24 | EncryptedData: str 25 | EncryptedDataKey: str 26 | EncryptionContext: Dict[str, str] 27 | Iv: str 28 | 29 | 30 | def decrypt( 31 | data: EncryptedData, session: Optional[boto3.session.Session] = None 32 | ) -> bytes: 33 | """Decrypts previously encrypted data. 34 | 35 | Args: 36 | data: The (JSON) object returned by earlier call to encrypt(). 37 | session: boto3.Session object to use for KMS calls. 38 | 39 | Returns: 40 | The encrypted secret as bytes. 41 | """ 42 | # Decode payload 43 | ciphertext = base64.b64decode(data["EncryptedData"]) 44 | encrypted_data_key = base64.b64decode(data["EncryptedDataKey"]) 45 | initialization_vector = binascii.unhexlify(data["Iv"]) 46 | 47 | # Decrypt key 48 | kms = (session or boto3.session.Session()).client("kms") 49 | res = kms.decrypt( 50 | CiphertextBlob=encrypted_data_key, 51 | EncryptionContext=data["EncryptionContext"], 52 | ) 53 | key = res["Plaintext"] 54 | 55 | # Decrypt data 56 | cipher = Cipher(algorithms.AES(key), modes.CBC(initialization_vector)) 57 | decryptor = cipher.decryptor() 58 | padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize() 59 | 60 | # Unpad data 61 | unpadder = padding.PKCS7(AES_BLOCK_SIZE).unpadder() 62 | plaintext = unpadder.update(padded_plaintext) + unpadder.finalize() 63 | 64 | return plaintext 65 | 66 | 67 | def encrypt( 68 | data: Union[str, bytes], 69 | key_id: str, 70 | encryption_context: Optional[Dict[str, str]] = None, 71 | session: Optional[boto3.session.Session] = None, 72 | ) -> EncryptedData: 73 | """Encrypts a given data string. 74 | 75 | Args: 76 | data: The secret to encrypt. It can be str / unicode (py2) or 77 | str / bytes (py3). 78 | key_id: ID, ARN, alias or alias ARN of the KMS key to encrypt the 79 | data with 80 | encryption_context: Optional encryption context (key-value dict) 81 | for KMS 82 | session: boto3.Session object to use for KMS calls. 83 | 84 | Returns: 85 | A dictionary containing the data that is required to decrypt the 86 | secret. 87 | """ 88 | 89 | if not encryption_context: 90 | encryption_context = {} 91 | 92 | # Generate key 93 | kms = (session or boto3.session.Session()).client("kms") 94 | res = kms.generate_data_key( 95 | KeyId=key_id, KeySpec=AES_KEY_SPEC, EncryptionContext=encryption_context 96 | ) 97 | key = res["Plaintext"] 98 | 99 | # And initialization vector 100 | initialization_vector = os.urandom(16) 101 | 102 | # Ensure data is bytes 103 | if isinstance(data, str): 104 | data = data.encode("utf-8") 105 | 106 | # Pad data 107 | padder = padding.PKCS7(AES_BLOCK_SIZE).padder() 108 | padded_data = padder.update(data) + padder.finalize() 109 | 110 | # Encrypt data 111 | cipher = Cipher(algorithms.AES(key), modes.CBC(initialization_vector)) 112 | encryptor = cipher.encryptor() 113 | ciphertext = encryptor.update(padded_data) + encryptor.finalize() 114 | 115 | return { 116 | "EncryptedData": base64.b64encode(ciphertext).decode(), 117 | "EncryptedDataKey": base64.b64encode(res["CiphertextBlob"]).decode(), 118 | "EncryptionContext": encryption_context, 119 | "Iv": binascii.b2a_hex(initialization_vector).decode(), 120 | } 121 | -------------------------------------------------------------------------------- /python/poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "astroid" 5 | version = "3.2.2" 6 | description = "An abstract syntax tree for Python with inference support." 7 | optional = false 8 | python-versions = ">=3.8.0" 9 | files = [ 10 | {file = "astroid-3.2.2-py3-none-any.whl", hash = "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0"}, 11 | {file = "astroid-3.2.2.tar.gz", hash = "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94"}, 12 | ] 13 | 14 | [package.dependencies] 15 | typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} 16 | 17 | [[package]] 18 | name = "bandit" 19 | version = "1.7.9" 20 | description = "Security oriented static analyser for python code." 21 | optional = false 22 | python-versions = ">=3.8" 23 | files = [ 24 | {file = "bandit-1.7.9-py3-none-any.whl", hash = "sha256:52077cb339000f337fb25f7e045995c4ad01511e716e5daac37014b9752de8ec"}, 25 | {file = "bandit-1.7.9.tar.gz", hash = "sha256:7c395a436743018f7be0a4cbb0a4ea9b902b6d87264ddecf8cfdc73b4f78ff61"}, 26 | ] 27 | 28 | [package.dependencies] 29 | colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} 30 | PyYAML = ">=5.3.1" 31 | rich = "*" 32 | stevedore = ">=1.20.0" 33 | 34 | [package.extras] 35 | baseline = ["GitPython (>=3.1.30)"] 36 | sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"] 37 | test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"] 38 | toml = ["tomli (>=1.1.0)"] 39 | yaml = ["PyYAML"] 40 | 41 | [[package]] 42 | name = "black" 43 | version = "24.4.2" 44 | description = "The uncompromising code formatter." 45 | optional = false 46 | python-versions = ">=3.8" 47 | files = [ 48 | {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, 49 | {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, 50 | {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, 51 | {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, 52 | {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, 53 | {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, 54 | {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, 55 | {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, 56 | {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, 57 | {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, 58 | {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, 59 | {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, 60 | {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, 61 | {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, 62 | {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, 63 | {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, 64 | {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, 65 | {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, 66 | {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, 67 | {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, 68 | {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, 69 | {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, 70 | ] 71 | 72 | [package.dependencies] 73 | click = ">=8.0.0" 74 | mypy-extensions = ">=0.4.3" 75 | packaging = ">=22.0" 76 | pathspec = ">=0.9.0" 77 | platformdirs = ">=2" 78 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 79 | typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} 80 | 81 | [package.extras] 82 | colorama = ["colorama (>=0.4.3)"] 83 | d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] 84 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 85 | uvloop = ["uvloop (>=0.15.2)"] 86 | 87 | [[package]] 88 | name = "boto3" 89 | version = "1.34.144" 90 | description = "The AWS SDK for Python" 91 | optional = false 92 | python-versions = ">=3.8" 93 | files = [ 94 | {file = "boto3-1.34.144-py3-none-any.whl", hash = "sha256:b8433d481d50b68a0162c0379c0dd4aabfc3d1ad901800beb5b87815997511c1"}, 95 | {file = "boto3-1.34.144.tar.gz", hash = "sha256:2f3e88b10b8fcc5f6100a9d74cd28230edc9d4fa226d99dd40a3ab38ac213673"}, 96 | ] 97 | 98 | [package.dependencies] 99 | botocore = ">=1.34.144,<1.35.0" 100 | jmespath = ">=0.7.1,<2.0.0" 101 | s3transfer = ">=0.10.0,<0.11.0" 102 | 103 | [package.extras] 104 | crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] 105 | 106 | [[package]] 107 | name = "boto3-stubs" 108 | version = "1.34.144" 109 | description = "Type annotations for boto3 1.34.144 generated with mypy-boto3-builder 7.25.0" 110 | optional = false 111 | python-versions = ">=3.8" 112 | files = [ 113 | {file = "boto3_stubs-1.34.144-py3-none-any.whl", hash = "sha256:4fc2f8d41ee7fb4952dc8d6a27bb616e7c0c5f9b71f3ad6d179f27df1bb69b0c"}, 114 | {file = "boto3_stubs-1.34.144.tar.gz", hash = "sha256:c19d0c4386ec160e6c06567b960b6f7c765acc4ed40f01f371c8e7a0b514520b"}, 115 | ] 116 | 117 | [package.dependencies] 118 | botocore-stubs = "*" 119 | mypy-boto3-kms = {version = ">=1.34.0,<1.35.0", optional = true, markers = "extra == \"kms\""} 120 | types-s3transfer = "*" 121 | typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} 122 | 123 | [package.extras] 124 | accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.34.0,<1.35.0)"] 125 | account = ["mypy-boto3-account (>=1.34.0,<1.35.0)"] 126 | acm = ["mypy-boto3-acm (>=1.34.0,<1.35.0)"] 127 | acm-pca = ["mypy-boto3-acm-pca (>=1.34.0,<1.35.0)"] 128 | all = ["mypy-boto3-accessanalyzer (>=1.34.0,<1.35.0)", "mypy-boto3-account (>=1.34.0,<1.35.0)", "mypy-boto3-acm (>=1.34.0,<1.35.0)", "mypy-boto3-acm-pca (>=1.34.0,<1.35.0)", "mypy-boto3-amp (>=1.34.0,<1.35.0)", "mypy-boto3-amplify (>=1.34.0,<1.35.0)", "mypy-boto3-amplifybackend (>=1.34.0,<1.35.0)", "mypy-boto3-amplifyuibuilder (>=1.34.0,<1.35.0)", "mypy-boto3-apigateway (>=1.34.0,<1.35.0)", "mypy-boto3-apigatewaymanagementapi (>=1.34.0,<1.35.0)", "mypy-boto3-apigatewayv2 (>=1.34.0,<1.35.0)", "mypy-boto3-appconfig (>=1.34.0,<1.35.0)", "mypy-boto3-appconfigdata (>=1.34.0,<1.35.0)", "mypy-boto3-appfabric (>=1.34.0,<1.35.0)", "mypy-boto3-appflow (>=1.34.0,<1.35.0)", "mypy-boto3-appintegrations (>=1.34.0,<1.35.0)", "mypy-boto3-application-autoscaling (>=1.34.0,<1.35.0)", "mypy-boto3-application-insights (>=1.34.0,<1.35.0)", "mypy-boto3-application-signals (>=1.34.0,<1.35.0)", "mypy-boto3-applicationcostprofiler (>=1.34.0,<1.35.0)", "mypy-boto3-appmesh (>=1.34.0,<1.35.0)", "mypy-boto3-apprunner (>=1.34.0,<1.35.0)", "mypy-boto3-appstream (>=1.34.0,<1.35.0)", "mypy-boto3-appsync (>=1.34.0,<1.35.0)", "mypy-boto3-apptest (>=1.34.0,<1.35.0)", "mypy-boto3-arc-zonal-shift (>=1.34.0,<1.35.0)", "mypy-boto3-artifact (>=1.34.0,<1.35.0)", "mypy-boto3-athena (>=1.34.0,<1.35.0)", "mypy-boto3-auditmanager (>=1.34.0,<1.35.0)", "mypy-boto3-autoscaling (>=1.34.0,<1.35.0)", "mypy-boto3-autoscaling-plans (>=1.34.0,<1.35.0)", "mypy-boto3-b2bi (>=1.34.0,<1.35.0)", "mypy-boto3-backup (>=1.34.0,<1.35.0)", "mypy-boto3-backup-gateway (>=1.34.0,<1.35.0)", "mypy-boto3-batch (>=1.34.0,<1.35.0)", "mypy-boto3-bcm-data-exports (>=1.34.0,<1.35.0)", "mypy-boto3-bedrock (>=1.34.0,<1.35.0)", "mypy-boto3-bedrock-agent (>=1.34.0,<1.35.0)", "mypy-boto3-bedrock-agent-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-bedrock-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-billingconductor (>=1.34.0,<1.35.0)", "mypy-boto3-braket (>=1.34.0,<1.35.0)", "mypy-boto3-budgets (>=1.34.0,<1.35.0)", "mypy-boto3-ce (>=1.34.0,<1.35.0)", "mypy-boto3-chatbot (>=1.34.0,<1.35.0)", "mypy-boto3-chime (>=1.34.0,<1.35.0)", "mypy-boto3-chime-sdk-identity (>=1.34.0,<1.35.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.34.0,<1.35.0)", "mypy-boto3-chime-sdk-meetings (>=1.34.0,<1.35.0)", "mypy-boto3-chime-sdk-messaging (>=1.34.0,<1.35.0)", "mypy-boto3-chime-sdk-voice (>=1.34.0,<1.35.0)", "mypy-boto3-cleanrooms (>=1.34.0,<1.35.0)", "mypy-boto3-cleanroomsml (>=1.34.0,<1.35.0)", "mypy-boto3-cloud9 (>=1.34.0,<1.35.0)", "mypy-boto3-cloudcontrol (>=1.34.0,<1.35.0)", "mypy-boto3-clouddirectory (>=1.34.0,<1.35.0)", "mypy-boto3-cloudformation (>=1.34.0,<1.35.0)", "mypy-boto3-cloudfront (>=1.34.0,<1.35.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.34.0,<1.35.0)", "mypy-boto3-cloudhsm (>=1.34.0,<1.35.0)", "mypy-boto3-cloudhsmv2 (>=1.34.0,<1.35.0)", "mypy-boto3-cloudsearch (>=1.34.0,<1.35.0)", "mypy-boto3-cloudsearchdomain (>=1.34.0,<1.35.0)", "mypy-boto3-cloudtrail (>=1.34.0,<1.35.0)", "mypy-boto3-cloudtrail-data (>=1.34.0,<1.35.0)", "mypy-boto3-cloudwatch (>=1.34.0,<1.35.0)", "mypy-boto3-codeartifact (>=1.34.0,<1.35.0)", "mypy-boto3-codebuild (>=1.34.0,<1.35.0)", "mypy-boto3-codecatalyst (>=1.34.0,<1.35.0)", "mypy-boto3-codecommit (>=1.34.0,<1.35.0)", "mypy-boto3-codeconnections (>=1.34.0,<1.35.0)", "mypy-boto3-codedeploy (>=1.34.0,<1.35.0)", "mypy-boto3-codeguru-reviewer (>=1.34.0,<1.35.0)", "mypy-boto3-codeguru-security (>=1.34.0,<1.35.0)", "mypy-boto3-codeguruprofiler (>=1.34.0,<1.35.0)", "mypy-boto3-codepipeline (>=1.34.0,<1.35.0)", "mypy-boto3-codestar (>=1.34.0,<1.35.0)", "mypy-boto3-codestar-connections (>=1.34.0,<1.35.0)", "mypy-boto3-codestar-notifications (>=1.34.0,<1.35.0)", "mypy-boto3-cognito-identity (>=1.34.0,<1.35.0)", "mypy-boto3-cognito-idp (>=1.34.0,<1.35.0)", "mypy-boto3-cognito-sync (>=1.34.0,<1.35.0)", "mypy-boto3-comprehend (>=1.34.0,<1.35.0)", "mypy-boto3-comprehendmedical (>=1.34.0,<1.35.0)", "mypy-boto3-compute-optimizer (>=1.34.0,<1.35.0)", "mypy-boto3-config (>=1.34.0,<1.35.0)", "mypy-boto3-connect (>=1.34.0,<1.35.0)", "mypy-boto3-connect-contact-lens (>=1.34.0,<1.35.0)", "mypy-boto3-connectcampaigns (>=1.34.0,<1.35.0)", "mypy-boto3-connectcases (>=1.34.0,<1.35.0)", "mypy-boto3-connectparticipant (>=1.34.0,<1.35.0)", "mypy-boto3-controlcatalog (>=1.34.0,<1.35.0)", "mypy-boto3-controltower (>=1.34.0,<1.35.0)", "mypy-boto3-cost-optimization-hub (>=1.34.0,<1.35.0)", "mypy-boto3-cur (>=1.34.0,<1.35.0)", "mypy-boto3-customer-profiles (>=1.34.0,<1.35.0)", "mypy-boto3-databrew (>=1.34.0,<1.35.0)", "mypy-boto3-dataexchange (>=1.34.0,<1.35.0)", "mypy-boto3-datapipeline (>=1.34.0,<1.35.0)", "mypy-boto3-datasync (>=1.34.0,<1.35.0)", "mypy-boto3-datazone (>=1.34.0,<1.35.0)", "mypy-boto3-dax (>=1.34.0,<1.35.0)", "mypy-boto3-deadline (>=1.34.0,<1.35.0)", "mypy-boto3-detective (>=1.34.0,<1.35.0)", "mypy-boto3-devicefarm (>=1.34.0,<1.35.0)", "mypy-boto3-devops-guru (>=1.34.0,<1.35.0)", "mypy-boto3-directconnect (>=1.34.0,<1.35.0)", "mypy-boto3-discovery (>=1.34.0,<1.35.0)", "mypy-boto3-dlm (>=1.34.0,<1.35.0)", "mypy-boto3-dms (>=1.34.0,<1.35.0)", "mypy-boto3-docdb (>=1.34.0,<1.35.0)", "mypy-boto3-docdb-elastic (>=1.34.0,<1.35.0)", "mypy-boto3-drs (>=1.34.0,<1.35.0)", "mypy-boto3-ds (>=1.34.0,<1.35.0)", "mypy-boto3-dynamodb (>=1.34.0,<1.35.0)", "mypy-boto3-dynamodbstreams (>=1.34.0,<1.35.0)", "mypy-boto3-ebs (>=1.34.0,<1.35.0)", "mypy-boto3-ec2 (>=1.34.0,<1.35.0)", "mypy-boto3-ec2-instance-connect (>=1.34.0,<1.35.0)", "mypy-boto3-ecr (>=1.34.0,<1.35.0)", "mypy-boto3-ecr-public (>=1.34.0,<1.35.0)", "mypy-boto3-ecs (>=1.34.0,<1.35.0)", "mypy-boto3-efs (>=1.34.0,<1.35.0)", "mypy-boto3-eks (>=1.34.0,<1.35.0)", "mypy-boto3-eks-auth (>=1.34.0,<1.35.0)", "mypy-boto3-elastic-inference (>=1.34.0,<1.35.0)", "mypy-boto3-elasticache (>=1.34.0,<1.35.0)", "mypy-boto3-elasticbeanstalk (>=1.34.0,<1.35.0)", "mypy-boto3-elastictranscoder (>=1.34.0,<1.35.0)", "mypy-boto3-elb (>=1.34.0,<1.35.0)", "mypy-boto3-elbv2 (>=1.34.0,<1.35.0)", "mypy-boto3-emr (>=1.34.0,<1.35.0)", "mypy-boto3-emr-containers (>=1.34.0,<1.35.0)", "mypy-boto3-emr-serverless (>=1.34.0,<1.35.0)", "mypy-boto3-entityresolution (>=1.34.0,<1.35.0)", "mypy-boto3-es (>=1.34.0,<1.35.0)", "mypy-boto3-events (>=1.34.0,<1.35.0)", "mypy-boto3-evidently (>=1.34.0,<1.35.0)", "mypy-boto3-finspace (>=1.34.0,<1.35.0)", "mypy-boto3-finspace-data (>=1.34.0,<1.35.0)", "mypy-boto3-firehose (>=1.34.0,<1.35.0)", "mypy-boto3-fis (>=1.34.0,<1.35.0)", "mypy-boto3-fms (>=1.34.0,<1.35.0)", "mypy-boto3-forecast (>=1.34.0,<1.35.0)", "mypy-boto3-forecastquery (>=1.34.0,<1.35.0)", "mypy-boto3-frauddetector (>=1.34.0,<1.35.0)", "mypy-boto3-freetier (>=1.34.0,<1.35.0)", "mypy-boto3-fsx (>=1.34.0,<1.35.0)", "mypy-boto3-gamelift (>=1.34.0,<1.35.0)", "mypy-boto3-glacier (>=1.34.0,<1.35.0)", "mypy-boto3-globalaccelerator (>=1.34.0,<1.35.0)", "mypy-boto3-glue (>=1.34.0,<1.35.0)", "mypy-boto3-grafana (>=1.34.0,<1.35.0)", "mypy-boto3-greengrass (>=1.34.0,<1.35.0)", "mypy-boto3-greengrassv2 (>=1.34.0,<1.35.0)", "mypy-boto3-groundstation (>=1.34.0,<1.35.0)", "mypy-boto3-guardduty (>=1.34.0,<1.35.0)", "mypy-boto3-health (>=1.34.0,<1.35.0)", "mypy-boto3-healthlake (>=1.34.0,<1.35.0)", "mypy-boto3-iam (>=1.34.0,<1.35.0)", "mypy-boto3-identitystore (>=1.34.0,<1.35.0)", "mypy-boto3-imagebuilder (>=1.34.0,<1.35.0)", "mypy-boto3-importexport (>=1.34.0,<1.35.0)", "mypy-boto3-inspector (>=1.34.0,<1.35.0)", "mypy-boto3-inspector-scan (>=1.34.0,<1.35.0)", "mypy-boto3-inspector2 (>=1.34.0,<1.35.0)", "mypy-boto3-internetmonitor (>=1.34.0,<1.35.0)", "mypy-boto3-iot (>=1.34.0,<1.35.0)", "mypy-boto3-iot-data (>=1.34.0,<1.35.0)", "mypy-boto3-iot-jobs-data (>=1.34.0,<1.35.0)", "mypy-boto3-iot1click-devices (>=1.34.0,<1.35.0)", "mypy-boto3-iot1click-projects (>=1.34.0,<1.35.0)", "mypy-boto3-iotanalytics (>=1.34.0,<1.35.0)", "mypy-boto3-iotdeviceadvisor (>=1.34.0,<1.35.0)", "mypy-boto3-iotevents (>=1.34.0,<1.35.0)", "mypy-boto3-iotevents-data (>=1.34.0,<1.35.0)", "mypy-boto3-iotfleethub (>=1.34.0,<1.35.0)", "mypy-boto3-iotfleetwise (>=1.34.0,<1.35.0)", "mypy-boto3-iotsecuretunneling (>=1.34.0,<1.35.0)", "mypy-boto3-iotsitewise (>=1.34.0,<1.35.0)", "mypy-boto3-iotthingsgraph (>=1.34.0,<1.35.0)", "mypy-boto3-iottwinmaker (>=1.34.0,<1.35.0)", "mypy-boto3-iotwireless (>=1.34.0,<1.35.0)", "mypy-boto3-ivs (>=1.34.0,<1.35.0)", "mypy-boto3-ivs-realtime (>=1.34.0,<1.35.0)", "mypy-boto3-ivschat (>=1.34.0,<1.35.0)", "mypy-boto3-kafka (>=1.34.0,<1.35.0)", "mypy-boto3-kafkaconnect (>=1.34.0,<1.35.0)", "mypy-boto3-kendra (>=1.34.0,<1.35.0)", "mypy-boto3-kendra-ranking (>=1.34.0,<1.35.0)", "mypy-boto3-keyspaces (>=1.34.0,<1.35.0)", "mypy-boto3-kinesis (>=1.34.0,<1.35.0)", "mypy-boto3-kinesis-video-archived-media (>=1.34.0,<1.35.0)", "mypy-boto3-kinesis-video-media (>=1.34.0,<1.35.0)", "mypy-boto3-kinesis-video-signaling (>=1.34.0,<1.35.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.34.0,<1.35.0)", "mypy-boto3-kinesisanalytics (>=1.34.0,<1.35.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.34.0,<1.35.0)", "mypy-boto3-kinesisvideo (>=1.34.0,<1.35.0)", "mypy-boto3-kms (>=1.34.0,<1.35.0)", "mypy-boto3-lakeformation (>=1.34.0,<1.35.0)", "mypy-boto3-lambda (>=1.34.0,<1.35.0)", "mypy-boto3-launch-wizard (>=1.34.0,<1.35.0)", "mypy-boto3-lex-models (>=1.34.0,<1.35.0)", "mypy-boto3-lex-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-lexv2-models (>=1.34.0,<1.35.0)", "mypy-boto3-lexv2-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-license-manager (>=1.34.0,<1.35.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.34.0,<1.35.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.34.0,<1.35.0)", "mypy-boto3-lightsail (>=1.34.0,<1.35.0)", "mypy-boto3-location (>=1.34.0,<1.35.0)", "mypy-boto3-logs (>=1.34.0,<1.35.0)", "mypy-boto3-lookoutequipment (>=1.34.0,<1.35.0)", "mypy-boto3-lookoutmetrics (>=1.34.0,<1.35.0)", "mypy-boto3-lookoutvision (>=1.34.0,<1.35.0)", "mypy-boto3-m2 (>=1.34.0,<1.35.0)", "mypy-boto3-machinelearning (>=1.34.0,<1.35.0)", "mypy-boto3-macie2 (>=1.34.0,<1.35.0)", "mypy-boto3-mailmanager (>=1.34.0,<1.35.0)", "mypy-boto3-managedblockchain (>=1.34.0,<1.35.0)", "mypy-boto3-managedblockchain-query (>=1.34.0,<1.35.0)", "mypy-boto3-marketplace-agreement (>=1.34.0,<1.35.0)", "mypy-boto3-marketplace-catalog (>=1.34.0,<1.35.0)", "mypy-boto3-marketplace-deployment (>=1.34.0,<1.35.0)", "mypy-boto3-marketplace-entitlement (>=1.34.0,<1.35.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.34.0,<1.35.0)", "mypy-boto3-mediaconnect (>=1.34.0,<1.35.0)", "mypy-boto3-mediaconvert (>=1.34.0,<1.35.0)", "mypy-boto3-medialive (>=1.34.0,<1.35.0)", "mypy-boto3-mediapackage (>=1.34.0,<1.35.0)", "mypy-boto3-mediapackage-vod (>=1.34.0,<1.35.0)", "mypy-boto3-mediapackagev2 (>=1.34.0,<1.35.0)", "mypy-boto3-mediastore (>=1.34.0,<1.35.0)", "mypy-boto3-mediastore-data (>=1.34.0,<1.35.0)", "mypy-boto3-mediatailor (>=1.34.0,<1.35.0)", "mypy-boto3-medical-imaging (>=1.34.0,<1.35.0)", "mypy-boto3-memorydb (>=1.34.0,<1.35.0)", "mypy-boto3-meteringmarketplace (>=1.34.0,<1.35.0)", "mypy-boto3-mgh (>=1.34.0,<1.35.0)", "mypy-boto3-mgn (>=1.34.0,<1.35.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.34.0,<1.35.0)", "mypy-boto3-migrationhub-config (>=1.34.0,<1.35.0)", "mypy-boto3-migrationhuborchestrator (>=1.34.0,<1.35.0)", "mypy-boto3-migrationhubstrategy (>=1.34.0,<1.35.0)", "mypy-boto3-mobile (>=1.34.0,<1.35.0)", "mypy-boto3-mq (>=1.34.0,<1.35.0)", "mypy-boto3-mturk (>=1.34.0,<1.35.0)", "mypy-boto3-mwaa (>=1.34.0,<1.35.0)", "mypy-boto3-neptune (>=1.34.0,<1.35.0)", "mypy-boto3-neptune-graph (>=1.34.0,<1.35.0)", "mypy-boto3-neptunedata (>=1.34.0,<1.35.0)", "mypy-boto3-network-firewall (>=1.34.0,<1.35.0)", "mypy-boto3-networkmanager (>=1.34.0,<1.35.0)", "mypy-boto3-networkmonitor (>=1.34.0,<1.35.0)", "mypy-boto3-nimble (>=1.34.0,<1.35.0)", "mypy-boto3-oam (>=1.34.0,<1.35.0)", "mypy-boto3-omics (>=1.34.0,<1.35.0)", "mypy-boto3-opensearch (>=1.34.0,<1.35.0)", "mypy-boto3-opensearchserverless (>=1.34.0,<1.35.0)", "mypy-boto3-opsworks (>=1.34.0,<1.35.0)", "mypy-boto3-opsworkscm (>=1.34.0,<1.35.0)", "mypy-boto3-organizations (>=1.34.0,<1.35.0)", "mypy-boto3-osis (>=1.34.0,<1.35.0)", "mypy-boto3-outposts (>=1.34.0,<1.35.0)", "mypy-boto3-panorama (>=1.34.0,<1.35.0)", "mypy-boto3-payment-cryptography (>=1.34.0,<1.35.0)", "mypy-boto3-payment-cryptography-data (>=1.34.0,<1.35.0)", "mypy-boto3-pca-connector-ad (>=1.34.0,<1.35.0)", "mypy-boto3-pca-connector-scep (>=1.34.0,<1.35.0)", "mypy-boto3-personalize (>=1.34.0,<1.35.0)", "mypy-boto3-personalize-events (>=1.34.0,<1.35.0)", "mypy-boto3-personalize-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-pi (>=1.34.0,<1.35.0)", "mypy-boto3-pinpoint (>=1.34.0,<1.35.0)", "mypy-boto3-pinpoint-email (>=1.34.0,<1.35.0)", "mypy-boto3-pinpoint-sms-voice (>=1.34.0,<1.35.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.34.0,<1.35.0)", "mypy-boto3-pipes (>=1.34.0,<1.35.0)", "mypy-boto3-polly (>=1.34.0,<1.35.0)", "mypy-boto3-pricing (>=1.34.0,<1.35.0)", "mypy-boto3-privatenetworks (>=1.34.0,<1.35.0)", "mypy-boto3-proton (>=1.34.0,<1.35.0)", "mypy-boto3-qapps (>=1.34.0,<1.35.0)", "mypy-boto3-qbusiness (>=1.34.0,<1.35.0)", "mypy-boto3-qconnect (>=1.34.0,<1.35.0)", "mypy-boto3-qldb (>=1.34.0,<1.35.0)", "mypy-boto3-qldb-session (>=1.34.0,<1.35.0)", "mypy-boto3-quicksight (>=1.34.0,<1.35.0)", "mypy-boto3-ram (>=1.34.0,<1.35.0)", "mypy-boto3-rbin (>=1.34.0,<1.35.0)", "mypy-boto3-rds (>=1.34.0,<1.35.0)", "mypy-boto3-rds-data (>=1.34.0,<1.35.0)", "mypy-boto3-redshift (>=1.34.0,<1.35.0)", "mypy-boto3-redshift-data (>=1.34.0,<1.35.0)", "mypy-boto3-redshift-serverless (>=1.34.0,<1.35.0)", "mypy-boto3-rekognition (>=1.34.0,<1.35.0)", "mypy-boto3-repostspace (>=1.34.0,<1.35.0)", "mypy-boto3-resiliencehub (>=1.34.0,<1.35.0)", "mypy-boto3-resource-explorer-2 (>=1.34.0,<1.35.0)", "mypy-boto3-resource-groups (>=1.34.0,<1.35.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.34.0,<1.35.0)", "mypy-boto3-robomaker (>=1.34.0,<1.35.0)", "mypy-boto3-rolesanywhere (>=1.34.0,<1.35.0)", "mypy-boto3-route53 (>=1.34.0,<1.35.0)", "mypy-boto3-route53-recovery-cluster (>=1.34.0,<1.35.0)", "mypy-boto3-route53-recovery-control-config (>=1.34.0,<1.35.0)", "mypy-boto3-route53-recovery-readiness (>=1.34.0,<1.35.0)", "mypy-boto3-route53domains (>=1.34.0,<1.35.0)", "mypy-boto3-route53profiles (>=1.34.0,<1.35.0)", "mypy-boto3-route53resolver (>=1.34.0,<1.35.0)", "mypy-boto3-rum (>=1.34.0,<1.35.0)", "mypy-boto3-s3 (>=1.34.0,<1.35.0)", "mypy-boto3-s3control (>=1.34.0,<1.35.0)", "mypy-boto3-s3outposts (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker-edge (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker-geospatial (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker-metrics (>=1.34.0,<1.35.0)", "mypy-boto3-sagemaker-runtime (>=1.34.0,<1.35.0)", "mypy-boto3-savingsplans (>=1.34.0,<1.35.0)", "mypy-boto3-scheduler (>=1.34.0,<1.35.0)", "mypy-boto3-schemas (>=1.34.0,<1.35.0)", "mypy-boto3-sdb (>=1.34.0,<1.35.0)", "mypy-boto3-secretsmanager (>=1.34.0,<1.35.0)", "mypy-boto3-securityhub (>=1.34.0,<1.35.0)", "mypy-boto3-securitylake (>=1.34.0,<1.35.0)", "mypy-boto3-serverlessrepo (>=1.34.0,<1.35.0)", "mypy-boto3-service-quotas (>=1.34.0,<1.35.0)", "mypy-boto3-servicecatalog (>=1.34.0,<1.35.0)", "mypy-boto3-servicecatalog-appregistry (>=1.34.0,<1.35.0)", "mypy-boto3-servicediscovery (>=1.34.0,<1.35.0)", "mypy-boto3-ses (>=1.34.0,<1.35.0)", "mypy-boto3-sesv2 (>=1.34.0,<1.35.0)", "mypy-boto3-shield (>=1.34.0,<1.35.0)", "mypy-boto3-signer (>=1.34.0,<1.35.0)", "mypy-boto3-simspaceweaver (>=1.34.0,<1.35.0)", "mypy-boto3-sms (>=1.34.0,<1.35.0)", "mypy-boto3-sms-voice (>=1.34.0,<1.35.0)", "mypy-boto3-snow-device-management (>=1.34.0,<1.35.0)", "mypy-boto3-snowball (>=1.34.0,<1.35.0)", "mypy-boto3-sns (>=1.34.0,<1.35.0)", "mypy-boto3-sqs (>=1.34.0,<1.35.0)", "mypy-boto3-ssm (>=1.34.0,<1.35.0)", "mypy-boto3-ssm-contacts (>=1.34.0,<1.35.0)", "mypy-boto3-ssm-incidents (>=1.34.0,<1.35.0)", "mypy-boto3-ssm-sap (>=1.34.0,<1.35.0)", "mypy-boto3-sso (>=1.34.0,<1.35.0)", "mypy-boto3-sso-admin (>=1.34.0,<1.35.0)", "mypy-boto3-sso-oidc (>=1.34.0,<1.35.0)", "mypy-boto3-stepfunctions (>=1.34.0,<1.35.0)", "mypy-boto3-storagegateway (>=1.34.0,<1.35.0)", "mypy-boto3-sts (>=1.34.0,<1.35.0)", "mypy-boto3-supplychain (>=1.34.0,<1.35.0)", "mypy-boto3-support (>=1.34.0,<1.35.0)", "mypy-boto3-support-app (>=1.34.0,<1.35.0)", "mypy-boto3-swf (>=1.34.0,<1.35.0)", "mypy-boto3-synthetics (>=1.34.0,<1.35.0)", "mypy-boto3-taxsettings (>=1.34.0,<1.35.0)", "mypy-boto3-textract (>=1.34.0,<1.35.0)", "mypy-boto3-timestream-influxdb (>=1.34.0,<1.35.0)", "mypy-boto3-timestream-query (>=1.34.0,<1.35.0)", "mypy-boto3-timestream-write (>=1.34.0,<1.35.0)", "mypy-boto3-tnb (>=1.34.0,<1.35.0)", "mypy-boto3-transcribe (>=1.34.0,<1.35.0)", "mypy-boto3-transfer (>=1.34.0,<1.35.0)", "mypy-boto3-translate (>=1.34.0,<1.35.0)", "mypy-boto3-trustedadvisor (>=1.34.0,<1.35.0)", "mypy-boto3-verifiedpermissions (>=1.34.0,<1.35.0)", "mypy-boto3-voice-id (>=1.34.0,<1.35.0)", "mypy-boto3-vpc-lattice (>=1.34.0,<1.35.0)", "mypy-boto3-waf (>=1.34.0,<1.35.0)", "mypy-boto3-waf-regional (>=1.34.0,<1.35.0)", "mypy-boto3-wafv2 (>=1.34.0,<1.35.0)", "mypy-boto3-wellarchitected (>=1.34.0,<1.35.0)", "mypy-boto3-wisdom (>=1.34.0,<1.35.0)", "mypy-boto3-workdocs (>=1.34.0,<1.35.0)", "mypy-boto3-worklink (>=1.34.0,<1.35.0)", "mypy-boto3-workmail (>=1.34.0,<1.35.0)", "mypy-boto3-workmailmessageflow (>=1.34.0,<1.35.0)", "mypy-boto3-workspaces (>=1.34.0,<1.35.0)", "mypy-boto3-workspaces-thin-client (>=1.34.0,<1.35.0)", "mypy-boto3-workspaces-web (>=1.34.0,<1.35.0)", "mypy-boto3-xray (>=1.34.0,<1.35.0)"] 129 | amp = ["mypy-boto3-amp (>=1.34.0,<1.35.0)"] 130 | amplify = ["mypy-boto3-amplify (>=1.34.0,<1.35.0)"] 131 | amplifybackend = ["mypy-boto3-amplifybackend (>=1.34.0,<1.35.0)"] 132 | amplifyuibuilder = ["mypy-boto3-amplifyuibuilder (>=1.34.0,<1.35.0)"] 133 | apigateway = ["mypy-boto3-apigateway (>=1.34.0,<1.35.0)"] 134 | apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (>=1.34.0,<1.35.0)"] 135 | apigatewayv2 = ["mypy-boto3-apigatewayv2 (>=1.34.0,<1.35.0)"] 136 | appconfig = ["mypy-boto3-appconfig (>=1.34.0,<1.35.0)"] 137 | appconfigdata = ["mypy-boto3-appconfigdata (>=1.34.0,<1.35.0)"] 138 | appfabric = ["mypy-boto3-appfabric (>=1.34.0,<1.35.0)"] 139 | appflow = ["mypy-boto3-appflow (>=1.34.0,<1.35.0)"] 140 | appintegrations = ["mypy-boto3-appintegrations (>=1.34.0,<1.35.0)"] 141 | application-autoscaling = ["mypy-boto3-application-autoscaling (>=1.34.0,<1.35.0)"] 142 | application-insights = ["mypy-boto3-application-insights (>=1.34.0,<1.35.0)"] 143 | application-signals = ["mypy-boto3-application-signals (>=1.34.0,<1.35.0)"] 144 | applicationcostprofiler = ["mypy-boto3-applicationcostprofiler (>=1.34.0,<1.35.0)"] 145 | appmesh = ["mypy-boto3-appmesh (>=1.34.0,<1.35.0)"] 146 | apprunner = ["mypy-boto3-apprunner (>=1.34.0,<1.35.0)"] 147 | appstream = ["mypy-boto3-appstream (>=1.34.0,<1.35.0)"] 148 | appsync = ["mypy-boto3-appsync (>=1.34.0,<1.35.0)"] 149 | apptest = ["mypy-boto3-apptest (>=1.34.0,<1.35.0)"] 150 | arc-zonal-shift = ["mypy-boto3-arc-zonal-shift (>=1.34.0,<1.35.0)"] 151 | artifact = ["mypy-boto3-artifact (>=1.34.0,<1.35.0)"] 152 | athena = ["mypy-boto3-athena (>=1.34.0,<1.35.0)"] 153 | auditmanager = ["mypy-boto3-auditmanager (>=1.34.0,<1.35.0)"] 154 | autoscaling = ["mypy-boto3-autoscaling (>=1.34.0,<1.35.0)"] 155 | autoscaling-plans = ["mypy-boto3-autoscaling-plans (>=1.34.0,<1.35.0)"] 156 | b2bi = ["mypy-boto3-b2bi (>=1.34.0,<1.35.0)"] 157 | backup = ["mypy-boto3-backup (>=1.34.0,<1.35.0)"] 158 | backup-gateway = ["mypy-boto3-backup-gateway (>=1.34.0,<1.35.0)"] 159 | batch = ["mypy-boto3-batch (>=1.34.0,<1.35.0)"] 160 | bcm-data-exports = ["mypy-boto3-bcm-data-exports (>=1.34.0,<1.35.0)"] 161 | bedrock = ["mypy-boto3-bedrock (>=1.34.0,<1.35.0)"] 162 | bedrock-agent = ["mypy-boto3-bedrock-agent (>=1.34.0,<1.35.0)"] 163 | bedrock-agent-runtime = ["mypy-boto3-bedrock-agent-runtime (>=1.34.0,<1.35.0)"] 164 | bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.34.0,<1.35.0)"] 165 | billingconductor = ["mypy-boto3-billingconductor (>=1.34.0,<1.35.0)"] 166 | boto3 = ["boto3 (==1.34.144)", "botocore (==1.34.144)"] 167 | braket = ["mypy-boto3-braket (>=1.34.0,<1.35.0)"] 168 | budgets = ["mypy-boto3-budgets (>=1.34.0,<1.35.0)"] 169 | ce = ["mypy-boto3-ce (>=1.34.0,<1.35.0)"] 170 | chatbot = ["mypy-boto3-chatbot (>=1.34.0,<1.35.0)"] 171 | chime = ["mypy-boto3-chime (>=1.34.0,<1.35.0)"] 172 | chime-sdk-identity = ["mypy-boto3-chime-sdk-identity (>=1.34.0,<1.35.0)"] 173 | chime-sdk-media-pipelines = ["mypy-boto3-chime-sdk-media-pipelines (>=1.34.0,<1.35.0)"] 174 | chime-sdk-meetings = ["mypy-boto3-chime-sdk-meetings (>=1.34.0,<1.35.0)"] 175 | chime-sdk-messaging = ["mypy-boto3-chime-sdk-messaging (>=1.34.0,<1.35.0)"] 176 | chime-sdk-voice = ["mypy-boto3-chime-sdk-voice (>=1.34.0,<1.35.0)"] 177 | cleanrooms = ["mypy-boto3-cleanrooms (>=1.34.0,<1.35.0)"] 178 | cleanroomsml = ["mypy-boto3-cleanroomsml (>=1.34.0,<1.35.0)"] 179 | cloud9 = ["mypy-boto3-cloud9 (>=1.34.0,<1.35.0)"] 180 | cloudcontrol = ["mypy-boto3-cloudcontrol (>=1.34.0,<1.35.0)"] 181 | clouddirectory = ["mypy-boto3-clouddirectory (>=1.34.0,<1.35.0)"] 182 | cloudformation = ["mypy-boto3-cloudformation (>=1.34.0,<1.35.0)"] 183 | cloudfront = ["mypy-boto3-cloudfront (>=1.34.0,<1.35.0)"] 184 | cloudfront-keyvaluestore = ["mypy-boto3-cloudfront-keyvaluestore (>=1.34.0,<1.35.0)"] 185 | cloudhsm = ["mypy-boto3-cloudhsm (>=1.34.0,<1.35.0)"] 186 | cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (>=1.34.0,<1.35.0)"] 187 | cloudsearch = ["mypy-boto3-cloudsearch (>=1.34.0,<1.35.0)"] 188 | cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (>=1.34.0,<1.35.0)"] 189 | cloudtrail = ["mypy-boto3-cloudtrail (>=1.34.0,<1.35.0)"] 190 | cloudtrail-data = ["mypy-boto3-cloudtrail-data (>=1.34.0,<1.35.0)"] 191 | cloudwatch = ["mypy-boto3-cloudwatch (>=1.34.0,<1.35.0)"] 192 | codeartifact = ["mypy-boto3-codeartifact (>=1.34.0,<1.35.0)"] 193 | codebuild = ["mypy-boto3-codebuild (>=1.34.0,<1.35.0)"] 194 | codecatalyst = ["mypy-boto3-codecatalyst (>=1.34.0,<1.35.0)"] 195 | codecommit = ["mypy-boto3-codecommit (>=1.34.0,<1.35.0)"] 196 | codeconnections = ["mypy-boto3-codeconnections (>=1.34.0,<1.35.0)"] 197 | codedeploy = ["mypy-boto3-codedeploy (>=1.34.0,<1.35.0)"] 198 | codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (>=1.34.0,<1.35.0)"] 199 | codeguru-security = ["mypy-boto3-codeguru-security (>=1.34.0,<1.35.0)"] 200 | codeguruprofiler = ["mypy-boto3-codeguruprofiler (>=1.34.0,<1.35.0)"] 201 | codepipeline = ["mypy-boto3-codepipeline (>=1.34.0,<1.35.0)"] 202 | codestar = ["mypy-boto3-codestar (>=1.34.0,<1.35.0)"] 203 | codestar-connections = ["mypy-boto3-codestar-connections (>=1.34.0,<1.35.0)"] 204 | codestar-notifications = ["mypy-boto3-codestar-notifications (>=1.34.0,<1.35.0)"] 205 | cognito-identity = ["mypy-boto3-cognito-identity (>=1.34.0,<1.35.0)"] 206 | cognito-idp = ["mypy-boto3-cognito-idp (>=1.34.0,<1.35.0)"] 207 | cognito-sync = ["mypy-boto3-cognito-sync (>=1.34.0,<1.35.0)"] 208 | comprehend = ["mypy-boto3-comprehend (>=1.34.0,<1.35.0)"] 209 | comprehendmedical = ["mypy-boto3-comprehendmedical (>=1.34.0,<1.35.0)"] 210 | compute-optimizer = ["mypy-boto3-compute-optimizer (>=1.34.0,<1.35.0)"] 211 | config = ["mypy-boto3-config (>=1.34.0,<1.35.0)"] 212 | connect = ["mypy-boto3-connect (>=1.34.0,<1.35.0)"] 213 | connect-contact-lens = ["mypy-boto3-connect-contact-lens (>=1.34.0,<1.35.0)"] 214 | connectcampaigns = ["mypy-boto3-connectcampaigns (>=1.34.0,<1.35.0)"] 215 | connectcases = ["mypy-boto3-connectcases (>=1.34.0,<1.35.0)"] 216 | connectparticipant = ["mypy-boto3-connectparticipant (>=1.34.0,<1.35.0)"] 217 | controlcatalog = ["mypy-boto3-controlcatalog (>=1.34.0,<1.35.0)"] 218 | controltower = ["mypy-boto3-controltower (>=1.34.0,<1.35.0)"] 219 | cost-optimization-hub = ["mypy-boto3-cost-optimization-hub (>=1.34.0,<1.35.0)"] 220 | cur = ["mypy-boto3-cur (>=1.34.0,<1.35.0)"] 221 | customer-profiles = ["mypy-boto3-customer-profiles (>=1.34.0,<1.35.0)"] 222 | databrew = ["mypy-boto3-databrew (>=1.34.0,<1.35.0)"] 223 | dataexchange = ["mypy-boto3-dataexchange (>=1.34.0,<1.35.0)"] 224 | datapipeline = ["mypy-boto3-datapipeline (>=1.34.0,<1.35.0)"] 225 | datasync = ["mypy-boto3-datasync (>=1.34.0,<1.35.0)"] 226 | datazone = ["mypy-boto3-datazone (>=1.34.0,<1.35.0)"] 227 | dax = ["mypy-boto3-dax (>=1.34.0,<1.35.0)"] 228 | deadline = ["mypy-boto3-deadline (>=1.34.0,<1.35.0)"] 229 | detective = ["mypy-boto3-detective (>=1.34.0,<1.35.0)"] 230 | devicefarm = ["mypy-boto3-devicefarm (>=1.34.0,<1.35.0)"] 231 | devops-guru = ["mypy-boto3-devops-guru (>=1.34.0,<1.35.0)"] 232 | directconnect = ["mypy-boto3-directconnect (>=1.34.0,<1.35.0)"] 233 | discovery = ["mypy-boto3-discovery (>=1.34.0,<1.35.0)"] 234 | dlm = ["mypy-boto3-dlm (>=1.34.0,<1.35.0)"] 235 | dms = ["mypy-boto3-dms (>=1.34.0,<1.35.0)"] 236 | docdb = ["mypy-boto3-docdb (>=1.34.0,<1.35.0)"] 237 | docdb-elastic = ["mypy-boto3-docdb-elastic (>=1.34.0,<1.35.0)"] 238 | drs = ["mypy-boto3-drs (>=1.34.0,<1.35.0)"] 239 | ds = ["mypy-boto3-ds (>=1.34.0,<1.35.0)"] 240 | dynamodb = ["mypy-boto3-dynamodb (>=1.34.0,<1.35.0)"] 241 | dynamodbstreams = ["mypy-boto3-dynamodbstreams (>=1.34.0,<1.35.0)"] 242 | ebs = ["mypy-boto3-ebs (>=1.34.0,<1.35.0)"] 243 | ec2 = ["mypy-boto3-ec2 (>=1.34.0,<1.35.0)"] 244 | ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (>=1.34.0,<1.35.0)"] 245 | ecr = ["mypy-boto3-ecr (>=1.34.0,<1.35.0)"] 246 | ecr-public = ["mypy-boto3-ecr-public (>=1.34.0,<1.35.0)"] 247 | ecs = ["mypy-boto3-ecs (>=1.34.0,<1.35.0)"] 248 | efs = ["mypy-boto3-efs (>=1.34.0,<1.35.0)"] 249 | eks = ["mypy-boto3-eks (>=1.34.0,<1.35.0)"] 250 | eks-auth = ["mypy-boto3-eks-auth (>=1.34.0,<1.35.0)"] 251 | elastic-inference = ["mypy-boto3-elastic-inference (>=1.34.0,<1.35.0)"] 252 | elasticache = ["mypy-boto3-elasticache (>=1.34.0,<1.35.0)"] 253 | elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (>=1.34.0,<1.35.0)"] 254 | elastictranscoder = ["mypy-boto3-elastictranscoder (>=1.34.0,<1.35.0)"] 255 | elb = ["mypy-boto3-elb (>=1.34.0,<1.35.0)"] 256 | elbv2 = ["mypy-boto3-elbv2 (>=1.34.0,<1.35.0)"] 257 | emr = ["mypy-boto3-emr (>=1.34.0,<1.35.0)"] 258 | emr-containers = ["mypy-boto3-emr-containers (>=1.34.0,<1.35.0)"] 259 | emr-serverless = ["mypy-boto3-emr-serverless (>=1.34.0,<1.35.0)"] 260 | entityresolution = ["mypy-boto3-entityresolution (>=1.34.0,<1.35.0)"] 261 | es = ["mypy-boto3-es (>=1.34.0,<1.35.0)"] 262 | essential = ["mypy-boto3-cloudformation (>=1.34.0,<1.35.0)", "mypy-boto3-dynamodb (>=1.34.0,<1.35.0)", "mypy-boto3-ec2 (>=1.34.0,<1.35.0)", "mypy-boto3-lambda (>=1.34.0,<1.35.0)", "mypy-boto3-rds (>=1.34.0,<1.35.0)", "mypy-boto3-s3 (>=1.34.0,<1.35.0)", "mypy-boto3-sqs (>=1.34.0,<1.35.0)"] 263 | events = ["mypy-boto3-events (>=1.34.0,<1.35.0)"] 264 | evidently = ["mypy-boto3-evidently (>=1.34.0,<1.35.0)"] 265 | finspace = ["mypy-boto3-finspace (>=1.34.0,<1.35.0)"] 266 | finspace-data = ["mypy-boto3-finspace-data (>=1.34.0,<1.35.0)"] 267 | firehose = ["mypy-boto3-firehose (>=1.34.0,<1.35.0)"] 268 | fis = ["mypy-boto3-fis (>=1.34.0,<1.35.0)"] 269 | fms = ["mypy-boto3-fms (>=1.34.0,<1.35.0)"] 270 | forecast = ["mypy-boto3-forecast (>=1.34.0,<1.35.0)"] 271 | forecastquery = ["mypy-boto3-forecastquery (>=1.34.0,<1.35.0)"] 272 | frauddetector = ["mypy-boto3-frauddetector (>=1.34.0,<1.35.0)"] 273 | freetier = ["mypy-boto3-freetier (>=1.34.0,<1.35.0)"] 274 | fsx = ["mypy-boto3-fsx (>=1.34.0,<1.35.0)"] 275 | gamelift = ["mypy-boto3-gamelift (>=1.34.0,<1.35.0)"] 276 | glacier = ["mypy-boto3-glacier (>=1.34.0,<1.35.0)"] 277 | globalaccelerator = ["mypy-boto3-globalaccelerator (>=1.34.0,<1.35.0)"] 278 | glue = ["mypy-boto3-glue (>=1.34.0,<1.35.0)"] 279 | grafana = ["mypy-boto3-grafana (>=1.34.0,<1.35.0)"] 280 | greengrass = ["mypy-boto3-greengrass (>=1.34.0,<1.35.0)"] 281 | greengrassv2 = ["mypy-boto3-greengrassv2 (>=1.34.0,<1.35.0)"] 282 | groundstation = ["mypy-boto3-groundstation (>=1.34.0,<1.35.0)"] 283 | guardduty = ["mypy-boto3-guardduty (>=1.34.0,<1.35.0)"] 284 | health = ["mypy-boto3-health (>=1.34.0,<1.35.0)"] 285 | healthlake = ["mypy-boto3-healthlake (>=1.34.0,<1.35.0)"] 286 | iam = ["mypy-boto3-iam (>=1.34.0,<1.35.0)"] 287 | identitystore = ["mypy-boto3-identitystore (>=1.34.0,<1.35.0)"] 288 | imagebuilder = ["mypy-boto3-imagebuilder (>=1.34.0,<1.35.0)"] 289 | importexport = ["mypy-boto3-importexport (>=1.34.0,<1.35.0)"] 290 | inspector = ["mypy-boto3-inspector (>=1.34.0,<1.35.0)"] 291 | inspector-scan = ["mypy-boto3-inspector-scan (>=1.34.0,<1.35.0)"] 292 | inspector2 = ["mypy-boto3-inspector2 (>=1.34.0,<1.35.0)"] 293 | internetmonitor = ["mypy-boto3-internetmonitor (>=1.34.0,<1.35.0)"] 294 | iot = ["mypy-boto3-iot (>=1.34.0,<1.35.0)"] 295 | iot-data = ["mypy-boto3-iot-data (>=1.34.0,<1.35.0)"] 296 | iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.34.0,<1.35.0)"] 297 | iot1click-devices = ["mypy-boto3-iot1click-devices (>=1.34.0,<1.35.0)"] 298 | iot1click-projects = ["mypy-boto3-iot1click-projects (>=1.34.0,<1.35.0)"] 299 | iotanalytics = ["mypy-boto3-iotanalytics (>=1.34.0,<1.35.0)"] 300 | iotdeviceadvisor = ["mypy-boto3-iotdeviceadvisor (>=1.34.0,<1.35.0)"] 301 | iotevents = ["mypy-boto3-iotevents (>=1.34.0,<1.35.0)"] 302 | iotevents-data = ["mypy-boto3-iotevents-data (>=1.34.0,<1.35.0)"] 303 | iotfleethub = ["mypy-boto3-iotfleethub (>=1.34.0,<1.35.0)"] 304 | iotfleetwise = ["mypy-boto3-iotfleetwise (>=1.34.0,<1.35.0)"] 305 | iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (>=1.34.0,<1.35.0)"] 306 | iotsitewise = ["mypy-boto3-iotsitewise (>=1.34.0,<1.35.0)"] 307 | iotthingsgraph = ["mypy-boto3-iotthingsgraph (>=1.34.0,<1.35.0)"] 308 | iottwinmaker = ["mypy-boto3-iottwinmaker (>=1.34.0,<1.35.0)"] 309 | iotwireless = ["mypy-boto3-iotwireless (>=1.34.0,<1.35.0)"] 310 | ivs = ["mypy-boto3-ivs (>=1.34.0,<1.35.0)"] 311 | ivs-realtime = ["mypy-boto3-ivs-realtime (>=1.34.0,<1.35.0)"] 312 | ivschat = ["mypy-boto3-ivschat (>=1.34.0,<1.35.0)"] 313 | kafka = ["mypy-boto3-kafka (>=1.34.0,<1.35.0)"] 314 | kafkaconnect = ["mypy-boto3-kafkaconnect (>=1.34.0,<1.35.0)"] 315 | kendra = ["mypy-boto3-kendra (>=1.34.0,<1.35.0)"] 316 | kendra-ranking = ["mypy-boto3-kendra-ranking (>=1.34.0,<1.35.0)"] 317 | keyspaces = ["mypy-boto3-keyspaces (>=1.34.0,<1.35.0)"] 318 | kinesis = ["mypy-boto3-kinesis (>=1.34.0,<1.35.0)"] 319 | kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (>=1.34.0,<1.35.0)"] 320 | kinesis-video-media = ["mypy-boto3-kinesis-video-media (>=1.34.0,<1.35.0)"] 321 | kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (>=1.34.0,<1.35.0)"] 322 | kinesis-video-webrtc-storage = ["mypy-boto3-kinesis-video-webrtc-storage (>=1.34.0,<1.35.0)"] 323 | kinesisanalytics = ["mypy-boto3-kinesisanalytics (>=1.34.0,<1.35.0)"] 324 | kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (>=1.34.0,<1.35.0)"] 325 | kinesisvideo = ["mypy-boto3-kinesisvideo (>=1.34.0,<1.35.0)"] 326 | kms = ["mypy-boto3-kms (>=1.34.0,<1.35.0)"] 327 | lakeformation = ["mypy-boto3-lakeformation (>=1.34.0,<1.35.0)"] 328 | lambda = ["mypy-boto3-lambda (>=1.34.0,<1.35.0)"] 329 | launch-wizard = ["mypy-boto3-launch-wizard (>=1.34.0,<1.35.0)"] 330 | lex-models = ["mypy-boto3-lex-models (>=1.34.0,<1.35.0)"] 331 | lex-runtime = ["mypy-boto3-lex-runtime (>=1.34.0,<1.35.0)"] 332 | lexv2-models = ["mypy-boto3-lexv2-models (>=1.34.0,<1.35.0)"] 333 | lexv2-runtime = ["mypy-boto3-lexv2-runtime (>=1.34.0,<1.35.0)"] 334 | license-manager = ["mypy-boto3-license-manager (>=1.34.0,<1.35.0)"] 335 | license-manager-linux-subscriptions = ["mypy-boto3-license-manager-linux-subscriptions (>=1.34.0,<1.35.0)"] 336 | license-manager-user-subscriptions = ["mypy-boto3-license-manager-user-subscriptions (>=1.34.0,<1.35.0)"] 337 | lightsail = ["mypy-boto3-lightsail (>=1.34.0,<1.35.0)"] 338 | location = ["mypy-boto3-location (>=1.34.0,<1.35.0)"] 339 | logs = ["mypy-boto3-logs (>=1.34.0,<1.35.0)"] 340 | lookoutequipment = ["mypy-boto3-lookoutequipment (>=1.34.0,<1.35.0)"] 341 | lookoutmetrics = ["mypy-boto3-lookoutmetrics (>=1.34.0,<1.35.0)"] 342 | lookoutvision = ["mypy-boto3-lookoutvision (>=1.34.0,<1.35.0)"] 343 | m2 = ["mypy-boto3-m2 (>=1.34.0,<1.35.0)"] 344 | machinelearning = ["mypy-boto3-machinelearning (>=1.34.0,<1.35.0)"] 345 | macie2 = ["mypy-boto3-macie2 (>=1.34.0,<1.35.0)"] 346 | mailmanager = ["mypy-boto3-mailmanager (>=1.34.0,<1.35.0)"] 347 | managedblockchain = ["mypy-boto3-managedblockchain (>=1.34.0,<1.35.0)"] 348 | managedblockchain-query = ["mypy-boto3-managedblockchain-query (>=1.34.0,<1.35.0)"] 349 | marketplace-agreement = ["mypy-boto3-marketplace-agreement (>=1.34.0,<1.35.0)"] 350 | marketplace-catalog = ["mypy-boto3-marketplace-catalog (>=1.34.0,<1.35.0)"] 351 | marketplace-deployment = ["mypy-boto3-marketplace-deployment (>=1.34.0,<1.35.0)"] 352 | marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (>=1.34.0,<1.35.0)"] 353 | marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (>=1.34.0,<1.35.0)"] 354 | mediaconnect = ["mypy-boto3-mediaconnect (>=1.34.0,<1.35.0)"] 355 | mediaconvert = ["mypy-boto3-mediaconvert (>=1.34.0,<1.35.0)"] 356 | medialive = ["mypy-boto3-medialive (>=1.34.0,<1.35.0)"] 357 | mediapackage = ["mypy-boto3-mediapackage (>=1.34.0,<1.35.0)"] 358 | mediapackage-vod = ["mypy-boto3-mediapackage-vod (>=1.34.0,<1.35.0)"] 359 | mediapackagev2 = ["mypy-boto3-mediapackagev2 (>=1.34.0,<1.35.0)"] 360 | mediastore = ["mypy-boto3-mediastore (>=1.34.0,<1.35.0)"] 361 | mediastore-data = ["mypy-boto3-mediastore-data (>=1.34.0,<1.35.0)"] 362 | mediatailor = ["mypy-boto3-mediatailor (>=1.34.0,<1.35.0)"] 363 | medical-imaging = ["mypy-boto3-medical-imaging (>=1.34.0,<1.35.0)"] 364 | memorydb = ["mypy-boto3-memorydb (>=1.34.0,<1.35.0)"] 365 | meteringmarketplace = ["mypy-boto3-meteringmarketplace (>=1.34.0,<1.35.0)"] 366 | mgh = ["mypy-boto3-mgh (>=1.34.0,<1.35.0)"] 367 | mgn = ["mypy-boto3-mgn (>=1.34.0,<1.35.0)"] 368 | migration-hub-refactor-spaces = ["mypy-boto3-migration-hub-refactor-spaces (>=1.34.0,<1.35.0)"] 369 | migrationhub-config = ["mypy-boto3-migrationhub-config (>=1.34.0,<1.35.0)"] 370 | migrationhuborchestrator = ["mypy-boto3-migrationhuborchestrator (>=1.34.0,<1.35.0)"] 371 | migrationhubstrategy = ["mypy-boto3-migrationhubstrategy (>=1.34.0,<1.35.0)"] 372 | mobile = ["mypy-boto3-mobile (>=1.34.0,<1.35.0)"] 373 | mq = ["mypy-boto3-mq (>=1.34.0,<1.35.0)"] 374 | mturk = ["mypy-boto3-mturk (>=1.34.0,<1.35.0)"] 375 | mwaa = ["mypy-boto3-mwaa (>=1.34.0,<1.35.0)"] 376 | neptune = ["mypy-boto3-neptune (>=1.34.0,<1.35.0)"] 377 | neptune-graph = ["mypy-boto3-neptune-graph (>=1.34.0,<1.35.0)"] 378 | neptunedata = ["mypy-boto3-neptunedata (>=1.34.0,<1.35.0)"] 379 | network-firewall = ["mypy-boto3-network-firewall (>=1.34.0,<1.35.0)"] 380 | networkmanager = ["mypy-boto3-networkmanager (>=1.34.0,<1.35.0)"] 381 | networkmonitor = ["mypy-boto3-networkmonitor (>=1.34.0,<1.35.0)"] 382 | nimble = ["mypy-boto3-nimble (>=1.34.0,<1.35.0)"] 383 | oam = ["mypy-boto3-oam (>=1.34.0,<1.35.0)"] 384 | omics = ["mypy-boto3-omics (>=1.34.0,<1.35.0)"] 385 | opensearch = ["mypy-boto3-opensearch (>=1.34.0,<1.35.0)"] 386 | opensearchserverless = ["mypy-boto3-opensearchserverless (>=1.34.0,<1.35.0)"] 387 | opsworks = ["mypy-boto3-opsworks (>=1.34.0,<1.35.0)"] 388 | opsworkscm = ["mypy-boto3-opsworkscm (>=1.34.0,<1.35.0)"] 389 | organizations = ["mypy-boto3-organizations (>=1.34.0,<1.35.0)"] 390 | osis = ["mypy-boto3-osis (>=1.34.0,<1.35.0)"] 391 | outposts = ["mypy-boto3-outposts (>=1.34.0,<1.35.0)"] 392 | panorama = ["mypy-boto3-panorama (>=1.34.0,<1.35.0)"] 393 | payment-cryptography = ["mypy-boto3-payment-cryptography (>=1.34.0,<1.35.0)"] 394 | payment-cryptography-data = ["mypy-boto3-payment-cryptography-data (>=1.34.0,<1.35.0)"] 395 | pca-connector-ad = ["mypy-boto3-pca-connector-ad (>=1.34.0,<1.35.0)"] 396 | pca-connector-scep = ["mypy-boto3-pca-connector-scep (>=1.34.0,<1.35.0)"] 397 | personalize = ["mypy-boto3-personalize (>=1.34.0,<1.35.0)"] 398 | personalize-events = ["mypy-boto3-personalize-events (>=1.34.0,<1.35.0)"] 399 | personalize-runtime = ["mypy-boto3-personalize-runtime (>=1.34.0,<1.35.0)"] 400 | pi = ["mypy-boto3-pi (>=1.34.0,<1.35.0)"] 401 | pinpoint = ["mypy-boto3-pinpoint (>=1.34.0,<1.35.0)"] 402 | pinpoint-email = ["mypy-boto3-pinpoint-email (>=1.34.0,<1.35.0)"] 403 | pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (>=1.34.0,<1.35.0)"] 404 | pinpoint-sms-voice-v2 = ["mypy-boto3-pinpoint-sms-voice-v2 (>=1.34.0,<1.35.0)"] 405 | pipes = ["mypy-boto3-pipes (>=1.34.0,<1.35.0)"] 406 | polly = ["mypy-boto3-polly (>=1.34.0,<1.35.0)"] 407 | pricing = ["mypy-boto3-pricing (>=1.34.0,<1.35.0)"] 408 | privatenetworks = ["mypy-boto3-privatenetworks (>=1.34.0,<1.35.0)"] 409 | proton = ["mypy-boto3-proton (>=1.34.0,<1.35.0)"] 410 | qapps = ["mypy-boto3-qapps (>=1.34.0,<1.35.0)"] 411 | qbusiness = ["mypy-boto3-qbusiness (>=1.34.0,<1.35.0)"] 412 | qconnect = ["mypy-boto3-qconnect (>=1.34.0,<1.35.0)"] 413 | qldb = ["mypy-boto3-qldb (>=1.34.0,<1.35.0)"] 414 | qldb-session = ["mypy-boto3-qldb-session (>=1.34.0,<1.35.0)"] 415 | quicksight = ["mypy-boto3-quicksight (>=1.34.0,<1.35.0)"] 416 | ram = ["mypy-boto3-ram (>=1.34.0,<1.35.0)"] 417 | rbin = ["mypy-boto3-rbin (>=1.34.0,<1.35.0)"] 418 | rds = ["mypy-boto3-rds (>=1.34.0,<1.35.0)"] 419 | rds-data = ["mypy-boto3-rds-data (>=1.34.0,<1.35.0)"] 420 | redshift = ["mypy-boto3-redshift (>=1.34.0,<1.35.0)"] 421 | redshift-data = ["mypy-boto3-redshift-data (>=1.34.0,<1.35.0)"] 422 | redshift-serverless = ["mypy-boto3-redshift-serverless (>=1.34.0,<1.35.0)"] 423 | rekognition = ["mypy-boto3-rekognition (>=1.34.0,<1.35.0)"] 424 | repostspace = ["mypy-boto3-repostspace (>=1.34.0,<1.35.0)"] 425 | resiliencehub = ["mypy-boto3-resiliencehub (>=1.34.0,<1.35.0)"] 426 | resource-explorer-2 = ["mypy-boto3-resource-explorer-2 (>=1.34.0,<1.35.0)"] 427 | resource-groups = ["mypy-boto3-resource-groups (>=1.34.0,<1.35.0)"] 428 | resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (>=1.34.0,<1.35.0)"] 429 | robomaker = ["mypy-boto3-robomaker (>=1.34.0,<1.35.0)"] 430 | rolesanywhere = ["mypy-boto3-rolesanywhere (>=1.34.0,<1.35.0)"] 431 | route53 = ["mypy-boto3-route53 (>=1.34.0,<1.35.0)"] 432 | route53-recovery-cluster = ["mypy-boto3-route53-recovery-cluster (>=1.34.0,<1.35.0)"] 433 | route53-recovery-control-config = ["mypy-boto3-route53-recovery-control-config (>=1.34.0,<1.35.0)"] 434 | route53-recovery-readiness = ["mypy-boto3-route53-recovery-readiness (>=1.34.0,<1.35.0)"] 435 | route53domains = ["mypy-boto3-route53domains (>=1.34.0,<1.35.0)"] 436 | route53profiles = ["mypy-boto3-route53profiles (>=1.34.0,<1.35.0)"] 437 | route53resolver = ["mypy-boto3-route53resolver (>=1.34.0,<1.35.0)"] 438 | rum = ["mypy-boto3-rum (>=1.34.0,<1.35.0)"] 439 | s3 = ["mypy-boto3-s3 (>=1.34.0,<1.35.0)"] 440 | s3control = ["mypy-boto3-s3control (>=1.34.0,<1.35.0)"] 441 | s3outposts = ["mypy-boto3-s3outposts (>=1.34.0,<1.35.0)"] 442 | sagemaker = ["mypy-boto3-sagemaker (>=1.34.0,<1.35.0)"] 443 | sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (>=1.34.0,<1.35.0)"] 444 | sagemaker-edge = ["mypy-boto3-sagemaker-edge (>=1.34.0,<1.35.0)"] 445 | sagemaker-featurestore-runtime = ["mypy-boto3-sagemaker-featurestore-runtime (>=1.34.0,<1.35.0)"] 446 | sagemaker-geospatial = ["mypy-boto3-sagemaker-geospatial (>=1.34.0,<1.35.0)"] 447 | sagemaker-metrics = ["mypy-boto3-sagemaker-metrics (>=1.34.0,<1.35.0)"] 448 | sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (>=1.34.0,<1.35.0)"] 449 | savingsplans = ["mypy-boto3-savingsplans (>=1.34.0,<1.35.0)"] 450 | scheduler = ["mypy-boto3-scheduler (>=1.34.0,<1.35.0)"] 451 | schemas = ["mypy-boto3-schemas (>=1.34.0,<1.35.0)"] 452 | sdb = ["mypy-boto3-sdb (>=1.34.0,<1.35.0)"] 453 | secretsmanager = ["mypy-boto3-secretsmanager (>=1.34.0,<1.35.0)"] 454 | securityhub = ["mypy-boto3-securityhub (>=1.34.0,<1.35.0)"] 455 | securitylake = ["mypy-boto3-securitylake (>=1.34.0,<1.35.0)"] 456 | serverlessrepo = ["mypy-boto3-serverlessrepo (>=1.34.0,<1.35.0)"] 457 | service-quotas = ["mypy-boto3-service-quotas (>=1.34.0,<1.35.0)"] 458 | servicecatalog = ["mypy-boto3-servicecatalog (>=1.34.0,<1.35.0)"] 459 | servicecatalog-appregistry = ["mypy-boto3-servicecatalog-appregistry (>=1.34.0,<1.35.0)"] 460 | servicediscovery = ["mypy-boto3-servicediscovery (>=1.34.0,<1.35.0)"] 461 | ses = ["mypy-boto3-ses (>=1.34.0,<1.35.0)"] 462 | sesv2 = ["mypy-boto3-sesv2 (>=1.34.0,<1.35.0)"] 463 | shield = ["mypy-boto3-shield (>=1.34.0,<1.35.0)"] 464 | signer = ["mypy-boto3-signer (>=1.34.0,<1.35.0)"] 465 | simspaceweaver = ["mypy-boto3-simspaceweaver (>=1.34.0,<1.35.0)"] 466 | sms = ["mypy-boto3-sms (>=1.34.0,<1.35.0)"] 467 | sms-voice = ["mypy-boto3-sms-voice (>=1.34.0,<1.35.0)"] 468 | snow-device-management = ["mypy-boto3-snow-device-management (>=1.34.0,<1.35.0)"] 469 | snowball = ["mypy-boto3-snowball (>=1.34.0,<1.35.0)"] 470 | sns = ["mypy-boto3-sns (>=1.34.0,<1.35.0)"] 471 | sqs = ["mypy-boto3-sqs (>=1.34.0,<1.35.0)"] 472 | ssm = ["mypy-boto3-ssm (>=1.34.0,<1.35.0)"] 473 | ssm-contacts = ["mypy-boto3-ssm-contacts (>=1.34.0,<1.35.0)"] 474 | ssm-incidents = ["mypy-boto3-ssm-incidents (>=1.34.0,<1.35.0)"] 475 | ssm-sap = ["mypy-boto3-ssm-sap (>=1.34.0,<1.35.0)"] 476 | sso = ["mypy-boto3-sso (>=1.34.0,<1.35.0)"] 477 | sso-admin = ["mypy-boto3-sso-admin (>=1.34.0,<1.35.0)"] 478 | sso-oidc = ["mypy-boto3-sso-oidc (>=1.34.0,<1.35.0)"] 479 | stepfunctions = ["mypy-boto3-stepfunctions (>=1.34.0,<1.35.0)"] 480 | storagegateway = ["mypy-boto3-storagegateway (>=1.34.0,<1.35.0)"] 481 | sts = ["mypy-boto3-sts (>=1.34.0,<1.35.0)"] 482 | supplychain = ["mypy-boto3-supplychain (>=1.34.0,<1.35.0)"] 483 | support = ["mypy-boto3-support (>=1.34.0,<1.35.0)"] 484 | support-app = ["mypy-boto3-support-app (>=1.34.0,<1.35.0)"] 485 | swf = ["mypy-boto3-swf (>=1.34.0,<1.35.0)"] 486 | synthetics = ["mypy-boto3-synthetics (>=1.34.0,<1.35.0)"] 487 | taxsettings = ["mypy-boto3-taxsettings (>=1.34.0,<1.35.0)"] 488 | textract = ["mypy-boto3-textract (>=1.34.0,<1.35.0)"] 489 | timestream-influxdb = ["mypy-boto3-timestream-influxdb (>=1.34.0,<1.35.0)"] 490 | timestream-query = ["mypy-boto3-timestream-query (>=1.34.0,<1.35.0)"] 491 | timestream-write = ["mypy-boto3-timestream-write (>=1.34.0,<1.35.0)"] 492 | tnb = ["mypy-boto3-tnb (>=1.34.0,<1.35.0)"] 493 | transcribe = ["mypy-boto3-transcribe (>=1.34.0,<1.35.0)"] 494 | transfer = ["mypy-boto3-transfer (>=1.34.0,<1.35.0)"] 495 | translate = ["mypy-boto3-translate (>=1.34.0,<1.35.0)"] 496 | trustedadvisor = ["mypy-boto3-trustedadvisor (>=1.34.0,<1.35.0)"] 497 | verifiedpermissions = ["mypy-boto3-verifiedpermissions (>=1.34.0,<1.35.0)"] 498 | voice-id = ["mypy-boto3-voice-id (>=1.34.0,<1.35.0)"] 499 | vpc-lattice = ["mypy-boto3-vpc-lattice (>=1.34.0,<1.35.0)"] 500 | waf = ["mypy-boto3-waf (>=1.34.0,<1.35.0)"] 501 | waf-regional = ["mypy-boto3-waf-regional (>=1.34.0,<1.35.0)"] 502 | wafv2 = ["mypy-boto3-wafv2 (>=1.34.0,<1.35.0)"] 503 | wellarchitected = ["mypy-boto3-wellarchitected (>=1.34.0,<1.35.0)"] 504 | wisdom = ["mypy-boto3-wisdom (>=1.34.0,<1.35.0)"] 505 | workdocs = ["mypy-boto3-workdocs (>=1.34.0,<1.35.0)"] 506 | worklink = ["mypy-boto3-worklink (>=1.34.0,<1.35.0)"] 507 | workmail = ["mypy-boto3-workmail (>=1.34.0,<1.35.0)"] 508 | workmailmessageflow = ["mypy-boto3-workmailmessageflow (>=1.34.0,<1.35.0)"] 509 | workspaces = ["mypy-boto3-workspaces (>=1.34.0,<1.35.0)"] 510 | workspaces-thin-client = ["mypy-boto3-workspaces-thin-client (>=1.34.0,<1.35.0)"] 511 | workspaces-web = ["mypy-boto3-workspaces-web (>=1.34.0,<1.35.0)"] 512 | xray = ["mypy-boto3-xray (>=1.34.0,<1.35.0)"] 513 | 514 | [[package]] 515 | name = "botocore" 516 | version = "1.34.144" 517 | description = "Low-level, data-driven core of boto 3." 518 | optional = false 519 | python-versions = ">=3.8" 520 | files = [ 521 | {file = "botocore-1.34.144-py3-none-any.whl", hash = "sha256:a2cf26e1bf10d5917a2285e50257bc44e94a1d16574f282f3274f7a5d8d1f08b"}, 522 | {file = "botocore-1.34.144.tar.gz", hash = "sha256:4215db28d25309d59c99507f1f77df9089e5bebbad35f6e19c7c44ec5383a3e8"}, 523 | ] 524 | 525 | [package.dependencies] 526 | jmespath = ">=0.7.1,<2.0.0" 527 | python-dateutil = ">=2.1,<3.0.0" 528 | urllib3 = [ 529 | {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""}, 530 | {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}, 531 | ] 532 | 533 | [package.extras] 534 | crt = ["awscrt (==0.20.11)"] 535 | 536 | [[package]] 537 | name = "botocore-stubs" 538 | version = "1.34.31" 539 | description = "Type annotations and code completion for botocore" 540 | optional = false 541 | python-versions = ">=3.8,<4.0" 542 | files = [ 543 | {file = "botocore_stubs-1.34.31-py3-none-any.whl", hash = "sha256:40014d0724d522bc3cdae5c98eda7a12a7225a7e6dc6b07bb8081e0288aab4df"}, 544 | {file = "botocore_stubs-1.34.31.tar.gz", hash = "sha256:cb9cd482674b913c81e7eccd5702feb4f7c993b7b18009e465b045ce05289aa7"}, 545 | ] 546 | 547 | [package.dependencies] 548 | types-awscrt = "*" 549 | typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.9\""} 550 | 551 | [package.extras] 552 | botocore = ["botocore"] 553 | 554 | [[package]] 555 | name = "certifi" 556 | version = "2024.7.4" 557 | description = "Python package for providing Mozilla's CA Bundle." 558 | optional = false 559 | python-versions = ">=3.6" 560 | files = [ 561 | {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, 562 | {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, 563 | ] 564 | 565 | [[package]] 566 | name = "cffi" 567 | version = "1.16.0" 568 | description = "Foreign Function Interface for Python calling C code." 569 | optional = false 570 | python-versions = ">=3.8" 571 | files = [ 572 | {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, 573 | {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, 574 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, 575 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, 576 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, 577 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, 578 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, 579 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, 580 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, 581 | {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, 582 | {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, 583 | {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, 584 | {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, 585 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, 586 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, 587 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, 588 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, 589 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, 590 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, 591 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, 592 | {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, 593 | {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, 594 | {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, 595 | {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, 596 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, 597 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, 598 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, 599 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, 600 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, 601 | {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, 602 | {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, 603 | {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, 604 | {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, 605 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, 606 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, 607 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, 608 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, 609 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, 610 | {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, 611 | {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, 612 | {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, 613 | {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, 614 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, 615 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, 616 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, 617 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, 618 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, 619 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, 620 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, 621 | {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, 622 | {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, 623 | {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, 624 | ] 625 | 626 | [package.dependencies] 627 | pycparser = "*" 628 | 629 | [[package]] 630 | name = "charset-normalizer" 631 | version = "3.3.2" 632 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 633 | optional = false 634 | python-versions = ">=3.7.0" 635 | files = [ 636 | {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, 637 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, 638 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, 639 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, 640 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, 641 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, 642 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, 643 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, 644 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, 645 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, 646 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, 647 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, 648 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, 649 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, 650 | {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, 651 | {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, 652 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, 653 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, 654 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, 655 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, 656 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, 657 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, 658 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, 659 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, 660 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, 661 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, 662 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, 663 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, 664 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, 665 | {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, 666 | {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, 667 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, 668 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, 669 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, 670 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, 671 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, 672 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, 673 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, 674 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, 675 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, 676 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, 677 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, 678 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, 679 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, 680 | {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, 681 | {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, 682 | {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, 683 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, 684 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, 685 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, 686 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, 687 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, 688 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, 689 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, 690 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, 691 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, 692 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, 693 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, 694 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, 695 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, 696 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, 697 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, 698 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, 699 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, 700 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, 701 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, 702 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, 703 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, 704 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, 705 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, 706 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, 707 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, 708 | {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, 709 | {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, 710 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, 711 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, 712 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, 713 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, 714 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, 715 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, 716 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, 717 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, 718 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, 719 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, 720 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, 721 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, 722 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, 723 | {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, 724 | {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, 725 | {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, 726 | ] 727 | 728 | [[package]] 729 | name = "click" 730 | version = "8.1.7" 731 | description = "Composable command line interface toolkit" 732 | optional = false 733 | python-versions = ">=3.7" 734 | files = [ 735 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, 736 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, 737 | ] 738 | 739 | [package.dependencies] 740 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 741 | 742 | [[package]] 743 | name = "colorama" 744 | version = "0.4.6" 745 | description = "Cross-platform colored terminal text." 746 | optional = false 747 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 748 | files = [ 749 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 750 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 751 | ] 752 | 753 | [[package]] 754 | name = "coverage" 755 | version = "7.4.1" 756 | description = "Code coverage measurement for Python" 757 | optional = false 758 | python-versions = ">=3.8" 759 | files = [ 760 | {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"}, 761 | {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"}, 762 | {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"}, 763 | {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"}, 764 | {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"}, 765 | {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"}, 766 | {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"}, 767 | {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"}, 768 | {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"}, 769 | {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"}, 770 | {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"}, 771 | {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"}, 772 | {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"}, 773 | {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"}, 774 | {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"}, 775 | {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"}, 776 | {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"}, 777 | {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"}, 778 | {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"}, 779 | {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"}, 780 | {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"}, 781 | {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"}, 782 | {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"}, 783 | {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"}, 784 | {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"}, 785 | {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"}, 786 | {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"}, 787 | {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"}, 788 | {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"}, 789 | {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"}, 790 | {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"}, 791 | {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"}, 792 | {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"}, 793 | {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"}, 794 | {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"}, 795 | {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"}, 796 | {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"}, 797 | {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"}, 798 | {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"}, 799 | {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"}, 800 | {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"}, 801 | {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"}, 802 | {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"}, 803 | {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"}, 804 | {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"}, 805 | {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"}, 806 | {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"}, 807 | {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"}, 808 | {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"}, 809 | {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"}, 810 | {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"}, 811 | {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, 812 | ] 813 | 814 | [package.dependencies] 815 | tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} 816 | 817 | [package.extras] 818 | toml = ["tomli"] 819 | 820 | [[package]] 821 | name = "cryptography" 822 | version = "42.0.8" 823 | description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." 824 | optional = false 825 | python-versions = ">=3.7" 826 | files = [ 827 | {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, 828 | {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, 829 | {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, 830 | {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, 831 | {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, 832 | {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, 833 | {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, 834 | {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, 835 | {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, 836 | {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, 837 | {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, 838 | {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, 839 | {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, 840 | {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, 841 | {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, 842 | {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, 843 | {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, 844 | {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, 845 | {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, 846 | {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, 847 | {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, 848 | {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, 849 | {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, 850 | {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, 851 | {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, 852 | {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, 853 | {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, 854 | {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, 855 | {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, 856 | {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, 857 | {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, 858 | {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, 859 | ] 860 | 861 | [package.dependencies] 862 | cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} 863 | 864 | [package.extras] 865 | docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] 866 | docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] 867 | nox = ["nox"] 868 | pep8test = ["check-sdist", "click", "mypy", "ruff"] 869 | sdist = ["build"] 870 | ssh = ["bcrypt (>=3.1.5)"] 871 | test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] 872 | test-randomorder = ["pytest-randomly"] 873 | 874 | [[package]] 875 | name = "dill" 876 | version = "0.3.8" 877 | description = "serialize all of Python" 878 | optional = false 879 | python-versions = ">=3.8" 880 | files = [ 881 | {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, 882 | {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, 883 | ] 884 | 885 | [package.extras] 886 | graph = ["objgraph (>=1.7.2)"] 887 | profile = ["gprof2dot (>=2022.7.29)"] 888 | 889 | [[package]] 890 | name = "exceptiongroup" 891 | version = "1.2.0" 892 | description = "Backport of PEP 654 (exception groups)" 893 | optional = false 894 | python-versions = ">=3.7" 895 | files = [ 896 | {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, 897 | {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, 898 | ] 899 | 900 | [package.extras] 901 | test = ["pytest (>=6)"] 902 | 903 | [[package]] 904 | name = "idna" 905 | version = "3.7" 906 | description = "Internationalized Domain Names in Applications (IDNA)" 907 | optional = false 908 | python-versions = ">=3.5" 909 | files = [ 910 | {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, 911 | {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, 912 | ] 913 | 914 | [[package]] 915 | name = "iniconfig" 916 | version = "2.0.0" 917 | description = "brain-dead simple config-ini parsing" 918 | optional = false 919 | python-versions = ">=3.7" 920 | files = [ 921 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 922 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 923 | ] 924 | 925 | [[package]] 926 | name = "isort" 927 | version = "5.13.2" 928 | description = "A Python utility / library to sort Python imports." 929 | optional = false 930 | python-versions = ">=3.8.0" 931 | files = [ 932 | {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, 933 | {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, 934 | ] 935 | 936 | [package.extras] 937 | colors = ["colorama (>=0.4.6)"] 938 | 939 | [[package]] 940 | name = "jinja2" 941 | version = "3.1.4" 942 | description = "A very fast and expressive template engine." 943 | optional = false 944 | python-versions = ">=3.7" 945 | files = [ 946 | {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, 947 | {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, 948 | ] 949 | 950 | [package.dependencies] 951 | MarkupSafe = ">=2.0" 952 | 953 | [package.extras] 954 | i18n = ["Babel (>=2.7)"] 955 | 956 | [[package]] 957 | name = "jmespath" 958 | version = "1.0.1" 959 | description = "JSON Matching Expressions" 960 | optional = false 961 | python-versions = ">=3.7" 962 | files = [ 963 | {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, 964 | {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, 965 | ] 966 | 967 | [[package]] 968 | name = "markdown-it-py" 969 | version = "3.0.0" 970 | description = "Python port of markdown-it. Markdown parsing, done right!" 971 | optional = false 972 | python-versions = ">=3.8" 973 | files = [ 974 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, 975 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, 976 | ] 977 | 978 | [package.dependencies] 979 | mdurl = ">=0.1,<1.0" 980 | 981 | [package.extras] 982 | benchmarking = ["psutil", "pytest", "pytest-benchmark"] 983 | code-style = ["pre-commit (>=3.0,<4.0)"] 984 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] 985 | linkify = ["linkify-it-py (>=1,<3)"] 986 | plugins = ["mdit-py-plugins"] 987 | profiling = ["gprof2dot"] 988 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] 989 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] 990 | 991 | [[package]] 992 | name = "markupsafe" 993 | version = "2.1.4" 994 | description = "Safely add untrusted strings to HTML/XML markup." 995 | optional = false 996 | python-versions = ">=3.7" 997 | files = [ 998 | {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, 999 | {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, 1000 | {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, 1001 | {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, 1002 | {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, 1003 | {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, 1004 | {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, 1005 | {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, 1006 | {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, 1007 | {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, 1008 | {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, 1009 | {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, 1010 | {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, 1011 | {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, 1012 | {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, 1013 | {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, 1014 | {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, 1015 | {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, 1016 | {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, 1017 | {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, 1018 | {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, 1019 | {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, 1020 | {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, 1021 | {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, 1022 | {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, 1023 | {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, 1024 | {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, 1025 | {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, 1026 | {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, 1027 | {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, 1028 | {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, 1029 | {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, 1030 | {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, 1031 | {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, 1032 | {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, 1033 | {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, 1034 | {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, 1035 | {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, 1036 | {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, 1037 | {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, 1038 | {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, 1039 | {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, 1040 | {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, 1041 | {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, 1042 | {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, 1043 | {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, 1044 | {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, 1045 | {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, 1046 | {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, 1047 | {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, 1048 | {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, 1049 | {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, 1050 | {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, 1051 | {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, 1052 | {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, 1053 | {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, 1054 | {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, 1055 | {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, 1056 | {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, 1057 | {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "mccabe" 1062 | version = "0.7.0" 1063 | description = "McCabe checker, plugin for flake8" 1064 | optional = false 1065 | python-versions = ">=3.6" 1066 | files = [ 1067 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, 1068 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, 1069 | ] 1070 | 1071 | [[package]] 1072 | name = "mdurl" 1073 | version = "0.1.2" 1074 | description = "Markdown URL utilities" 1075 | optional = false 1076 | python-versions = ">=3.7" 1077 | files = [ 1078 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 1079 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "moto" 1084 | version = "5.0.11" 1085 | description = "" 1086 | optional = false 1087 | python-versions = ">=3.8" 1088 | files = [ 1089 | {file = "moto-5.0.11-py2.py3-none-any.whl", hash = "sha256:bdba9bec0afcde9f99b58c5271d6458dbfcda0a0a1e9beaecd808d2591db65ea"}, 1090 | {file = "moto-5.0.11.tar.gz", hash = "sha256:606b641f4c6ef69f28a84147d6d6806d052011e7ae7b0fe46ae8858e7a27a0a3"}, 1091 | ] 1092 | 1093 | [package.dependencies] 1094 | boto3 = ">=1.9.201" 1095 | botocore = ">=1.14.0" 1096 | cryptography = ">=3.3.1" 1097 | Jinja2 = ">=2.10.1" 1098 | python-dateutil = ">=2.1,<3.0.0" 1099 | requests = ">=2.5" 1100 | responses = ">=0.15.0" 1101 | werkzeug = ">=0.5,<2.2.0 || >2.2.0,<2.2.1 || >2.2.1" 1102 | xmltodict = "*" 1103 | 1104 | [package.extras] 1105 | all = ["PyYAML (>=5.1)", "antlr4-python3-runtime", "aws-xray-sdk (>=0.93,!=0.96)", "cfn-lint (>=0.40.0)", "docker (>=3.0.0)", "graphql-core", "joserfc (>=0.9.0)", "jsondiff (>=1.1.2)", "jsonpath-ng", "multipart", "openapi-spec-validator (>=0.5.0)", "py-partiql-parser (==0.5.5)", "pyparsing (>=3.0.7)", "setuptools"] 1106 | apigateway = ["PyYAML (>=5.1)", "joserfc (>=0.9.0)", "openapi-spec-validator (>=0.5.0)"] 1107 | apigatewayv2 = ["PyYAML (>=5.1)", "openapi-spec-validator (>=0.5.0)"] 1108 | appsync = ["graphql-core"] 1109 | awslambda = ["docker (>=3.0.0)"] 1110 | batch = ["docker (>=3.0.0)"] 1111 | cloudformation = ["PyYAML (>=5.1)", "aws-xray-sdk (>=0.93,!=0.96)", "cfn-lint (>=0.40.0)", "docker (>=3.0.0)", "graphql-core", "joserfc (>=0.9.0)", "jsondiff (>=1.1.2)", "openapi-spec-validator (>=0.5.0)", "py-partiql-parser (==0.5.5)", "pyparsing (>=3.0.7)", "setuptools"] 1112 | cognitoidp = ["joserfc (>=0.9.0)"] 1113 | dynamodb = ["docker (>=3.0.0)", "py-partiql-parser (==0.5.5)"] 1114 | dynamodbstreams = ["docker (>=3.0.0)", "py-partiql-parser (==0.5.5)"] 1115 | glue = ["pyparsing (>=3.0.7)"] 1116 | iotdata = ["jsondiff (>=1.1.2)"] 1117 | proxy = ["PyYAML (>=5.1)", "antlr4-python3-runtime", "aws-xray-sdk (>=0.93,!=0.96)", "cfn-lint (>=0.40.0)", "docker (>=2.5.1)", "graphql-core", "joserfc (>=0.9.0)", "jsondiff (>=1.1.2)", "jsonpath-ng", "multipart", "openapi-spec-validator (>=0.5.0)", "py-partiql-parser (==0.5.5)", "pyparsing (>=3.0.7)", "setuptools"] 1118 | resourcegroupstaggingapi = ["PyYAML (>=5.1)", "cfn-lint (>=0.40.0)", "docker (>=3.0.0)", "graphql-core", "joserfc (>=0.9.0)", "jsondiff (>=1.1.2)", "openapi-spec-validator (>=0.5.0)", "py-partiql-parser (==0.5.5)", "pyparsing (>=3.0.7)"] 1119 | s3 = ["PyYAML (>=5.1)", "py-partiql-parser (==0.5.5)"] 1120 | s3crc32c = ["PyYAML (>=5.1)", "crc32c", "py-partiql-parser (==0.5.5)"] 1121 | server = ["PyYAML (>=5.1)", "antlr4-python3-runtime", "aws-xray-sdk (>=0.93,!=0.96)", "cfn-lint (>=0.40.0)", "docker (>=3.0.0)", "flask (!=2.2.0,!=2.2.1)", "flask-cors", "graphql-core", "joserfc (>=0.9.0)", "jsondiff (>=1.1.2)", "jsonpath-ng", "openapi-spec-validator (>=0.5.0)", "py-partiql-parser (==0.5.5)", "pyparsing (>=3.0.7)", "setuptools"] 1122 | ssm = ["PyYAML (>=5.1)"] 1123 | stepfunctions = ["antlr4-python3-runtime", "jsonpath-ng"] 1124 | xray = ["aws-xray-sdk (>=0.93,!=0.96)", "setuptools"] 1125 | 1126 | [[package]] 1127 | name = "mypy" 1128 | version = "1.10.1" 1129 | description = "Optional static typing for Python" 1130 | optional = false 1131 | python-versions = ">=3.8" 1132 | files = [ 1133 | {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, 1134 | {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, 1135 | {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, 1136 | {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, 1137 | {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, 1138 | {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, 1139 | {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, 1140 | {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, 1141 | {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, 1142 | {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, 1143 | {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, 1144 | {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, 1145 | {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, 1146 | {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, 1147 | {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, 1148 | {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, 1149 | {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, 1150 | {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, 1151 | {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, 1152 | {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, 1153 | {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, 1154 | {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, 1155 | {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, 1156 | {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, 1157 | {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, 1158 | {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, 1159 | {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, 1160 | ] 1161 | 1162 | [package.dependencies] 1163 | mypy-extensions = ">=1.0.0" 1164 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 1165 | typing-extensions = ">=4.1.0" 1166 | 1167 | [package.extras] 1168 | dmypy = ["psutil (>=4.0)"] 1169 | install-types = ["pip"] 1170 | mypyc = ["setuptools (>=50)"] 1171 | reports = ["lxml"] 1172 | 1173 | [[package]] 1174 | name = "mypy-boto3-kms" 1175 | version = "1.34.14" 1176 | description = "Type annotations for boto3.KMS 1.34.14 service generated with mypy-boto3-builder 7.23.0" 1177 | optional = false 1178 | python-versions = ">=3.8" 1179 | files = [ 1180 | {file = "mypy-boto3-kms-1.34.14.tar.gz", hash = "sha256:7c6b937550a681da9a61d25c10963bbe1bcdc3e422d4d5d81524f5ea65e9d140"}, 1181 | {file = "mypy_boto3_kms-1.34.14-py3-none-any.whl", hash = "sha256:3e884b78d7d668ad9e113c079be4ca7c66cf12398480f6bae71a0cde64a21e55"}, 1182 | ] 1183 | 1184 | [package.dependencies] 1185 | typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} 1186 | 1187 | [[package]] 1188 | name = "mypy-extensions" 1189 | version = "1.0.0" 1190 | description = "Type system extensions for programs checked with the mypy type checker." 1191 | optional = false 1192 | python-versions = ">=3.5" 1193 | files = [ 1194 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 1195 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "packaging" 1200 | version = "23.2" 1201 | description = "Core utilities for Python packages" 1202 | optional = false 1203 | python-versions = ">=3.7" 1204 | files = [ 1205 | {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, 1206 | {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "pathspec" 1211 | version = "0.12.1" 1212 | description = "Utility library for gitignore style pattern matching of file paths." 1213 | optional = false 1214 | python-versions = ">=3.8" 1215 | files = [ 1216 | {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, 1217 | {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "pbr" 1222 | version = "6.0.0" 1223 | description = "Python Build Reasonableness" 1224 | optional = false 1225 | python-versions = ">=2.6" 1226 | files = [ 1227 | {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, 1228 | {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, 1229 | ] 1230 | 1231 | [[package]] 1232 | name = "platformdirs" 1233 | version = "4.2.0" 1234 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 1235 | optional = false 1236 | python-versions = ">=3.8" 1237 | files = [ 1238 | {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, 1239 | {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, 1240 | ] 1241 | 1242 | [package.extras] 1243 | docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] 1244 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] 1245 | 1246 | [[package]] 1247 | name = "pluggy" 1248 | version = "1.5.0" 1249 | description = "plugin and hook calling mechanisms for python" 1250 | optional = false 1251 | python-versions = ">=3.8" 1252 | files = [ 1253 | {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, 1254 | {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, 1255 | ] 1256 | 1257 | [package.extras] 1258 | dev = ["pre-commit", "tox"] 1259 | testing = ["pytest", "pytest-benchmark"] 1260 | 1261 | [[package]] 1262 | name = "pycparser" 1263 | version = "2.21" 1264 | description = "C parser in Python" 1265 | optional = false 1266 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 1267 | files = [ 1268 | {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, 1269 | {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "pygments" 1274 | version = "2.17.2" 1275 | description = "Pygments is a syntax highlighting package written in Python." 1276 | optional = false 1277 | python-versions = ">=3.7" 1278 | files = [ 1279 | {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, 1280 | {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, 1281 | ] 1282 | 1283 | [package.extras] 1284 | plugins = ["importlib-metadata"] 1285 | windows-terminal = ["colorama (>=0.4.6)"] 1286 | 1287 | [[package]] 1288 | name = "pylint" 1289 | version = "3.2.5" 1290 | description = "python code static checker" 1291 | optional = false 1292 | python-versions = ">=3.8.0" 1293 | files = [ 1294 | {file = "pylint-3.2.5-py3-none-any.whl", hash = "sha256:32cd6c042b5004b8e857d727708720c54a676d1e22917cf1a2df9b4d4868abd6"}, 1295 | {file = "pylint-3.2.5.tar.gz", hash = "sha256:e9b7171e242dcc6ebd0aaa7540481d1a72860748a0a7816b8fe6cf6c80a6fe7e"}, 1296 | ] 1297 | 1298 | [package.dependencies] 1299 | astroid = ">=3.2.2,<=3.3.0-dev0" 1300 | colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} 1301 | dill = [ 1302 | {version = ">=0.2", markers = "python_version < \"3.11\""}, 1303 | {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, 1304 | {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, 1305 | ] 1306 | isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" 1307 | mccabe = ">=0.6,<0.8" 1308 | platformdirs = ">=2.2.0" 1309 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 1310 | tomlkit = ">=0.10.1" 1311 | typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} 1312 | 1313 | [package.extras] 1314 | spelling = ["pyenchant (>=3.2,<4.0)"] 1315 | testutils = ["gitpython (>3)"] 1316 | 1317 | [[package]] 1318 | name = "pytest" 1319 | version = "8.2.2" 1320 | description = "pytest: simple powerful testing with Python" 1321 | optional = false 1322 | python-versions = ">=3.8" 1323 | files = [ 1324 | {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, 1325 | {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, 1326 | ] 1327 | 1328 | [package.dependencies] 1329 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 1330 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 1331 | iniconfig = "*" 1332 | packaging = "*" 1333 | pluggy = ">=1.5,<2.0" 1334 | tomli = {version = ">=1", markers = "python_version < \"3.11\""} 1335 | 1336 | [package.extras] 1337 | dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] 1338 | 1339 | [[package]] 1340 | name = "pytest-cov" 1341 | version = "5.0.0" 1342 | description = "Pytest plugin for measuring coverage." 1343 | optional = false 1344 | python-versions = ">=3.8" 1345 | files = [ 1346 | {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, 1347 | {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, 1348 | ] 1349 | 1350 | [package.dependencies] 1351 | coverage = {version = ">=5.2.1", extras = ["toml"]} 1352 | pytest = ">=4.6" 1353 | 1354 | [package.extras] 1355 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] 1356 | 1357 | [[package]] 1358 | name = "python-dateutil" 1359 | version = "2.8.2" 1360 | description = "Extensions to the standard Python datetime module" 1361 | optional = false 1362 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 1363 | files = [ 1364 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, 1365 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, 1366 | ] 1367 | 1368 | [package.dependencies] 1369 | six = ">=1.5" 1370 | 1371 | [[package]] 1372 | name = "pyyaml" 1373 | version = "6.0.1" 1374 | description = "YAML parser and emitter for Python" 1375 | optional = false 1376 | python-versions = ">=3.6" 1377 | files = [ 1378 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, 1379 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, 1380 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, 1381 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, 1382 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, 1383 | {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, 1384 | {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, 1385 | {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, 1386 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, 1387 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, 1388 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, 1389 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, 1390 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, 1391 | {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, 1392 | {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, 1393 | {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, 1394 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, 1395 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, 1396 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, 1397 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, 1398 | {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, 1399 | {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, 1400 | {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, 1401 | {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, 1402 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, 1403 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, 1404 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, 1405 | {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, 1406 | {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, 1407 | {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, 1408 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, 1409 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, 1410 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, 1411 | {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, 1412 | {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, 1413 | {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, 1414 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, 1415 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, 1416 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, 1417 | {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, 1418 | {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, 1419 | {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, 1420 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, 1421 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, 1422 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, 1423 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, 1424 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, 1425 | {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, 1426 | {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, 1427 | {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, 1428 | {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "requests" 1433 | version = "2.32.2" 1434 | description = "Python HTTP for Humans." 1435 | optional = false 1436 | python-versions = ">=3.8" 1437 | files = [ 1438 | {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, 1439 | {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, 1440 | ] 1441 | 1442 | [package.dependencies] 1443 | certifi = ">=2017.4.17" 1444 | charset-normalizer = ">=2,<4" 1445 | idna = ">=2.5,<4" 1446 | urllib3 = ">=1.21.1,<3" 1447 | 1448 | [package.extras] 1449 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 1450 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 1451 | 1452 | [[package]] 1453 | name = "responses" 1454 | version = "0.24.1" 1455 | description = "A utility library for mocking out the `requests` Python library." 1456 | optional = false 1457 | python-versions = ">=3.8" 1458 | files = [ 1459 | {file = "responses-0.24.1-py3-none-any.whl", hash = "sha256:a2b43f4c08bfb9c9bd242568328c65a34b318741d3fab884ac843c5ceeb543f9"}, 1460 | {file = "responses-0.24.1.tar.gz", hash = "sha256:b127c6ca3f8df0eb9cc82fd93109a3007a86acb24871834c47b77765152ecf8c"}, 1461 | ] 1462 | 1463 | [package.dependencies] 1464 | pyyaml = "*" 1465 | requests = ">=2.30.0,<3.0" 1466 | urllib3 = ">=1.25.10,<3.0" 1467 | 1468 | [package.extras] 1469 | tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli", "tomli-w", "types-PyYAML", "types-requests"] 1470 | 1471 | [[package]] 1472 | name = "rich" 1473 | version = "13.7.0" 1474 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 1475 | optional = false 1476 | python-versions = ">=3.7.0" 1477 | files = [ 1478 | {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, 1479 | {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, 1480 | ] 1481 | 1482 | [package.dependencies] 1483 | markdown-it-py = ">=2.2.0" 1484 | pygments = ">=2.13.0,<3.0.0" 1485 | typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} 1486 | 1487 | [package.extras] 1488 | jupyter = ["ipywidgets (>=7.5.1,<9)"] 1489 | 1490 | [[package]] 1491 | name = "s3transfer" 1492 | version = "0.10.0" 1493 | description = "An Amazon S3 Transfer Manager" 1494 | optional = false 1495 | python-versions = ">= 3.8" 1496 | files = [ 1497 | {file = "s3transfer-0.10.0-py3-none-any.whl", hash = "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e"}, 1498 | {file = "s3transfer-0.10.0.tar.gz", hash = "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b"}, 1499 | ] 1500 | 1501 | [package.dependencies] 1502 | botocore = ">=1.33.2,<2.0a.0" 1503 | 1504 | [package.extras] 1505 | crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] 1506 | 1507 | [[package]] 1508 | name = "six" 1509 | version = "1.16.0" 1510 | description = "Python 2 and 3 compatibility utilities" 1511 | optional = false 1512 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 1513 | files = [ 1514 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 1515 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 1516 | ] 1517 | 1518 | [[package]] 1519 | name = "stevedore" 1520 | version = "5.1.0" 1521 | description = "Manage dynamic plugins for Python applications" 1522 | optional = false 1523 | python-versions = ">=3.8" 1524 | files = [ 1525 | {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, 1526 | {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, 1527 | ] 1528 | 1529 | [package.dependencies] 1530 | pbr = ">=2.0.0,<2.1.0 || >2.1.0" 1531 | 1532 | [[package]] 1533 | name = "tomli" 1534 | version = "2.0.1" 1535 | description = "A lil' TOML parser" 1536 | optional = false 1537 | python-versions = ">=3.7" 1538 | files = [ 1539 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 1540 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "tomlkit" 1545 | version = "0.12.3" 1546 | description = "Style preserving TOML library" 1547 | optional = false 1548 | python-versions = ">=3.7" 1549 | files = [ 1550 | {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, 1551 | {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, 1552 | ] 1553 | 1554 | [[package]] 1555 | name = "types-awscrt" 1556 | version = "0.20.3" 1557 | description = "Type annotations and code completion for awscrt" 1558 | optional = false 1559 | python-versions = ">=3.7,<4.0" 1560 | files = [ 1561 | {file = "types_awscrt-0.20.3-py3-none-any.whl", hash = "sha256:f61a120d3e98ee1387bc5ca4b93437f258cc5c2af1f55f8634ec4cee5729f178"}, 1562 | {file = "types_awscrt-0.20.3.tar.gz", hash = "sha256:06a859189a329ca8e66d56ceeef2391488e39b878fbd2141f115eab4d416fe22"}, 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "types-s3transfer" 1567 | version = "0.10.0" 1568 | description = "Type annotations and code completion for s3transfer" 1569 | optional = false 1570 | python-versions = ">=3.7,<4.0" 1571 | files = [ 1572 | {file = "types_s3transfer-0.10.0-py3-none-any.whl", hash = "sha256:44fcdf0097b924a9aab1ee4baa1179081a9559ca62a88c807e2b256893ce688f"}, 1573 | {file = "types_s3transfer-0.10.0.tar.gz", hash = "sha256:35e4998c25df7f8985ad69dedc8e4860e8af3b43b7615e940d53c00d413bdc69"}, 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "typing-extensions" 1578 | version = "4.9.0" 1579 | description = "Backported and Experimental Type Hints for Python 3.8+" 1580 | optional = false 1581 | python-versions = ">=3.8" 1582 | files = [ 1583 | {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, 1584 | {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "urllib3" 1589 | version = "1.26.19" 1590 | description = "HTTP library with thread-safe connection pooling, file post, and more." 1591 | optional = false 1592 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" 1593 | files = [ 1594 | {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, 1595 | {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, 1596 | ] 1597 | 1598 | [package.extras] 1599 | brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] 1600 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] 1601 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 1602 | 1603 | [[package]] 1604 | name = "werkzeug" 1605 | version = "3.0.3" 1606 | description = "The comprehensive WSGI web application library." 1607 | optional = false 1608 | python-versions = ">=3.8" 1609 | files = [ 1610 | {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, 1611 | {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, 1612 | ] 1613 | 1614 | [package.dependencies] 1615 | MarkupSafe = ">=2.1.1" 1616 | 1617 | [package.extras] 1618 | watchdog = ["watchdog (>=2.3)"] 1619 | 1620 | [[package]] 1621 | name = "xmltodict" 1622 | version = "0.13.0" 1623 | description = "Makes working with XML feel like you are working with JSON" 1624 | optional = false 1625 | python-versions = ">=3.4" 1626 | files = [ 1627 | {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, 1628 | {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, 1629 | ] 1630 | 1631 | [metadata] 1632 | lock-version = "2.0" 1633 | python-versions = ">=3.8,<4.0" 1634 | content-hash = "415398438405deff41514651831a4d4651279f1401eff19e5e30f6168c2e3fc7" 1635 | -------------------------------------------------------------------------------- /python/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sjakthol/aws-kms-crypt/3fa50eddefc65d8ff885d31c146f37dae69852c8/python/py.typed -------------------------------------------------------------------------------- /python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "aws-kms-crypt" 3 | version = "3.0.0" 4 | description = "Utility for encrypting and decrypting secrets with the AWS KMS service" 5 | authors = ["Sami Jaktholm "] 6 | license = "MIT" 7 | packages = [ 8 | {include = "kmscrypt"}, 9 | {include = "py.typed"} 10 | ] 11 | readme = 'README.md' 12 | 13 | [tool.poetry.dependencies] 14 | python = ">=3.8,<4.0" 15 | cryptography = ">=3.4,<43.0" 16 | boto3 = "^1.26.13" 17 | 18 | [tool.poetry.dev-dependencies] 19 | bandit = "^1.7.9" 20 | black = "^24.4.2" 21 | boto3-stubs = {extras = ["kms"], version = "^1.34.144"} 22 | mypy = "^1.10.1" 23 | pylint = "^3.2.5" 24 | pytest = "^8.2.2" 25 | pytest-cov = "^5.0" 26 | moto = {extras = ["kms"], version = "^5.0.11"} 27 | 28 | [build-system] 29 | requires = ["poetry-core>=1.0.0"] 30 | build-backend = "poetry.core.masonry.api" 31 | -------------------------------------------------------------------------------- /python/tests/test_crypto.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=missing-function-docstring,missing-module-docstring,redefined-outer-name 2 | import json 3 | 4 | import boto3 5 | import moto 6 | import pytest 7 | 8 | import kmscrypt 9 | 10 | 11 | @pytest.fixture(autouse=True) 12 | def mock_aws_env(monkeypatch): 13 | monkeypatch.setenv("AWS_ACCESS_KEY_ID", "testing") 14 | monkeypatch.setenv("AWS_DEFAULT_REGION", "eu-north-1") 15 | monkeypatch.setenv("AWS_SECRET_ACCESS_KEY", "testing") 16 | 17 | 18 | @pytest.fixture() 19 | def mock_kms_key(): 20 | with moto.mock_aws(): 21 | kms = boto3.client("kms") 22 | yield kms.create_key()["KeyMetadata"]["KeyId"] 23 | 24 | 25 | @pytest.mark.parametrize("data", [b"hello world!", "hello_world!"]) 26 | def test_encrypt_decrypt(mock_kms_key, data): 27 | encrypted = kmscrypt.encrypt(data, mock_kms_key, encryption_context={"Foo": "Bar"}) 28 | assert json.dumps(encrypted) 29 | assert encrypted["EncryptionContext"] == {"Foo": "Bar"} 30 | 31 | decrypted = kmscrypt.decrypt(encrypted) 32 | assert decrypted == data if isinstance(data, bytes) else data.encode() 33 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aws_kms_crypt" 3 | description = "Library for encrypting and decrypting secrets within the AWS ecosystem." 4 | license = "MIT" 5 | repository = "https://github.com/sjakthol/aws-kms-crypt" 6 | readme = "../README.md" 7 | version = "0.1.0" 8 | authors = ["Sami Jaktholm "] 9 | 10 | [dependencies] 11 | base64 = "0.7.0" 12 | base64-serde = "0.2.0" 13 | error-chain = "0.11.0" 14 | hex-serde = "0.1.0" 15 | openssl = "0.9.23" 16 | rand = "0.4" 17 | rusoto_core = "0.31.0" 18 | rusoto_kms = "0.31.0" 19 | serde = "1.0" 20 | serde_derive = "1.0" 21 | serde_json = "1.0" 22 | -------------------------------------------------------------------------------- /rust/examples/decrypt.rs: -------------------------------------------------------------------------------- 1 | extern crate aws_kms_crypt; 2 | 3 | // Optional; needed only if EncryptedSecret is deserialized from JSON string / Value 4 | extern crate serde_json; 5 | 6 | fn main() { 7 | let raw = r#"{ 8 | "EncryptedData": "vRhu+D5LrwNctyhxDvUoqL51YH2LclgUKtDz/2Nxy6Y=", 9 | "EncryptedDataKey": "AQIDAHhyrbU/fPcQ+a8pJiYC78j8wop4mw1jqy3CZk35rNUzEwFRrB1MZuSJ9fSjzh/ccg1FAAAAbjBsBgkqhkiG9w0BBwagXzBdAgEAMFgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM+3tP6OXBVMmw1CMsAgEQgCvFaTozKkl/fI4eX3LqAp+aW+FxpoEC57/aGKBFRpvDvpXNXu3e/tTO6Jfi", 10 | "EncryptionContext": { 11 | "entity": "admin" 12 | }, 13 | "Iv": "31bf06a8e0d15a26f1325da6f4f33a9c" 14 | }"#; 15 | 16 | let data: aws_kms_crypt::EncryptedSecret = serde_json::from_str(raw).unwrap(); 17 | let options = aws_kms_crypt::DecryptOptions { 18 | region: "eu-west-1".to_owned() 19 | }; 20 | 21 | let res = aws_kms_crypt::decrypt(&data, &options); 22 | println!("Secret is: {:?}", res.unwrap()); 23 | } 24 | -------------------------------------------------------------------------------- /rust/examples/encrypt.rs: -------------------------------------------------------------------------------- 1 | extern crate aws_kms_crypt; 2 | 3 | // Optional; needed only if EncryptedSecret is serialized into JSON string 4 | extern crate serde_json; 5 | 6 | use std::collections::HashMap; 7 | 8 | fn main() { 9 | let mut encryption_context = HashMap::new(); 10 | encryption_context.insert("entity".to_owned(), "admin".to_owned()); 11 | 12 | let options = aws_kms_crypt::EncryptOptions { 13 | encryption_context: encryption_context, 14 | key: "alias/common".into(), 15 | region: "eu-west-1".into() 16 | }; 17 | 18 | let data = "secret".into(); 19 | let res = aws_kms_crypt::encrypt(&data, &options); 20 | println!("{}", serde_json::to_string(&res.unwrap()).unwrap()); 21 | } 22 | -------------------------------------------------------------------------------- /rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A Rust implementation of aws-kms-crypt – a cross-language utility 2 | //! for encrypting and decrypting secrets with the AWS KMS service. 3 | //! 4 | //! # Features 5 | //! 6 | //! * Simple APIs for encrypting and decrypting secrets 7 | //! * Interoperable implementations for multiple languages (Shell, Node, Python and Rust) 8 | //! * [Envelope Encryption](https://docs.aws.amazon.com/kms/latest/developerguide/workflow.html) 9 | //! with `AES-128-CBC` and KMS generated data keys 10 | //! 11 | //! See [https://github.com/sjakthol/aws-kms-crypt](https://github.com/sjakthol/aws-kms-crypt) 12 | //! for general information about the library. 13 | 14 | #![recursion_limit = "1024"] 15 | 16 | extern crate base64; 17 | #[macro_use] 18 | extern crate base64_serde; 19 | #[macro_use] 20 | extern crate error_chain; 21 | extern crate hex_serde; 22 | extern crate openssl; 23 | extern crate rand; 24 | extern crate rusoto_core; 25 | extern crate rusoto_kms; 26 | extern crate serde; 27 | #[macro_use] 28 | extern crate serde_derive; 29 | extern crate serde_json; 30 | 31 | use rand::Rng; 32 | use rusoto_kms::{Kms, KmsClient}; 33 | use std::option::Option; 34 | use std::str::FromStr; 35 | use std::string::String; 36 | 37 | pub mod errors { 38 | //! Error constructs powered by [error_chain](https://github.com/rust-lang-nursery/error-chain) 39 | //! crate. 40 | //! 41 | //! See [ErrorKind](enum.ErrorKind.html) for details on different error variants. 42 | error_chain!{ 43 | errors { 44 | /// An error emitted if the AWS SDK fails iternally 45 | AwsSdkError(detail: String) { 46 | description("aws-sdk internal error") 47 | display("aws-sdk internal error: {}", detail) 48 | } 49 | 50 | /// An error emitted if AWS API call returns an error 51 | AwsError(detail: String) { 52 | description("aws call error") 53 | display("call to aws failed: {}", detail) 54 | } 55 | 56 | /// An error emitted if decryption fails 57 | DecryptFailed(detail: String) { 58 | description("decrypt failed") 59 | display("decrypt failed: {}", detail) 60 | } 61 | 62 | /// An error emitted if encryption fails 63 | EncryptFailed(detail: String) { 64 | description("encrypt failed") 65 | display("encrypt failed: {}", detail) 66 | } 67 | 68 | /// An error emitted if the region configured in options is 69 | /// invalid 70 | InvalidRegion(region: String) { 71 | description("invalid region") 72 | display("invalid region: '{}'", region) 73 | } 74 | } 75 | } 76 | } 77 | 78 | use errors::{ResultExt, ErrorKind}; 79 | 80 | base64_serde_type!(Base64Standard, base64::STANDARD); 81 | 82 | /// A struct that holds an encrypted secret. 83 | /// 84 | /// # Examples 85 | /// 86 | /// ## Create EncryptedSecret from JSON string 87 | /// ``` 88 | /// extern crate aws_kms_crypt; 89 | /// extern crate serde_json; 90 | /// 91 | /// let input = r#"{ 92 | /// "EncryptedData": "c2FtcGxlX2RhdGE=", 93 | /// "EncryptedDataKey": "c2FtcGxlX2RhdGFfa2V5", 94 | /// "EncryptionContext": { 95 | /// "entity": "test" 96 | /// }, 97 | /// "Iv": "73616D706C655F6976" 98 | /// }"#; 99 | /// 100 | /// let data: aws_kms_crypt::EncryptedSecret = serde_json::from_str(input).unwrap(); 101 | /// # assert_eq!(data.EncryptedData, "sample_data".to_owned().into_bytes()); 102 | /// # assert_eq!(data.EncryptedDataKey, "sample_data_key".to_owned().into_bytes()); 103 | /// # assert_eq!(data.Iv, "sample_iv".to_owned().into_bytes()); 104 | /// ``` 105 | #[allow(non_snake_case)] 106 | #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] 107 | pub struct EncryptedSecret { 108 | /// AES encrypted secret 109 | #[serde(with = "Base64Standard")] 110 | pub EncryptedData: Vec, 111 | 112 | /// AWS KMS encrypted data encryption key 113 | #[serde(with = "Base64Standard")] 114 | pub EncryptedDataKey: Vec, 115 | 116 | /// AWS KMS encryption context 117 | pub EncryptionContext: std::collections::HashMap, 118 | 119 | /// AES initialization vector 120 | #[serde(with = "hex_serde")] 121 | pub Iv: Vec 122 | } 123 | 124 | /// Options for decryption 125 | #[derive(Clone, Debug, Default)] 126 | pub struct DecryptOptions { 127 | /// The AWS region to use when calling KMS 128 | pub region: String 129 | } 130 | 131 | /// Options for encryption 132 | #[derive(Clone, Debug, Default)] 133 | pub struct EncryptOptions { 134 | /// The AWS region to use when calling KMS 135 | pub region: String, 136 | 137 | /// KMS key ID, ARN, alias or alias ARN 138 | pub key: String, 139 | 140 | /// AWS KMS encryption context 141 | pub encryption_context: std::collections::HashMap 142 | } 143 | 144 | /// Decrypt a previously encrypted secret. 145 | /// 146 | /// # Examples 147 | /// ``` 148 | /// extern crate aws_kms_crypt; 149 | /// extern crate serde_json; 150 | /// let raw = r#"{ 151 | /// "EncryptedData": "vRhu+D5LrwNctyhxDvUoqL51YH2LclgUKtDz/2Nxy6Y=", 152 | /// "EncryptedDataKey": "AQIDAHhyrbU/fPcQ+a8pJiYC78j8wop4mw1jqy3CZk35rNUzEwFRrB1MZuSJ9fSjzh/ccg1FAAAAbjBsBgkqhkiG9w0BBwagXzBdAgEAMFgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM+3tP6OXBVMmw1CMsAgEQgCvFaTozKkl/fI4eX3LqAp+aW+FxpoEC57/aGKBFRpvDvpXNXu3e/tTO6Jfi", 153 | /// "EncryptionContext": { 154 | /// "entity": "admin" 155 | /// }, 156 | /// "Iv": "31bf06a8e0d15a26f1325da6f4f33a9c" 157 | /// }"#; 158 | /// 159 | /// let data: aws_kms_crypt::EncryptedSecret = serde_json::from_str(raw).unwrap(); 160 | /// let options = aws_kms_crypt::DecryptOptions { 161 | /// region: "eu-west-1".to_owned() 162 | /// }; 163 | /// 164 | /// let res = aws_kms_crypt::decrypt(&data, &options); 165 | /// ``` 166 | pub fn decrypt(data: &EncryptedSecret, options: &DecryptOptions) -> errors::Result { 167 | let key = decrypt_data_key(data, options)?; 168 | let iv = Option::Some(&data.Iv[..]); 169 | let encrypted = &data.EncryptedData; 170 | 171 | let cipher = openssl::symm::Cipher::aes_128_cbc(); 172 | let res = openssl::symm::decrypt(cipher, &key, iv, encrypted) 173 | .chain_err(|| ErrorKind::DecryptFailed("openssl error".into()))?; 174 | 175 | let decoded = String::from_utf8(res) 176 | .chain_err(|| ErrorKind::DecryptFailed("secret not valid utf-8".into()))?; 177 | 178 | Ok(decoded) 179 | } 180 | 181 | /// Encrypt a secret with KMS. 182 | /// 183 | /// # Examples 184 | /// ``` 185 | /// extern crate aws_kms_crypt; 186 | /// extern crate serde_json; 187 | /// 188 | /// use std::collections::HashMap; 189 | /// 190 | /// let mut encryption_context = HashMap::new(); 191 | /// encryption_context.insert("entity".to_owned(), "admin".to_owned()); 192 | /// 193 | /// let options = aws_kms_crypt::EncryptOptions { 194 | /// encryption_context: encryption_context, 195 | /// key: "alias/common".into(), 196 | /// region: "eu-west-1".into() 197 | /// }; 198 | /// 199 | /// let data = "secret".into(); 200 | /// let res = aws_kms_crypt::encrypt(&data, &options); 201 | /// ``` 202 | pub fn encrypt(data: &String, options: &EncryptOptions) -> errors::Result { 203 | let datakey = generate_data_key(options)?; 204 | let key = datakey.plaintext 205 | .chain_err(|| ErrorKind::AwsError("KMS.GenerateDataKey() didn't return plaintext".into()))?; 206 | let key_enc = datakey.ciphertext_blob 207 | .chain_err(|| ErrorKind::AwsError("KMS.GenerateDataKey() didn't return plaintext".into()))?; 208 | let iv = rand::thread_rng() 209 | .gen_iter::() 210 | .take(16) 211 | .collect::>(); 212 | 213 | let cipher = openssl::symm::Cipher::aes_128_cbc(); 214 | let res = openssl::symm::encrypt(cipher, &key, Option::Some(&iv), data.as_bytes()) 215 | .chain_err(|| ErrorKind::DecryptFailed("openssl error".into()))?; 216 | 217 | Ok(EncryptedSecret { 218 | EncryptedData: res.clone(), 219 | EncryptedDataKey: key_enc, 220 | EncryptionContext: options.encryption_context.clone(), 221 | Iv: iv 222 | }) 223 | } 224 | 225 | fn generate_data_key(options: &EncryptOptions) -> errors::Result { 226 | let client = rusoto_core::default_tls_client() 227 | .chain_err(|| ErrorKind::AwsSdkError("failed to build http client".into()))?; 228 | let credentials = rusoto_core::DefaultCredentialsProvider::new() 229 | .chain_err(|| ErrorKind::AwsSdkError("failed to build credential provider".into()))?; 230 | let region = rusoto_core::Region::from_str(&options.region) 231 | .chain_err(|| ErrorKind::InvalidRegion(options.region.clone()))?; 232 | 233 | let kms = KmsClient::new(client, credentials, region); 234 | let req = rusoto_kms::GenerateDataKeyRequest { 235 | encryption_context: Option::Some(options.encryption_context.clone()), 236 | key_id: options.key.clone(), 237 | key_spec: Option::Some("AES_128".into()), 238 | grant_tokens: Option::None, 239 | number_of_bytes: Option::None 240 | }; 241 | 242 | let res = kms.generate_data_key(&req) 243 | .chain_err(|| ErrorKind::AwsError("KMS.GenerateDataKey() failed".into()))?; 244 | 245 | Ok(res) 246 | } 247 | 248 | fn decrypt_data_key(data: &EncryptedSecret, options: &DecryptOptions) -> errors::Result> { 249 | let client = rusoto_core::default_tls_client() 250 | .chain_err(|| ErrorKind::AwsSdkError("failed to build http client".into()))?; 251 | let credentials = rusoto_core::DefaultCredentialsProvider::new() 252 | .chain_err(|| ErrorKind::AwsSdkError("failed to build credential provider".into()))?; 253 | let region = rusoto_core::Region::from_str(&options.region) 254 | .chain_err(|| ErrorKind::InvalidRegion(options.region.clone()))?; 255 | 256 | let kms = KmsClient::new(client, credentials, region); 257 | let req = rusoto_kms::DecryptRequest { 258 | ciphertext_blob: data.EncryptedDataKey.clone(), 259 | encryption_context: Option::Some(data.EncryptionContext.clone()), 260 | grant_tokens: Option::None, 261 | }; 262 | 263 | let res = kms.decrypt(&req) 264 | .chain_err(|| ErrorKind::AwsError("KMS.Decrypt() failed".into()))?; 265 | let key = res.plaintext 266 | .chain_err(|| ErrorKind::AwsError("KMS.Decrypt() didn't return plaintext".into()))?; 267 | 268 | Ok(key) 269 | } 270 | 271 | #[cfg(test)] 272 | mod test { 273 | use super::*; 274 | 275 | #[test] 276 | fn test_invalid_region() { 277 | let raw = r#"{ 278 | "EncryptedData": "vRhu+D5LrwNctyhxDvUoqL51YH2LclgUKtDz/2Nxy6Y=", 279 | "EncryptedDataKey": "agXzBdAgEAMFgGCSqGSIb3DQEHATAeBglghkgBZQME", 280 | "EncryptionContext": { 281 | "entity": "admin" 282 | }, 283 | "Iv": "31bf06a8e0d15a26f1325da6f4f33a9c" 284 | }"#; 285 | 286 | let data: EncryptedSecret = serde_json::from_str(raw).unwrap(); 287 | let options = DecryptOptions { 288 | region: "eu-wst-1".to_owned() 289 | }; 290 | 291 | let res = decrypt(&data, &options); 292 | match res { 293 | Err(errors::Error(ErrorKind::InvalidRegion(_), _)) => { 294 | assert_eq!(true, true); 295 | } 296 | _ => { panic!("Unexpected error {:?}", res); } 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /shell/aws-kms-crypt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | AES_KEY_LENGTH=16 # 16 bytes => 128 bit AES 6 | AES_KEY_LENGTH_HEX=32 # 16 bytes translates to 32 digits in hex 7 | AES_IV_LENGTH=16 8 | AES_IV_LENGTH_HEX=32 9 | 10 | required_commands=("aws" "openssl" "base64" "jq" "cut" "sed" "od") 11 | operation="" 12 | kms_key_id="" 13 | encryption_context="{}" 14 | 15 | main() { 16 | check_required_commands 17 | parse_args "$@" 18 | 19 | if [ "$operation" = "encrypt" ]; then 20 | do_encrypt 21 | elif [ "$operation" = "decrypt" ]; then 22 | do_decrypt 23 | fi 24 | } 25 | 26 | do_encrypt() { 27 | log_info "Encrypting data with key $kms_key_id (${encryption_context:-empty encryption context})" 28 | log_debug "Generating $AES_IV_LENGTH random bytes for IV" 29 | 30 | # NOTE: read + subshells used there to make the script fail if 31 | # the commands generating the important numbers fail 32 | 33 | # Generate the initialization vector 34 | local iv_b64 35 | read iv_b64 < \ 36 | <(aws kms generate-random \ 37 | --number-of-bytes $AES_IV_LENGTH \ 38 | --output text \ 39 | --query Plaintext) 40 | local iv_hex="$(base64tohex "$iv_b64")" 41 | log_debug "Generated IV: hex=$iv_hex, b64=$iv_b64" 42 | 43 | local key_enc key_b64; 44 | log_debug "Generating encrypted data key" 45 | read key_b64 key_enc < \ 46 | <(aws kms generate-data-key \ 47 | --key-id "$kms_key_id" \ 48 | --encryption-context "$encryption_context" \ 49 | --key-spec AES_128 \ 50 | --output text --query '[Plaintext,CiphertextBlob]') 51 | local key_hex="$(base64tohex "$key_b64")" 52 | log_debug "Generated Data Key: hex=$key_hex, b64=$key_b64, enc=$key_enc" 53 | 54 | # Some important sanity checks 55 | if [ "${#iv_hex}" != "$AES_IV_LENGTH_HEX" ]; then 56 | log_error "Failed to generate initialization vector for encryption (${iv_hex:-(empty)} is not a valid IV)" 57 | exit 3 58 | fi 59 | 60 | if [ "${#key_hex}" != "$AES_KEY_LENGTH_HEX" ]; then 61 | log_error "Failed to generate datakey for encryption (${key:-(empty)} is not a valid key)" 62 | exit 3 63 | fi 64 | 65 | # Do the encryption 66 | local encrypted_data 67 | read encrypted_data < \ 68 | <(openssl enc -aes-128-cbc -a \ 69 | -K "$key_hex" \ 70 | -iv "$iv_hex" 71 | ) 72 | log_debug "encrypted_data = $encrypted_data" 73 | 74 | # Formulate the output 75 | jq -n \ 76 | --arg EncryptedData "$encrypted_data" \ 77 | --arg EncryptedDataKey "$key_enc" \ 78 | --arg EncryptionContext "$encryption_context" \ 79 | --arg Iv "$iv_hex" \ 80 | '{ EncryptedData: $EncryptedData, 81 | EncryptedDataKey: $EncryptedDataKey, 82 | EncryptionContext: $EncryptionContext | fromjson, 83 | Iv: $Iv }' 84 | 85 | } 86 | 87 | do_decrypt() { 88 | # Extract the details from input 89 | local parsed_variables="$(jq -r '@sh " 90 | local encrypted_data=\(.EncryptedData) 91 | local key_enc=\(.EncryptedDataKey) 92 | local encryption_context=\(.EncryptionContext | tojson) 93 | local iv_hex=\(.Iv) 94 | "')" 95 | 96 | if [ -z "$parsed_variables" ]; then 97 | log_error "Failed to parse input from stdin" 98 | exit 5 99 | fi 100 | 101 | eval "$parsed_variables" 102 | 103 | log_debug "data = $encrypted_data" 104 | log_debug "key = $key_enc" 105 | log_debug "ctx = $encryption_context" 106 | log_debug "iv = $iv_hex" 107 | 108 | # Decrypt the data key 109 | local key_b64 110 | log_debug "Decrypting encrypted datakey" 111 | read key_b64 < \ 112 | <(echo "$key_enc" | base64 -d | aws kms decrypt --encryption-context "$encryption_context" --ciphertext-blob fileb:///dev/stdin --output text --query Plaintext) 113 | local key_hex="$(base64tohex "$key_b64")" 114 | log_debug "Decrypted Data Key: hex=$key_hex, b64=$key_b64, enc=$key_enc" 115 | 116 | # Decrypt! 117 | openssl enc -aes-128-cbc -d -a \ 118 | -K "$key_hex" \ 119 | -iv "$iv_hex" <<< "$encrypted_data" 120 | } 121 | 122 | # Helper to turn short (<= 16 bytes) of base64 encoded data into hex strings 123 | base64tohex() { 124 | (base64 -d | od -t x1 | cut -s -d " " -f 2- | sed "s/ //g") <<< "$1" 125 | } 126 | 127 | # Check that required apps can be found from the path 128 | check_required_commands() { 129 | for cmd in ${required_commands[@]}; do 130 | if ! which $cmd > /dev/null 2>&1; then 131 | log_error "$cmd is required but not found from PATH" 132 | exit 1 133 | fi 134 | done 135 | } 136 | 137 | # Parses the arguments to figure out what should be done 138 | parse_args() { 139 | operation="${1:-}"; 140 | 141 | while [ $# -gt 1 ]; do 142 | shift 143 | 144 | case $1 in 145 | -k|--kms-key-id) 146 | kms_key_id="$2"; shift 147 | ;; 148 | -e|--encryption-context) 149 | encryption_context="$2"; shift 150 | ;; 151 | esac 152 | 153 | done 154 | 155 | if [ -z "$operation" ]; then 156 | exit_arg_failure "Operation missing" 157 | fi 158 | 159 | if [ "$operation" != "decrypt" ] && [ "$operation" != "encrypt" ]; then 160 | exit_arg_failure "Invalid operation: $operation" 161 | fi 162 | 163 | if [ "$operation" == "encrypt" ]; then 164 | if [ -z "$kms_key_id" ]; then 165 | exit_arg_failure "encrypt requires -k or --kms-key-id argument" 166 | fi 167 | fi 168 | 169 | if [ -n "$encryption_context" ]; then 170 | local parsed_ctx 171 | read parsed_ctx < <(echo "$encryption_context" | jq .) 172 | 173 | if [ -z "$parsed_ctx" ]; then 174 | exit_arg_failure "failed to parse the provided encryption context (must be valid JSON)" 175 | fi 176 | fi 177 | } 178 | 179 | exit_arg_failure() { 180 | log_error "$@" 181 | usage 182 | exit 2 183 | } 184 | 185 | # Helpers for logging messages 186 | log_msg() { 187 | local level="$1"; shift 188 | echo "[$(date -Iseconds)] $level: $@" >&2 189 | } 190 | log_error() { log_msg "ERROR" "$@"; } 191 | log_warn() { log_msg "WARNING" "$@"; } 192 | log_info() { log_msg "INFO" "$@"; } 193 | log_debug() { 194 | if [ -n "${DEBUG:-}" ]; then 195 | log_msg "DEBUG" "$@" 196 | fi 197 | } 198 | 199 | usage() { 200 | log_info "Usage:" 201 | log_info " $0 encrypt --kms-key-id [--encryption-context KeyName1=1,KeyName2=2]" 202 | log_info " $0 decrypt [--encryption-context KeyName1=1,KeyName2=2]" 203 | } 204 | 205 | main "$@" 206 | --------------------------------------------------------------------------------