diff --git a/package-lock.json b/package-lock.json index beb9411..a3e46ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@aws-sdk/client-kms": "^3.716.0", "@nestjs/common": "^10.4.15", "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.4.15", @@ -200,6 +201,673 @@ "node": ">=0.12.0" } }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-kms": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.716.0.tgz", + "integrity": "sha512-OZwhaOmeJ145oF9fNWd0rRny45OTdbt+3m+fgxuzXVGsbqCm+b0vHVSqaf8TwB7Ao+iP1bWwQeEA3sLBlXtbug==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.716.0", + "@aws-sdk/client-sts": "3.716.0", + "@aws-sdk/core": "3.716.0", + "@aws-sdk/credential-provider-node": "3.716.0", + "@aws-sdk/middleware-host-header": "3.714.0", + "@aws-sdk/middleware-logger": "3.714.0", + "@aws-sdk/middleware-recursion-detection": "3.714.0", + "@aws-sdk/middleware-user-agent": "3.716.0", + "@aws-sdk/region-config-resolver": "3.714.0", + "@aws-sdk/types": "3.714.0", + "@aws-sdk/util-endpoints": "3.714.0", + "@aws-sdk/util-user-agent-browser": "3.714.0", + "@aws-sdk/util-user-agent-node": "3.716.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.6", + "@smithy/middleware-retry": "^3.0.31", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.31", + "@smithy/util-defaults-mode-node": "^3.0.31", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.716.0.tgz", + "integrity": "sha512-5Nb0jJXce2TclbjG7WVPufwhgV1TRydz1QnsuBtKU0AdViEpr787YrZhPpGnNIM1Dx+R1H/tmAHZnOoohS6D8g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.716.0", + "@aws-sdk/middleware-host-header": "3.714.0", + "@aws-sdk/middleware-logger": "3.714.0", + "@aws-sdk/middleware-recursion-detection": "3.714.0", + "@aws-sdk/middleware-user-agent": "3.716.0", + "@aws-sdk/region-config-resolver": "3.714.0", + "@aws-sdk/types": "3.714.0", + "@aws-sdk/util-endpoints": "3.714.0", + "@aws-sdk/util-user-agent-browser": "3.714.0", + "@aws-sdk/util-user-agent-node": "3.716.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.6", + "@smithy/middleware-retry": "^3.0.31", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.31", + "@smithy/util-defaults-mode-node": "^3.0.31", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.716.0.tgz", + "integrity": "sha512-lA4IB9FzR2KjH7EVCo+mHGFKqdViVyeBQEIX9oVratL/l7P0bMS1fMwgfHOc3ACazqNxBxDES7x08ZCp32y6Lw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.716.0", + "@aws-sdk/credential-provider-node": "3.716.0", + "@aws-sdk/middleware-host-header": "3.714.0", + "@aws-sdk/middleware-logger": "3.714.0", + "@aws-sdk/middleware-recursion-detection": "3.714.0", + "@aws-sdk/middleware-user-agent": "3.716.0", + "@aws-sdk/region-config-resolver": "3.714.0", + "@aws-sdk/types": "3.714.0", + "@aws-sdk/util-endpoints": "3.714.0", + "@aws-sdk/util-user-agent-browser": "3.714.0", + "@aws-sdk/util-user-agent-node": "3.716.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.6", + "@smithy/middleware-retry": "^3.0.31", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.31", + "@smithy/util-defaults-mode-node": "^3.0.31", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.716.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.716.0.tgz", + "integrity": "sha512-i4SVNsrdXudp8T4bkm7Fi3YWlRnvXCSwvNDqf6nLqSJxqr4CN3VlBELueDyjBK7TAt453/qSif+eNx+bHmwo4Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.716.0", + "@aws-sdk/core": "3.716.0", + "@aws-sdk/credential-provider-node": "3.716.0", + "@aws-sdk/middleware-host-header": "3.714.0", + "@aws-sdk/middleware-logger": "3.714.0", + "@aws-sdk/middleware-recursion-detection": "3.714.0", + "@aws-sdk/middleware-user-agent": "3.716.0", + "@aws-sdk/region-config-resolver": "3.714.0", + "@aws-sdk/types": "3.714.0", + "@aws-sdk/util-endpoints": "3.714.0", + "@aws-sdk/util-user-agent-browser": "3.714.0", + "@aws-sdk/util-user-agent-node": "3.716.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.6", + "@smithy/middleware-retry": "^3.0.31", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.31", + "@smithy/util-defaults-mode-node": "^3.0.31", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.716.0.tgz", + "integrity": "sha512-5DkUiTrbyzO8/W4g7UFEqRFpuhgizayHI/Zbh0wtFMcot8801nJV+MP/YMhdjimlvAr/OqYB08FbGsPyWppMTw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.716.0.tgz", + "integrity": "sha512-JI2KQUnn2arICwP9F3CnqP1W3nAbm4+meQg/yOhp9X0DMzQiHrHRd4HIrK2vyVgi2/6hGhONY5uLF26yRTA7nQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.716.0.tgz", + "integrity": "sha512-CZ04pl2z7igQPysQyH2xKZHM3fLwkemxQbKOlje3TmiS1NwXvcKvERhp9PE/H23kOL7beTM19NMRog/Fka/rlw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.716.0.tgz", + "integrity": "sha512-P37We2GtZvdROxiwP0zrpEL81/HuYK1qlYxp5VCj3uV+G4mG8UQN2gMIU/baYrpOQqa0h81RfyQGRFUjVaDVqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.716.0", + "@aws-sdk/credential-provider-env": "3.716.0", + "@aws-sdk/credential-provider-http": "3.716.0", + "@aws-sdk/credential-provider-process": "3.716.0", + "@aws-sdk/credential-provider-sso": "3.716.0", + "@aws-sdk/credential-provider-web-identity": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.716.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.716.0.tgz", + "integrity": "sha512-FGQPK2uKfS53dVvoskN/s/t6m0Po24BGd1PzJdzHBFCOjxbZLM6+8mDMXeyi2hCLVVQOUcuW41kOgmJ0+zMbww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.716.0", + "@aws-sdk/credential-provider-http": "3.716.0", + "@aws-sdk/credential-provider-ini": "3.716.0", + "@aws-sdk/credential-provider-process": "3.716.0", + "@aws-sdk/credential-provider-sso": "3.716.0", + "@aws-sdk/credential-provider-web-identity": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.716.0.tgz", + "integrity": "sha512-0spcu2MWVVHSTHH3WE2E//ttUJPwXRM3BCp+WyI41xLzpNu1Fd8zjOrDpEo0SnGUzsSiRTIJWgkuu/tqv9NJ2A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.716.0.tgz", + "integrity": "sha512-J2IA3WuCpRGGoZm6VHZVFCnrxXP+41iUWb9Ct/1spljegTa1XjiaZ5Jf3+Ubj7WKiyvP9/dgz1L0bu2bYEjliw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.716.0", + "@aws-sdk/core": "3.716.0", + "@aws-sdk/token-providers": "3.714.0", + "@aws-sdk/types": "3.714.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.716.0.tgz", + "integrity": "sha512-vzgpWKs2gGXZGdbMKRFrMW4PqEFWkGvwWH2T7ZwQv9m+8lQ7P4Dk2uimqu0f37HZAbpn8HFMqRh4CaySjU354A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.716.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.714.0.tgz", + "integrity": "sha512-6l68kjNrh5QC8FGX3I3geBDavWN5Tg1RLHJ2HLA8ByGBtJyCwnz3hEkKfaxn0bBx0hF9DzbfjEOUF6cDqy2Kjg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.714.0.tgz", + "integrity": "sha512-RkqHlMvQWUaRklU1bMfUuBvdWwxgUtEqpADaHXlGVj3vtEY2UgBjy+57CveC4MByqKIunNvVHBBbjrGVtwY7Lg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.714.0.tgz", + "integrity": "sha512-AVU5ixnh93nqtsfgNc284oXsXaadyHGPHpql/jwgaaqQfEXjS/1/j3j9E/vpacfTTz2Vzo7hAOjnvrOXSEVDaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.716.0.tgz", + "integrity": "sha512-FpAtT6nNKrYdkDZndutEraiRMf+TgDzAGvniqRtZ/YTPA+gIsWrsn+TwMKINR81lFC3nQfb9deS5CFtxd021Ew==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@aws-sdk/util-endpoints": "3.714.0", + "@smithy/core": "^2.5.5", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.714.0.tgz", + "integrity": "sha512-HJzsQxgMOAzZrbf/YIqEx30or4tZK1oNAk6Wm6xecUQx+23JXIaePRu1YFUOLBBERQ4QBPpISFurZWBMZ5ibAw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.714.0.tgz", + "integrity": "sha512-vKN064aLE3kl+Zl16Ony3jltHnMddMBT7JRkP1L+lLywhA0PcAKxpdvComul/sTBWnbnwLnaS5NsDUhcWySH8A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.714.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.714.0.tgz", + "integrity": "sha512-ZjpP2gYbSFlxxaUDa1Il5AVvfggvUPbjzzB/l3q0gIE5Thd6xKW+yzEpt2mLZ5s5UaYSABZbF94g8NUOF4CVGA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.714.0.tgz", + "integrity": "sha512-Xv+Z2lhe7w7ZZRsgBwBMZgGTVmS+dkkj2S13uNHAx9lhB5ovM8PhK5G/j28xYf6vIibeuHkRAbb7/ozdZIGR+A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/types": "^3.7.2", + "@smithy/util-endpoints": "^2.1.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz", + "integrity": "sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.714.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.714.0.tgz", + "integrity": "sha512-OdJJ03cP9/MgIVToPJPCPUImbpZzTcwdIgbXC0tUQPJhbD7b7cB4LdnkhNHko+MptpOrCq4CPY/33EpOjRdofw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.714.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.716.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.716.0.tgz", + "integrity": "sha512-3PqaXmQbxrtHKAsPCdp7kn5FrQktj8j3YyuNsqFZ8rWZeEQ88GWlsvE61PTsr2peYCKzpFqYVddef2x1axHU0w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.716.0", + "@aws-sdk/types": "3.714.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -1082,6 +1750,559 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@smithy/abort-controller": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", + "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", + "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.5.tgz", + "integrity": "sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-stream": "^3.3.2", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", + "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz", + "integrity": "sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", + "@smithy/types": "^3.7.2", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/hash-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", + "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", + "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", + "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.6.tgz", + "integrity": "sha512-WAqzyulvvSKrT5c6VrQelgNVNNO7BlTQW9Z+s9tcG6G5CaBS1YBpPtT3VuhXLQbewSiGi7oXQROwpw26EG9PLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^2.5.5", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-middleware": "^3.0.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "3.0.31", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.31.tgz", + "integrity": "sha512-yq9wawrJLYHAYFpChLujxRN4My+SiKXvZk9Ml/CvTdRSA8ew+hvuR5LT+mjSlSBv3c4XJrkN8CWegkBaeD0Vrg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/protocol-http": "^4.1.8", + "@smithy/service-error-classification": "^3.0.11", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", + "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz", + "integrity": "sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz", + "integrity": "sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz", + "integrity": "sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^3.1.9", + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", + "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", + "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", + "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz", + "integrity": "sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", + "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz", + "integrity": "sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", + "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.5.1.tgz", + "integrity": "sha512-PmjskH4Os1Eh3rd5vSsa5uVelZ4DRu+N5CBEgb9AT96hQSJGWSEb6pGxKV/PtKQSIp9ft3+KvnT8ViMKaguzgA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^2.5.5", + "@smithy/middleware-endpoint": "^3.2.6", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", + "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.11.tgz", + "integrity": "sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.31", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.31.tgz", + "integrity": "sha512-eO+zkbqrPnmsagqzrmF7IJrCoU2wTQXWVYxMPqA9Oue55kw9WEvhyuw2XQzTVTCRcYsg6KgmV3YYhLlWQJfK1A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.31", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.31.tgz", + "integrity": "sha512-0/nJfpSpbGZOs6qs42wCe2TdjobbnnD4a3YUUlvTXSQqLy4qa63luDaV04hGvqSHP7wQ7/WGehbvHkDhMZd1MQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^3.0.13", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.5.1", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", + "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", + "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", + "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.2.tgz", + "integrity": "sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/types": "^3.7.2", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -1836,6 +3057,12 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3159,6 +4386,28 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -6241,6 +7490,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6745,6 +8000,19 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index e4e4ab9..6280c09 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test": "jest" }, "dependencies": { + "@aws-sdk/client-kms": "^3.716.0", "@nestjs/common": "^10.4.15", "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.4.15", diff --git a/prisma/local-aws-state.sqlite b/prisma/local-aws-state.sqlite index 58754d2..20eae5d 100644 Binary files a/prisma/local-aws-state.sqlite and b/prisma/local-aws-state.sqlite differ diff --git a/prisma/migrations/20241220224222_/migration.sql b/prisma/migrations/20241220224222_/migration.sql new file mode 100644 index 0000000..e8fc604 --- /dev/null +++ b/prisma/migrations/20241220224222_/migration.sql @@ -0,0 +1,25 @@ +/* + Warnings: + + - Added the required column `updatedAt` to the `KmsAlias` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_KmsAlias" ( + "name" TEXT NOT NULL, + "accountId" TEXT NOT NULL, + "region" TEXT NOT NULL, + "kmsKeyId" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + + PRIMARY KEY ("accountId", "region", "name"), + CONSTRAINT "KmsAlias_kmsKeyId_fkey" FOREIGN KEY ("kmsKeyId") REFERENCES "KmsKey" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_KmsAlias" ("accountId", "kmsKeyId", "name", "region") SELECT "accountId", "kmsKeyId", "name", "region" FROM "KmsAlias"; +DROP TABLE "KmsAlias"; +ALTER TABLE "new_KmsAlias" RENAME TO "KmsAlias"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/migrations/20241221004838_/migration.sql b/prisma/migrations/20241221004838_/migration.sql new file mode 100644 index 0000000..4e55ad7 --- /dev/null +++ b/prisma/migrations/20241221004838_/migration.sql @@ -0,0 +1,36 @@ +/* + Warnings: + + - You are about to alter the column `key` on the `KmsKey` table. The data in that column could be lost. The data in that column will be cast from `String` to `Binary`. + - Added the required column `enabled` to the `KmsKey` table without a default value. This is not possible if the table is not empty. + - Added the required column `keyState` to the `KmsKey` table without a default value. This is not possible if the table is not empty. + - Added the required column `multiRegion` to the `KmsKey` table without a default value. This is not possible if the table is not empty. + - Added the required column `origin` to the `KmsKey` table without a default value. This is not possible if the table is not empty. + - Added the required column `policy` to the `KmsKey` table without a default value. This is not possible if the table is not empty. + - Added the required column `updatedAt` to the `KmsKey` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_KmsKey" ( + "id" TEXT NOT NULL PRIMARY KEY, + "enabled" BOOLEAN NOT NULL, + "usage" TEXT NOT NULL, + "description" TEXT NOT NULL, + "keySpec" TEXT NOT NULL, + "keyState" TEXT NOT NULL, + "origin" TEXT NOT NULL, + "multiRegion" BOOLEAN NOT NULL, + "policy" TEXT NOT NULL, + "key" BLOB NOT NULL, + "accountId" TEXT NOT NULL, + "region" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); +INSERT INTO "new_KmsKey" ("accountId", "createdAt", "description", "id", "key", "keySpec", "region", "usage") SELECT "accountId", "createdAt", "description", "id", "key", "keySpec", "region", "usage" FROM "KmsKey"; +DROP TABLE "KmsKey"; +ALTER TABLE "new_KmsKey" RENAME TO "KmsKey"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/migrations/20241221010230_/migration.sql b/prisma/migrations/20241221010230_/migration.sql new file mode 100644 index 0000000..f6ea731 --- /dev/null +++ b/prisma/migrations/20241221010230_/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "KmsKey" ADD COLUMN "nextRotation" DATETIME; +ALTER TABLE "KmsKey" ADD COLUMN "rotationPeriod" INTEGER; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6eae3e9..d45cfa9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -29,19 +29,33 @@ model KmsAlias { accountId String region String kmsKeyId String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + kmsKey KmsKey @relation(fields: [kmsKeyId], references: [id]) @@id([accountId, region, name]) } model KmsKey { - id String @id - usage String - description String - keySpec String - key String - accountId String - region String - createdAt DateTime @default(now()) + id String @id + enabled Boolean + usage String + description String + keySpec String + keyState String + origin String + multiRegion Boolean + policy String + key Bytes + rotationPeriod Int? + nextRotation DateTime? + accountId String + region String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + aliases KmsAlias[] } model Secret { diff --git a/src/_context/request.context.ts b/src/_context/request.context.ts index b74a8c6..ce83c40 100644 --- a/src/_context/request.context.ts +++ b/src/_context/request.context.ts @@ -6,7 +6,7 @@ import { Format } from "../abstract-action.handler"; export interface RequestContext { action?: Action; format?: Format; - requestId: string; + readonly requestId: string; } export interface IRequest extends Request { diff --git a/src/aws-shared-entities/aws-exceptions.ts b/src/aws-shared-entities/aws-exceptions.ts index 6c14219..94bee64 100644 --- a/src/aws-shared-entities/aws-exceptions.ts +++ b/src/aws-shared-entities/aws-exceptions.ts @@ -154,3 +154,12 @@ export class InvalidArnException extends AwsException { ) } } +export class UnsupportedOperationException extends AwsException { + constructor(message: string) { + super( + message, + UnsupportedOperationException.name, + HttpStatus.BAD_REQUEST, + ) + } +} \ No newline at end of file diff --git a/src/aws-shared-entities/tags.service.ts b/src/aws-shared-entities/tags.service.ts index 44bc328..fd4c2e5 100644 --- a/src/aws-shared-entities/tags.service.ts +++ b/src/aws-shared-entities/tags.service.ts @@ -20,7 +20,7 @@ export class TagsService { } async createMany(arn: string, records: { key: string, value: string }[]): Promise { - await this.prismaService.attribute.createMany({ + await this.prismaService.tag.createMany({ data: records.map(r => ({ name: r.key, value: r.value, diff --git a/src/kms/create-alias.handler.ts b/src/kms/create-alias.handler.ts new file mode 100644 index 0000000..8c506da --- /dev/null +++ b/src/kms/create-alias.handler.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { KmsService } from './kms.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; + +type QueryParams = { + AliasName: string; + TargetKeyId: string; +} + +@Injectable() +export class CreateAliasHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsCreateAlias; + validator = Joi.object({ + TargetKeyId: Joi.string().required(), + AliasName: Joi.string().min(1).max(256).regex(new RegExp(`^alias/[a-zA-Z0-9/_-]+$`)).required(), + }); + + protected async handle({ TargetKeyId, AliasName }: QueryParams, awsProperties: AwsProperties) { + + const keyRecord = await this.kmsService.findOneByRef(TargetKeyId, awsProperties); + + if (!keyRecord) { + throw new NotFoundException(); + } + + await this.kmsService.createAlias({ + accountId: awsProperties.accountId, + region: awsProperties.region, + name: AliasName, + kmsKey: { + connect: { + id: keyRecord.id, + }, + }, + }); + } +} diff --git a/src/kms/create-key.handler.ts b/src/kms/create-key.handler.ts index e69de29..71a2d28 100644 --- a/src/kms/create-key.handler.ts +++ b/src/kms/create-key.handler.ts @@ -0,0 +1,184 @@ +import { CustomerMasterKeySpec, KeySpec, KeyState, KeyUsageType, OriginType, Tag } from '@aws-sdk/client-kms'; +import { Injectable } from '@nestjs/common'; +import * as Joi from 'joi'; + +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import { KmsService } from './kms.service'; +import * as crypto from 'crypto'; +import { keySpecToUsageType } from './kms-key.entity'; +import { UnsupportedOperationException } from '../aws-shared-entities/aws-exceptions'; +import { TagsService } from '../aws-shared-entities/tags.service'; + +type NoUndefinedField = { [P in keyof T]-?: NoUndefinedField> }; + +type QueryParams = { + BypassPolicyLockoutSafetyCheck: boolean; + CustomerMasterKeySpec: CustomerMasterKeySpec; + CustomKeyStoreId: string; + Description: string; + KeySpec: KeySpec; + KeyUsage: KeyUsageType; + MultiRegion: boolean; + Origin: OriginType; + Policy: string; + Tags: NoUndefinedField[]; + XksKeyId: string; +} + +const generateDefaultPolicy = (accountId: string) => JSON.stringify({ + "Sid": "Enable IAM User Permissions", + "Effect": "Allow", + "Principal": { + "AWS": `arn:aws:iam::${accountId}:root` + }, + "Action": "kms:*", + "Resource": "*" +}) + +@Injectable() +export class CreateKeyHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + private readonly tagsService: TagsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsCreateKey; + validator = Joi.object({ + BypassPolicyLockoutSafetyCheck: Joi.boolean().default(false), + CustomerMasterKeySpec: Joi.string().allow(...Object.values(CustomerMasterKeySpec)), + CustomKeyStoreId: Joi.string().min(1).max(64), + Description: Joi.string().min(0).max(8192).default(''), + KeySpec: Joi.string().allow(...Object.values(KeySpec)).default(KeySpec.SYMMETRIC_DEFAULT), + KeyUsage: Joi.string().allow(...Object.values(KeyUsageType)).default(KeyUsageType.ENCRYPT_DECRYPT), + MultiRegion: Joi.boolean().default(false), + Origin: Joi.string().allow(...Object.values(OriginType)).default(OriginType.AWS_KMS), + Policy: Joi.string().min(1).max(32768), + Tags: Joi.array().items( + Joi.object({ + TagKey: Joi.string().min(1).max(128).required(), + TagValue: Joi.string().min(0).max(256).required(), + }) + ), + XksKeyId: Joi.when('Origin', { + is: OriginType.EXTERNAL_KEY_STORE, + then: Joi.string().min(1).max(128), + otherwise: Joi.forbidden(), + }) as unknown as Joi.StringSchema, + }); + + protected async handle({ KeyUsage, Description, KeySpec, Origin, MultiRegion, Policy, Tags, CustomerMasterKeySpec }: QueryParams, awsProperties: AwsProperties) { + + const keySpec = CustomerMasterKeySpec ?? KeySpec; + + if (!keySpecToUsageType[keySpec].includes(KeyUsage)) { + throw new UnsupportedOperationException(`KeySpec ${KeySpec} is not valid for KeyUsage ${KeyUsage}`); + } + + const key = this.keyGeneratorMap[keySpec](); + + const createdKey = await this.kmsService.createKmsKey({ + id: crypto.randomUUID(), + enabled: true, + usage: KeyUsage, + description: Description, + keySpec: keySpec, + keyState: KeyState.Enabled, + origin: Origin, + multiRegion: MultiRegion, + policy: Policy ?? generateDefaultPolicy(awsProperties.accountId), + key, + accountId: awsProperties.accountId, + region: awsProperties.region, + }); + + await this.tagsService.createMany(createdKey.arn, Tags.map(({ TagKey, TagValue }) => ({ key: TagKey, value: TagValue }))); + + return { + KeyMetadata: createdKey.metadata, + } + } + + private keyGeneratorMap: Record Buffer> = { + ECC_NIST_P256: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'X9_62_prime256v1' }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + ECC_NIST_P384: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'secp384r1' }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + ECC_NIST_P521: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'secp521r1' }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + ECC_SECG_P256K1: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + HMAC_224: function (): Buffer { + return crypto.randomBytes(32); + }, + HMAC_256: function (): Buffer { + return crypto.randomBytes(32); + }, + HMAC_384: function (): Buffer { + return crypto.randomBytes(32); + }, + HMAC_512: function (): Buffer { + return crypto.randomBytes(32); + }, + RSA_2048: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + RSA_3072: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 3072, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + RSA_4096: function (): Buffer { + const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 4096, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }); + return Buffer.from(JSON.stringify({ privateKey, publicKey })); + }, + SM2: function (): Buffer { + throw new Error('Function not implemented.'); + }, + SYMMETRIC_DEFAULT: function (): Buffer { + return crypto.randomBytes(32); + } + } +} diff --git a/src/kms/describe-key.handler.ts b/src/kms/describe-key.handler.ts index edcca9c..b7d7cb6 100644 --- a/src/kms/describe-key.handler.ts +++ b/src/kms/describe-key.handler.ts @@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common'; import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; import { Action } from '../action.enum'; import * as Joi from 'joi'; -import { breakdownArn } from '../util/breakdown-arn'; import { KmsService } from './kms.service'; import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; @@ -29,20 +28,7 @@ export class DescribeKeyHandler extends AbstractActionHandler { protected async handle({ KeyId }: QueryParams, awsProperties: AwsProperties) { - const searchable = KeyId.startsWith('arn') ? breakdownArn(KeyId) : { - service: 'kms', - region: awsProperties.region, - accountId: awsProperties.accountId, - identifier: KeyId, - }; - const [ type, pk ] = searchable.identifier.split('/'); - const keyId = await (type === 'key' ? Promise.resolve(pk) : this.kmsService.findKeyIdFromAlias(pk, searchable)); - - if (!keyId) { - throw new NotFoundException(); - } - - const keyRecord = await this.kmsService.findOneById(keyId); + const keyRecord = await this.kmsService.findOneByRef(KeyId, awsProperties); if (!keyRecord) { throw new NotFoundException(); diff --git a/src/kms/enable-key-rotation.handler.ts b/src/kms/enable-key-rotation.handler.ts new file mode 100644 index 0000000..a047eb8 --- /dev/null +++ b/src/kms/enable-key-rotation.handler.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { KmsService } from './kms.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; + +type QueryParams = { + KeyId: string; + RotationPeriodInDays: number; +} + +@Injectable() +export class EnableKeyRotationHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsEnableKeyRotation; + validator = Joi.object({ + KeyId: Joi.string().required(), + RotationPeriodInDays: Joi.number().min(90).max(2560).default(365), + }); + + protected async handle({ KeyId, RotationPeriodInDays }: QueryParams, awsProperties: AwsProperties) { + + const keyRecord = await this.kmsService.findOneByRef(KeyId, awsProperties); + + if (!keyRecord) { + throw new NotFoundException(); + } + + const next = new Date(); + next.setDate(next.getDate() + RotationPeriodInDays); + + await this.kmsService.updateKmsKey(keyRecord.id, { + rotationPeriod: RotationPeriodInDays, + nextRotation: next, + }); + } +} diff --git a/src/kms/get-key-policy.handler.ts b/src/kms/get-key-policy.handler.ts new file mode 100644 index 0000000..d782164 --- /dev/null +++ b/src/kms/get-key-policy.handler.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { KmsService } from './kms.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; + +type QueryParams = { + PolicyName: string; + KeyId: string; +} + +@Injectable() +export class GetKeyPolicyHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsGetKeyPolicy; + validator = Joi.object({ + KeyId: Joi.string().required(), + PolicyName: Joi.string().min(1).max(128).default('default'), + }); + + protected async handle({ KeyId, PolicyName }: QueryParams, awsProperties: AwsProperties) { + + const keyRecord = await this.kmsService.findOneByRef(KeyId, awsProperties); + + if (!keyRecord) { + throw new NotFoundException(); + } + + return { + PolicyName, + Policy: keyRecord.policy, + } + } +} diff --git a/src/kms/get-key-rotation-status.handler.ts b/src/kms/get-key-rotation-status.handler.ts new file mode 100644 index 0000000..f24472d --- /dev/null +++ b/src/kms/get-key-rotation-status.handler.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { KmsService } from './kms.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; + +type QueryParams = { + KeyId: string; +} + +@Injectable() +export class GetKeyRotationStatusHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsGetKeyRotationStatus; + validator = Joi.object({ + KeyId: Joi.string().required(), + }); + + protected async handle({ KeyId }: QueryParams, awsProperties: AwsProperties) { + + const keyRecord = await this.kmsService.findOneByRef(KeyId, awsProperties); + + if (!keyRecord) { + throw new NotFoundException(); + } + + return { + KeyId: keyRecord.id, + KeyRotationEnabled: !!keyRecord.rotationPeriod, + NextRotationDate: keyRecord.nextRotation, + RotationPeriodInDays: keyRecord.rotationPeriod, + } + } +} diff --git a/src/kms/kms-alias.entity.ts b/src/kms/kms-alias.entity.ts new file mode 100644 index 0000000..61f5beb --- /dev/null +++ b/src/kms/kms-alias.entity.ts @@ -0,0 +1,34 @@ +import { KmsAlias as PrismaKeyAlias } from "@prisma/client" + +export class KmsAlias implements PrismaKeyAlias { + + name: string + accountId: string + region: string + kmsKeyId: string + createdAt: Date; + updatedAt: Date; + + constructor(p: PrismaKeyAlias) { + this.name = p.name; + this.accountId = p.accountId; + this.region = p.region; + this.kmsKeyId = p.kmsKeyId; + this.createdAt = p.createdAt; + this.updatedAt = p.updatedAt; + } + + get arn() { + return `arn:aws:kms:${this.region}:${this.accountId}:${this.name}`; + } + + toAws() { + return { + AliasArn: this.arn, + AliasName: this.name, + CreationDate: this.createdAt.getAwsTime(), + LastUpdatedDate: this.updatedAt.getAwsTime(), + TargetKeyId: this.kmsKeyId, + } + } +} diff --git a/src/kms/kms-key-alias.entity.ts b/src/kms/kms-key-alias.entity.ts deleted file mode 100644 index 2a04065..0000000 --- a/src/kms/kms-key-alias.entity.ts +++ /dev/null @@ -1,11 +0,0 @@ -export class KmsKeyAlias { - - // name: string; - // targetKeyId: string; - // accountId: string; - // region: string; - - // get arn() { - // return `arn:aws:kms:${this.region}:${this.accountId}:alias/${this.name}`; - // } -} diff --git a/src/kms/kms-key.entity.ts b/src/kms/kms-key.entity.ts index e1b79c1..a018fcf 100644 --- a/src/kms/kms-key.entity.ts +++ b/src/kms/kms-key.entity.ts @@ -1,28 +1,58 @@ +import { KeySpec, KeyUsageType, KeyState, AlgorithmSpec, OriginType, ExpirationModelType, KeyAgreementAlgorithmSpec, MacAlgorithmSpec, MultiRegionKeyType, SigningAlgorithmSpec } from '@aws-sdk/client-kms'; import { KmsKey as PrismaKmsKey } from '@prisma/client'; -export type KeySpec = 'RSA_2048' | 'RSA_3072' | 'RSA_4096' | 'ECC_NIST_P256' | 'ECC_NIST_P384' | 'ECC_NIST_P521' | 'ECC_SECG_P256K1' | 'SYMMETRIC_DEFAULT' | 'HMAC_224' | 'HMAC_256' | 'HMAC_384' | 'HMAC_512' | 'SM2'; -export type KeyUsage = 'SIGN_VERIFY' | 'ENCRYPT_DECRYPT' | 'GENERATE_VERIFY_MAC'; +export const keySpecToUsageType: Record = { + ECC_NIST_P256: [KeyUsageType.SIGN_VERIFY, KeyUsageType.KEY_AGREEMENT], + ECC_NIST_P384: [KeyUsageType.SIGN_VERIFY, KeyUsageType.KEY_AGREEMENT], + ECC_NIST_P521: [KeyUsageType.SIGN_VERIFY, KeyUsageType.KEY_AGREEMENT], + ECC_SECG_P256K1: [KeyUsageType.SIGN_VERIFY], + HMAC_224: [KeyUsageType.GENERATE_VERIFY_MAC], + HMAC_256: [KeyUsageType.GENERATE_VERIFY_MAC], + HMAC_384: [KeyUsageType.GENERATE_VERIFY_MAC], + HMAC_512: [KeyUsageType.GENERATE_VERIFY_MAC], + RSA_2048: [KeyUsageType.ENCRYPT_DECRYPT, KeyUsageType.SIGN_VERIFY], + RSA_3072: [KeyUsageType.ENCRYPT_DECRYPT, KeyUsageType.SIGN_VERIFY], + RSA_4096: [KeyUsageType.ENCRYPT_DECRYPT, KeyUsageType.SIGN_VERIFY], + SM2: [KeyUsageType.ENCRYPT_DECRYPT, KeyUsageType.SIGN_VERIFY, KeyUsageType.KEY_AGREEMENT], + SYMMETRIC_DEFAULT: [KeyUsageType.ENCRYPT_DECRYPT] +} export class KmsKey implements PrismaKmsKey { id: string; - usage: KeyUsage; + enabled: boolean; + usage: KeyUsageType; description: string; keySpec: KeySpec; - key: string; + keyState: KeyState; + origin: OriginType; + multiRegion: boolean; + policy: string; + key: Buffer; + nextRotation: Date | null; + rotationPeriod: number | null; accountId: string; region: string; createdAt: Date; + updatedAt: Date; constructor(p: PrismaKmsKey) { this.id = p.id; - this.usage = p.usage as KeyUsage; + this.enabled = p.enabled; + this.usage = p.usage as KeyUsageType; this.description = p.description; this.keySpec = p.keySpec as KeySpec; - this.key = p.key; + this.keyState = p.keyState as KeyState; + this.origin = p.origin as OriginType; + this.multiRegion = p.multiRegion; + this.policy = p.policy; + this.key = Buffer.from(p.key); + this.nextRotation = p.nextRotation; + this.rotationPeriod = p.rotationPeriod; this.accountId = p.accountId; this.region = p.region; this.createdAt = p.createdAt; + this.updatedAt = p.updatedAt; } get arn() { @@ -30,27 +60,58 @@ export class KmsKey implements PrismaKmsKey { } get metadata() { + + const dynamicContent: Record = {}; + + if (keySpecToUsageType[this.keySpec].includes(KeyUsageType.ENCRYPT_DECRYPT)) { + dynamicContent.EncryptionAlgorithms = Object.values(AlgorithmSpec); + } + + if (this.origin === OriginType.EXTERNAL) { + dynamicContent.ExpirationModel = ExpirationModelType.KEY_MATERIAL_DOES_NOT_EXPIRE; + } + + if (keySpecToUsageType[this.keySpec].includes(KeyUsageType.KEY_AGREEMENT)) { + dynamicContent.KeyAgreementAlgorithms = Object.values(KeyAgreementAlgorithmSpec); + } + + if (keySpecToUsageType[this.keySpec].includes(KeyUsageType.GENERATE_VERIFY_MAC)) { + dynamicContent.MacAlgorithms = Object.values(MacAlgorithmSpec); + } + + if (this.multiRegion) { + dynamicContent.MultiRegionConfiguration = { + MultiRegionKeyType: MultiRegionKeyType.PRIMARY, + PrimaryKey: { + Arn: this.arn, + Region: this.region, + }, + ReplicaKeys: [], + } + } + + if (keySpecToUsageType[this.keySpec].includes(KeyUsageType.SIGN_VERIFY)) { + dynamicContent.SigningAlgorithms = Object.values(SigningAlgorithmSpec); + } + return { AWSAccountId: this.accountId, - KeyId: this.id, Arn: this.arn, - CreationDate: new Date(this.createdAt).toISOString(), - Enabled: true, - Description: this.description, - KeyUsage: this.usage, - KeyState: 'Enabled', - KeyManager: "CUSTOMER", + CreationDate: this.createdAt.getAwsTime(), CustomerMasterKeySpec: this.keySpec, + Description: this.description, + Enabled: true, + KeyId: this.id, + KeyManager: undefined, KeySpec: this.keySpec, - DeletionDate: null, - SigningAlgorithms: [ - "RSASSA_PSS_SHA_256", - "RSASSA_PSS_SHA_384", - "RSASSA_PSS_SHA_512", - "RSASSA_PKCS1_V1_5_SHA_256", - "RSASSA_PKCS1_V1_5_SHA_384", - "RSASSA_PKCS1_V1_5_SHA_512" - ] + KeyState: this.keyState, + KeyUsage: this.usage, + MultiRegion: this.multiRegion, + Origin: this.origin, + PendingDeletionWindowInDays: undefined, + ValidTo: undefined, + XksKeyConfiguration: undefined, + ...dynamicContent, } } } diff --git a/src/kms/kms.module.ts b/src/kms/kms.module.ts index 615a823..8e82875 100644 --- a/src/kms/kms.module.ts +++ b/src/kms/kms.module.ts @@ -9,9 +9,23 @@ import { KmsService } from './kms.service'; import { KMSHandlers } from './kms.constants'; import { DescribeKeyHandler } from './describe-key.handler'; import { PrismaModule } from '../_prisma/prisma.module'; +import { ListAliasesHandler } from './list-aliases.handler'; +import { CreateKeyHandler } from './create-key.handler'; +import { EnableKeyRotationHandler } from './enable-key-rotation.handler'; +import { GetKeyRotationStatusHandler } from './get-key-rotation-status.handler'; +import { GetKeyPolicyHandler } from './get-key-policy.handler'; +import { ListResourceTagsHandler } from './list-resource-tags.handler'; +import { CreateAliasHandler } from './create-alias.handler'; const handlers = [ + CreateAliasHandler, + CreateKeyHandler, DescribeKeyHandler, + EnableKeyRotationHandler, + GetKeyPolicyHandler, + GetKeyRotationStatusHandler, + ListAliasesHandler, + ListResourceTagsHandler, ] const actions = [ diff --git a/src/kms/kms.service.ts b/src/kms/kms.service.ts index fa2c0ab..38c442d 100644 --- a/src/kms/kms.service.ts +++ b/src/kms/kms.service.ts @@ -1,8 +1,12 @@ import { Injectable } from '@nestjs/common'; +import { Prisma } from '@prisma/client'; import { PrismaService } from '../_prisma/prisma.service'; -import { ArnParts } from '../util/breakdown-arn'; +import { breakdownArn } from '../util/breakdown-arn'; import { KmsKey } from './kms-key.entity'; +import { KmsAlias } from './kms-alias.entity'; +import { AwsProperties } from '../abstract-action.handler'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; @Injectable() export class KmsService { @@ -10,21 +14,103 @@ export class KmsService { private readonly prismaService: PrismaService, ) {} - async findOneById(id: string): Promise { - const pRecord = await this.prismaService.kmsKey.findFirst({ - where: { id } - }); - return pRecord ? new KmsKey(pRecord) : null; + async findOneByRef(ref: string, awsProperties: AwsProperties): Promise { + if (ref.startsWith('arn')) { + return await this.findOneByArn(ref); + } + return await this.findOneById(awsProperties.accountId, awsProperties.region, ref); } - async findKeyIdFromAlias(alias: string, arn: ArnParts): Promise { - const record = await this.prismaService.kmsAlias.findFirst({ + async findOneByArn(arn: string): Promise { + const parts = breakdownArn(arn); + return await this.findOneById(parts.accountId, parts.region, parts.identifier.split('/')[1]); + } + + async findOneById(accountId: string, region: string, ref: string): Promise { + + const [alias, record] = await Promise.all([ + this.prismaService.kmsAlias.findFirst({ + include: { + kmsKey: true + }, + where: { + accountId, + region, + name: ref, + } + }), + this.prismaService.kmsKey.findFirst({ + where: { + accountId, + region, + id: ref, + } + }) + ]); + + if (!alias?.kmsKey && !record) { + throw new NotFoundException(); + } + + return record ? new KmsKey(record) : new KmsKey(alias!.kmsKey); + } + + async findAndCountAliasesByKeyId(accountId: string, region: string, limit: number, kmsKeyId: string, marker = ''): Promise { + const take = limit + 1; + const records = await this.prismaService.kmsAlias.findMany({ where: { - name: alias, - accountId: arn.accountId, - region: arn.region, - } + accountId, + region, + kmsKeyId, + name: { + gte: marker, + } + }, + take, + orderBy: { + name: 'desc', + }, + }); + + return records.map(r => new KmsAlias(r)); + } + + async findAndCountAliases(accountId: string, region: string, limit: number, marker = ''): Promise { + const take = limit + 1; + const records = await this.prismaService.kmsAlias.findMany({ + where: { + accountId, + region, + name: { + gte: marker, + } + }, + take, + orderBy: { + name: 'desc', + }, + }); + + return records.map(r => new KmsAlias(r)); + } + + async createKmsKey(data: Prisma.KmsKeyCreateInput): Promise { + const record = await this.prismaService.kmsKey.create({ + data + }); + return new KmsKey(record); + } + + async updateKmsKey(id: string, data: Prisma.KmsKeyUpdateInput): Promise { + await this.prismaService.kmsKey.update({ + where: { id }, + data, + }); + } + + async createAlias(data: Prisma.KmsAliasCreateInput) { + await this.prismaService.kmsAlias.create({ + data }); - return record?.kmsKeyId ?? null; } } diff --git a/src/kms/list-aliases.handler.ts b/src/kms/list-aliases.handler.ts index e69de29..3ef5257 100644 --- a/src/kms/list-aliases.handler.ts +++ b/src/kms/list-aliases.handler.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; +import * as Joi from 'joi'; + +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import { KmsService } from './kms.service'; + +type QueryParams = { + KeyId?: string; + Limit: number; + Marker?: string; +} + +@Injectable() +export class ListAliasesHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsListAliases; + validator = Joi.object({ + KeyId: Joi.string(), + Limit: Joi.number().min(1).max(100).default(50), + Marker: Joi.string(), + }); + + protected async handle({ KeyId, Limit, Marker }: QueryParams, awsProperties: AwsProperties) { + + const records = await (KeyId + ? this.kmsService.findAndCountAliasesByKeyId(awsProperties.accountId, awsProperties.region, Limit, KeyId, Marker) + : this.kmsService.findAndCountAliases(awsProperties.accountId, awsProperties.region, Limit, Marker) + ) + + const nextMarker = records.length > Limit ? records.pop() : null; + + return { + Aliases: records.map(r => r.toAws()), + NextMarker: nextMarker?.name, + Truncated: !!nextMarker, + } + } +} diff --git a/src/kms/list-resource-tags.handler.ts b/src/kms/list-resource-tags.handler.ts new file mode 100644 index 0000000..de36c20 --- /dev/null +++ b/src/kms/list-resource-tags.handler.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { KmsService } from './kms.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; +import { TagsService } from '../aws-shared-entities/tags.service'; + +type QueryParams = { + KeyId: string; + Limit: number; + Marker: string; +} + +@Injectable() +export class ListResourceTagsHandler extends AbstractActionHandler { + + constructor( + private readonly kmsService: KmsService, + private readonly tagsService: TagsService, + ) { + super(); + } + + format = Format.Json; + action = Action.KmsListResourceTags; + validator = Joi.object({ + KeyId: Joi.string().required(), + Limit: Joi.number().min(1).max(100).default(50), + Marker: Joi.string(), + }); + + protected async handle({ KeyId }: QueryParams, awsProperties: AwsProperties) { + + const keyRecord = await this.kmsService.findOneByRef(KeyId, awsProperties); + + if (!keyRecord) { + throw new NotFoundException(); + } + + const tags = await this.tagsService.getByArn(keyRecord.arn); + + return { + Tags: tags.map(({ name, value }) => ({ TagKey: name, TagValue: value })), + Truncated: false, + } + } +} diff --git a/src/main.ts b/src/main.ts index 789c450..3acdbe4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,16 @@ import { AwsExceptionFilter } from './_context/exception.filter'; const bodyParser = require('body-parser'); +declare global { + interface Date { + getAwsTime(): number; + } +} + +Date.prototype.getAwsTime = function (this: Date) { + return Math.floor(this.getTime() / 1000); +}; + (async () => { const app = await NestFactory.create(AppModule);