@planetarium/account-aws-kms
Version:
Libplanet account implementation using AWS KMS
8 lines (7 loc) • 16.3 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/AwsKmsAccount.ts", "../src/crypto/browser.ts", "../src/asn1.ts", "../src/AwsKmsKeyStore.ts", "../src/index.ts"],
"sourcesContent": ["import { AwsKmsKeyId } from \"./AwsKmsKeyId.js\";\nimport { KMSClient, SignCommand } from \"@aws-sdk/client-kms\";\nimport { Signature as NobleSignature } from \"@noble/secp256k1\";\nimport { crypto } from \"#crypto\";\nimport {\n Address,\n type Account,\n type Message,\n PublicKey,\n Signature,\n} from \"@planetarium/account\";\n\nexport class AwsKmsAccount implements Account {\n readonly #client: KMSClient;\n\n readonly keyId: AwsKmsKeyId;\n\n // TODO: This attribute is deprecated. We should remove it and make\n // getPublicKey() method the only choice in the future.\n /**\n * @deprecated Use {@link getPublicKey()} instead.\n */\n readonly publicKey: PublicKey;\n\n constructor(keyId: AwsKmsKeyId, publicKey: PublicKey, client: KMSClient) {\n this.keyId = keyId;\n this.publicKey = publicKey;\n this.#client = client;\n }\n\n getAddress(): Promise<Address> {\n return Promise.resolve(Address.deriveFrom(this.publicKey));\n }\n\n getPublicKey(): Promise<PublicKey> {\n return Promise.resolve(this.publicKey);\n }\n\n async sign(message: Message): Promise<Signature> {\n const digest = await crypto.subtle.digest(\"SHA-256\", message);\n const digestArray = new Uint8Array(digest);\n\n const cmd = new SignCommand({\n KeyId: this.keyId,\n Message: digestArray,\n MessageType: \"DIGEST\",\n SigningAlgorithm: \"ECDSA_SHA_256\",\n });\n const response = await this.#client.send(cmd);\n if (response.Signature == null) throw new Error(\"Failed to sign message\");\n const sig = NobleSignature.fromDER(response.Signature).normalizeS();\n return Signature.fromHex(sig.toDERHex());\n }\n}\n\nexport default AwsKmsAccount;\n", "declare const globalThis: Record<string, any> | undefined;\nexport const crypto =\n typeof globalThis === \"object\" && \"crypto\" in globalThis\n ? globalThis.crypto\n : undefined;\n", "import {\n Any,\n BitString,\n ObjectIdentifier,\n Sequence,\n verifySchema,\n} from \"asn1js\";\n\n// https://www.rfc-editor.org/rfc/rfc5280#section-4.1\nconst SubjectPublicKeyInfo = new Sequence({\n name: \"subjectPublicKeyInfo\",\n value: [\n new Sequence({\n name: \"algorithm\",\n value: [\n new ObjectIdentifier({\n name: \"algorithm\",\n }),\n new Any({\n name: \"parameters\",\n optional: true,\n }),\n ],\n }),\n new BitString({\n name: \"subjectPublicKey\",\n }),\n ],\n});\n\nexport function parseSubjectPublicKeyInfo(buf: Uint8Array) {\n const { result, verified } = verifySchema(buf, SubjectPublicKeyInfo);\n if (!verified) {\n throw new RangeError(\"Failed to verify SubjectPublicKeyInfo data\");\n }\n const bitstring: BitString = (result as typeof SubjectPublicKeyInfo)\n .valueBlock.value[1] as BitString;\n return bitstring.valueBlock.valueHexView;\n}\n", "import { AwsKmsAccount } from \"./AwsKmsAccount.js\";\nimport { AwsKmsKeyId } from \"./AwsKmsKeyId.js\";\nimport { AwsKmsMetadata } from \"./AwsKmsMetadata.js\";\nimport { parseSubjectPublicKeyInfo } from \"./asn1.js\";\nimport {\n CreateKeyCommand,\n DescribeKeyCommand,\n GetPublicKeyCommand,\n KMSClient,\n KMSInvalidStateException,\n type KeyMetadata,\n ListKeysCommand,\n ListResourceTagsCommand,\n NotFoundException,\n OriginType,\n ScheduleKeyDeletionCommand,\n} from \"@aws-sdk/client-kms\";\nimport {\n type AccountDeletion,\n type AccountGeneration,\n type AccountMetadata,\n type AccountRetrieval,\n type MutableKeyStore,\n PublicKey,\n} from \"@planetarium/account\";\n\nexport interface AwsKmsKeyStoreOptions {\n listWindow: number;\n scopingTags: Record<string, string>;\n}\n\nexport class AwsKmsKeyStore\n implements MutableKeyStore<AwsKmsKeyId, AwsKmsAccount, AwsKmsMetadata>\n{\n readonly #client: KMSClient;\n readonly #options: AwsKmsKeyStoreOptions;\n\n constructor(client: KMSClient, options: Partial<AwsKmsKeyStoreOptions> = {}) {\n this.#client = client;\n this.#options = {\n listWindow: options.listWindow ?? 100,\n scopingTags: options.scopingTags ?? {},\n };\n }\n\n #isValidKey(\n metadata: KeyMetadata,\n ): metadata is KeyMetadata & { KeyId: string } {\n return (\n metadata.KeyId != null &&\n metadata.Enabled === true &&\n metadata.DeletionDate == null &&\n metadata.KeySpec === \"ECC_SECG_P256K1\" &&\n metadata.KeyUsage === \"SIGN_VERIFY\"\n );\n }\n\n #mapMetadata(metadata: KeyMetadata): AwsKmsMetadata {\n return {\n customKeyStoreId: metadata.CustomKeyStoreId,\n description: metadata.Description ?? \"\",\n multiRegion: metadata.MultiRegion ?? false,\n origin: metadata.Origin ?? OriginType.AWS_KMS,\n };\n }\n\n async #hasTags(\n keyId: AwsKmsKeyId,\n tags: Record<string, string>,\n ): Promise<boolean> {\n let marker: string | undefined;\n const remainTags = new Map(Object.entries(tags));\n do {\n const cmd = new ListResourceTagsCommand({ KeyId: keyId, Marker: marker });\n const result = await this.#client.send(cmd);\n marker = result.NextMarker;\n if (result.Tags == null) continue;\n for (const { TagKey, TagValue } of result.Tags) {\n if (TagKey == null || TagValue == null) continue;\n if (remainTags.has(TagKey)) {\n if (remainTags.get(TagKey) === TagValue) {\n remainTags.delete(TagKey);\n if (remainTags.size < 1) return true;\n } else return false;\n }\n }\n } while (marker != null);\n return remainTags.size < 1;\n }\n\n async *list(): AsyncIterable<AccountMetadata<AwsKmsKeyId, AwsKmsMetadata>> {\n let nextMarker: string | undefined;\n const hasScopingTags = Object.keys(this.#options).length > 0;\n do {\n const listCmd = new ListKeysCommand({\n Marker: nextMarker,\n Limit: this.#options.listWindow,\n });\n const resp = await this.#client.send(listCmd);\n const keys = resp.Keys ?? [];\n for (let i = 0; i < keys.length; i += 5) {\n const promises = keys\n .slice(i, i + 5)\n .map(({ KeyId }) => new DescribeKeyCommand({ KeyId }))\n .map((cmd) => this.#client.send(cmd));\n const responses = await Promise.all(promises);\n for (const resp of responses) {\n const metadata = resp.KeyMetadata;\n if (\n metadata == null ||\n !this.#isValidKey(metadata) ||\n (hasScopingTags &&\n !this.#hasTags(metadata.KeyId, this.#options.scopingTags))\n ) {\n continue;\n }\n yield {\n keyId: metadata.KeyId,\n metadata: this.#mapMetadata(metadata),\n createdAt: metadata.CreationDate,\n };\n }\n }\n nextMarker = resp.NextMarker;\n } while (nextMarker != null);\n }\n\n async get(\n keyId: AwsKmsKeyId,\n ): Promise<AccountRetrieval<AwsKmsKeyId, AwsKmsAccount, AwsKmsMetadata>> {\n const descCmd = new DescribeKeyCommand({ KeyId: keyId });\n const pubKeyCmd = new GetPublicKeyCommand({ KeyId: keyId });\n const descPromise = this.#client.send(descCmd);\n const pubKeyPromise = this.#client.send(pubKeyCmd);\n let descResp;\n let pubKeyResp;\n try {\n [descResp, pubKeyResp] = await Promise.all([descPromise, pubKeyPromise]);\n } catch (e) {\n if (\n e instanceof NotFoundException ||\n e instanceof KMSInvalidStateException\n ) {\n return { result: \"keyNotFound\", keyId };\n }\n return { result: \"error\", keyId, message: `${e}` };\n }\n if (\n descResp.KeyMetadata == null ||\n !this.#isValidKey(descResp.KeyMetadata) ||\n pubKeyResp.PublicKey == null\n ) {\n return { result: \"keyNotFound\", keyId };\n }\n const publicKeyBytes: Uint8Array = parseSubjectPublicKeyInfo(\n pubKeyResp.PublicKey,\n );\n const publicKey = PublicKey.fromBytes(publicKeyBytes, \"uncompressed\");\n return {\n result: \"success\",\n keyId,\n account: new AwsKmsAccount(keyId, publicKey, this.#client),\n metadata: this.#mapMetadata(descResp.KeyMetadata),\n createdAt: descResp.KeyMetadata.CreationDate,\n };\n }\n\n async generate(\n metadata?: AwsKmsMetadata,\n ): Promise<AccountGeneration<AwsKmsKeyId, AwsKmsAccount>> {\n const cmd = new CreateKeyCommand({\n KeySpec: \"ECC_SECG_P256K1\",\n KeyUsage: \"SIGN_VERIFY\",\n CustomKeyStoreId: metadata?.customKeyStoreId,\n Description: metadata?.description,\n MultiRegion: metadata?.multiRegion,\n Origin: metadata?.origin,\n Tags: Object.entries(this.#options.scopingTags).map(\n ([TagKey, TagValue]) => ({ TagKey, TagValue }),\n ),\n });\n let response;\n try {\n response = await this.#client.send(cmd);\n } catch (e) {\n return { result: \"error\", message: `${e}` };\n }\n const keyId = response.KeyMetadata?.KeyId;\n if (keyId == null) {\n return { result: \"error\", message: \"failed to determine keyId\" };\n }\n const pubKeyCmd = new GetPublicKeyCommand({ KeyId: keyId });\n let pubKeyResp;\n try {\n pubKeyResp = await this.#client.send(pubKeyCmd);\n } catch (e) {\n return { result: \"error\", message: `${e}` };\n }\n if (pubKeyResp.PublicKey == null) {\n return { result: \"error\", message: \"failed to get public key\" };\n }\n const publicKeyBytes: Uint8Array = parseSubjectPublicKeyInfo(\n pubKeyResp.PublicKey,\n );\n const publicKey = PublicKey.fromBytes(publicKeyBytes, \"uncompressed\");\n const account = new AwsKmsAccount(keyId, publicKey, this.#client);\n return { result: \"success\", keyId, account };\n }\n\n async delete(keyId: AwsKmsKeyId): Promise<AccountDeletion<AwsKmsKeyId>> {\n const cmd = new ScheduleKeyDeletionCommand({ KeyId: keyId });\n try {\n await this.#client.send(cmd);\n } catch (e) {\n if (\n e instanceof NotFoundException ||\n e instanceof KMSInvalidStateException\n ) {\n return { result: \"keyNotFound\", keyId };\n }\n return { result: \"error\", message: `${e}` };\n }\n return { result: \"success\", keyId };\n }\n}\n", "export { AwsKmsKeyStore } from \"./AwsKmsKeyStore.js\";\nexport { type AwsKmsKeyId } from \"./AwsKmsKeyId.js\";\nexport { AwsKmsAccount } from \"./AwsKmsAccount.js\";\nexport { type AwsKmsMetadata } from \"./AwsKmsMetadata.js\";\nexport { KMSClient } from \"@aws-sdk/client-kms\";\n"],
"mappings": "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",
"names": ["PublicKey", "resp", "PublicKey", "KMSClient"]
}