From 3a9304a350506fba7e521541f734d2defc436570 Mon Sep 17 00:00:00 2001 From: jagpreetsinghsaan Date: Thu, 22 Jul 2021 16:31:01 +0530 Subject: [PATCH] feat(azure-kv): added keychain plugin for azure keyvault Primary Change --- 1. Added new package cactus-plugin-keychain-azure-kv under packages/ 2. Added PluginKeychainAzureKvMock class to mock the functions of SecretClient under packages/cactus-plugin-keychain-azure-kv/src/test/typescript/mock/plugin-keychain-azure-kv-mock.ts Resolves #971 Signed-off-by: jagpreetsinghsaan --- .cspell.json | 3 +- .../cactus-plugin-keychain-azure-kv/README.md | 3 + .../openapitools.json | 7 + .../package.json | 94 +++++++ .../src/main/json/openapi.json | 81 ++++++ .../.openapi-generator-ignore | 27 ++ .../typescript-axios/.openapi-generator/FILES | 5 + .../.openapi-generator/VERSION | 1 + .../generated/openapi/typescript-axios/api.ts | 264 ++++++++++++++++++ .../openapi/typescript-axios/base.ts | 71 +++++ .../openapi/typescript-axios/common.ts | 138 +++++++++ .../openapi/typescript-axios/configuration.ts | 101 +++++++ .../openapi/typescript-axios/index.ts | 18 ++ .../src/main/typescript/index.ts | 1 + .../src/main/typescript/index.web.ts | 1 + .../typescript/plugin-factory-keychain.ts | 27 ++ .../typescript/plugin-keychain-azure-kv.ts | 232 +++++++++++++++ .../src/main/typescript/public-api.ts | 18 ++ .../plugin-keychain-azure-kv.test.ts | 59 ++++ .../mock/plugin-keychain-azure-kv-mock.ts | 146 ++++++++++ .../test/typescript/unit/api-surface.test.ts | 7 + .../tsconfig.json | 10 + .../cactus-plugin-keychain-vault/package.json | 1 - webpack.prod.node.js | 1 + 24 files changed, 1314 insertions(+), 2 deletions(-) create mode 100644 packages/cactus-plugin-keychain-azure-kv/README.md create mode 100644 packages/cactus-plugin-keychain-azure-kv/openapitools.json create mode 100644 packages/cactus-plugin-keychain-azure-kv/package.json create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/json/openapi.json create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/api.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/base.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/common.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/configuration.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/index.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.web.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-factory-keychain.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-keychain-azure-kv.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/main/typescript/public-api.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/test/typescript/integration/plugin-keychain-azure-kv.test.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/test/typescript/mock/plugin-keychain-azure-kv-mock.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/src/test/typescript/unit/api-surface.test.ts create mode 100644 packages/cactus-plugin-keychain-azure-kv/tsconfig.json diff --git a/.cspell.json b/.cspell.json index 89c3df83eaf..634be4a1b9e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -90,7 +90,8 @@ "uuidv", "vscc", "wasm", - "Xdai" + "Xdai", + "parameterizable" ], "dictionaries": [ "typescript,node,npm,go,rust" diff --git a/packages/cactus-plugin-keychain-azure-kv/README.md b/packages/cactus-plugin-keychain-azure-kv/README.md new file mode 100644 index 00000000000..71001042c8a --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/README.md @@ -0,0 +1,3 @@ +# `@hyperledger/cactus-plugin-keychain-azure-kv` + +# TO-DO \ No newline at end of file diff --git a/packages/cactus-plugin-keychain-azure-kv/openapitools.json b/packages/cactus-plugin-keychain-azure-kv/openapitools.json new file mode 100644 index 00000000000..29f5d069907 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "5.2.0" + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/package.json b/packages/cactus-plugin-keychain-azure-kv/package.json new file mode 100644 index 00000000000..646b0a610f7 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/package.json @@ -0,0 +1,94 @@ +{ + "name": "@hyperledger/cactus-plugin-keychain-azure-kv", + "version": "0.6.0", + "description": "A keychain implementation storing its entries in Azure key vault.", + "main": "dist/lib/main/typescript/index.js", + "mainMinified": "dist/cactus-plugin-keychain-azure-kv.node.umd.min.js", + "browser": "dist/cactus-plugin-keychain-azure-kv.web.umd.js", + "browserMinified": "dist/cactus-plugin-keychain-azure-kv.web.umd.min.js", + "module": "dist/lib/main/typescript/index.js", + "types": "dist/types/main/typescript/index.d.ts", + "files": [ + "dist/*" + ], + "scripts": { + "generate-sdk": "openapi-generator-cli generate -i ./src/main/json/openapi.json -g typescript-axios -o ./src/main/typescript/generated/openapi/typescript-axios/", + "codegen:openapi": "npm run generate-sdk", + "codegen": "run-p 'codegen:*'", + "watch": "npm-watch", + "pretsc": "npm run generate-sdk", + "webpack": "npm-run-all webpack:dev webpack:prod", + "webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web", + "webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js", + "webpack:dev:node": "webpack --env=dev --target=node --config ../../webpack.config.js", + "webpack:prod": "npm-run-all webpack:prod:node webpack:prod:web", + "webpack:prod:web": "webpack --env=prod --target=web --config ../../webpack.config.js", + "webpack:prod:node": "webpack --env=prod --target=node --config ../../webpack.config.js" + }, + "watch": { + "codegen:openapi": { + "patterns": [ + "./src/main/json/openapi.json" + ] + } + }, + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hyperledger/cactus.git" + }, + "keywords": [ + "Hyperledger", + "Cactus", + "Integration", + "Blockchain", + "Distributed Ledger Technology" + ], + "author": { + "name": "Hyperledger Cactus Contributors", + "email": "cactus@lists.hyperledger.org", + "url": "https://www.hyperledger.org/use/cactus" + }, + "contributors": [ + { + "name": "Please add yourself to the list of contributors", + "email": "your.name@example.com", + "url": "https://example.com" + }, + { + "name": "Peter Somogyvari", + "email": "peter.somogyvari@accenture.com", + "url": "https://accenture.com" + } + ], + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/hyperledger/cactus/issues" + }, + "homepage": "https://github.com/hyperledger/cactus#readme", + "dependencies": { + "@azure/identity": "1.3.0", + "@azure/keyvault-secrets": "4.1.0", + "@hyperledger/cactus-common": "0.6.0", + "@hyperledger/cactus-core": "0.6.0", + "@hyperledger/cactus-core-api": "0.6.0", + "axios": "0.21.1", + "http-status-codes": "2.1.4", + "typescript-optional": "2.0.1" + }, + "devDependencies": { + "@hyperledger/cactus-test-tooling": "0.6.0", + "@types/express": "4.17.8", + "@types/express-serve-static-core": "4.17.17", + "@types/request": "2.48.5", + "internal-ip": "6.2.0", + "express": "4.17.1", + "openapi-types": "7.2.2" + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/json/openapi.json b/packages/cactus-plugin-keychain-azure-kv/src/main/json/openapi.json new file mode 100644 index 00000000000..0a75c1942ab --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/json/openapi.json @@ -0,0 +1,81 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Hyperledger Cactus - Keychain API", + "description": "Contains/describes the Keychain API types/paths for Hyperledger Cactus.", + "version": "0.3.0", + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "components": { + "schemas": { + } + }, + "paths": { + "/api/v1/plugins/@hyperledger/cactus-plugin-keychain-azure-kv/get-keychain-entry": { + "post": { + "x-hyperledger-cactus": { + "http": { + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-keychain-azure-kv/get-keychain-entry", + "verbLowerCase": "post" + } + }, + "operationId": "getKeychainEntryV1", + "summary": "Retrieves the contents of a keychain entry from the backend.", + "parameters": [], + "requestBody": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/requestBodies/keychain_get_entry_request_body" + }, + "responses": { + "200": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_get_entry_200" + }, + "400": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_get_entry_400" + }, + "401": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_get_entry_401" + }, + "404": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_get_entry_404" + }, + "500": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_get_entry_500" + } + } + } + }, + "/api/v1/plugins/@hyperledger/cactus-plugin-keychain-azure-kv/set-keychain-entry": { + "post": { + "x-hyperledger-cactus": { + "http": { + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-keychain-azure-kv/set-keychain-entry", + "verbLowerCase": "post" + } + }, + "operationId": "setKeychainEntryV1", + "summary": "Sets a value under a key on the keychain backend.", + "parameters": [], + "requestBody": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/requestBodies/keychain_set_entry_request_body" + }, + "responses": { + "200": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_set_entry_200" + }, + "400": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_set_entry_400" + }, + "401": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_set_entry_401" + }, + "500": { + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/responses/keychain_set_entry_500" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore new file mode 100644 index 00000000000..ad66c7e1784 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore @@ -0,0 +1,27 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md + +.npmignore +.gitignore +git_push.sh diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES new file mode 100644 index 00000000000..53250c02696 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES @@ -0,0 +1,5 @@ +api.ts +base.ts +common.ts +configuration.ts +index.ts diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION new file mode 100644 index 00000000000..7cbea073bea --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION @@ -0,0 +1 @@ +5.2.0 \ No newline at end of file diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/api.ts new file mode 100644 index 00000000000..1d325d0f6dd --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -0,0 +1,264 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus - Keychain API + * Contains/describes the Keychain API types/paths for Hyperledger Cactus. + * + * The version of the OpenAPI document: 0.3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from './configuration'; +import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from './base'; + +/** + * + * @export + * @interface GetKeychainEntryRequest + */ +export interface GetKeychainEntryRequest { + /** + * The key for the entry to get from the keychain. + * @type {string} + * @memberof GetKeychainEntryRequest + */ + key: string; +} +/** + * + * @export + * @interface GetKeychainEntryResponse + */ +export interface GetKeychainEntryResponse { + /** + * The key that was used to retrieve the value from the keychain. + * @type {string} + * @memberof GetKeychainEntryResponse + */ + key: string; + /** + * The value associated with the requested key on the keychain. + * @type {string} + * @memberof GetKeychainEntryResponse + */ + value: string; +} +/** + * + * @export + * @interface SetKeychainEntryRequest + */ +export interface SetKeychainEntryRequest { + /** + * The key for the entry to set on the keychain. + * @type {string} + * @memberof SetKeychainEntryRequest + */ + key: string; + /** + * The value that will be associated with the key on the keychain. + * @type {string} + * @memberof SetKeychainEntryRequest + */ + value: string; +} +/** + * + * @export + * @interface SetKeychainEntryResponse + */ +export interface SetKeychainEntryResponse { + /** + * The key that was used to set the value on the keychain. + * @type {string} + * @memberof SetKeychainEntryResponse + */ + key: string; +} + +/** + * DefaultApi - axios parameter creator + * @export + */ +export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @summary Retrieves the contents of a keychain entry from the backend. + * @param {GetKeychainEntryRequest} getKeychainEntryRequest Request body to obtain a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getKeychainEntryV1: async (getKeychainEntryRequest: GetKeychainEntryRequest, options: any = {}): Promise => { + // verify required parameter 'getKeychainEntryRequest' is not null or undefined + assertParamExists('getKeychainEntryV1', 'getKeychainEntryRequest', getKeychainEntryRequest) + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-keychain-azure-kv/get-keychain-entry`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(getKeychainEntryRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Sets a value under a key on the keychain backend. + * @param {SetKeychainEntryRequest} setKeychainEntryRequest Request body to write/update a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + setKeychainEntryV1: async (setKeychainEntryRequest: SetKeychainEntryRequest, options: any = {}): Promise => { + // verify required parameter 'setKeychainEntryRequest' is not null or undefined + assertParamExists('setKeychainEntryV1', 'setKeychainEntryRequest', setKeychainEntryRequest) + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-keychain-azure-kv/set-keychain-entry`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(setKeychainEntryRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * DefaultApi - functional programming interface + * @export + */ +export const DefaultApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration) + return { + /** + * + * @summary Retrieves the contents of a keychain entry from the backend. + * @param {GetKeychainEntryRequest} getKeychainEntryRequest Request body to obtain a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getKeychainEntryV1(getKeychainEntryRequest: GetKeychainEntryRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getKeychainEntryV1(getKeychainEntryRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @summary Sets a value under a key on the keychain backend. + * @param {SetKeychainEntryRequest} setKeychainEntryRequest Request body to write/update a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async setKeychainEntryV1(setKeychainEntryRequest: SetKeychainEntryRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.setKeychainEntryV1(setKeychainEntryRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + } +}; + +/** + * DefaultApi - factory interface + * @export + */ +export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = DefaultApiFp(configuration) + return { + /** + * + * @summary Retrieves the contents of a keychain entry from the backend. + * @param {GetKeychainEntryRequest} getKeychainEntryRequest Request body to obtain a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getKeychainEntryV1(getKeychainEntryRequest: GetKeychainEntryRequest, options?: any): AxiosPromise { + return localVarFp.getKeychainEntryV1(getKeychainEntryRequest, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Sets a value under a key on the keychain backend. + * @param {SetKeychainEntryRequest} setKeychainEntryRequest Request body to write/update a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + setKeychainEntryV1(setKeychainEntryRequest: SetKeychainEntryRequest, options?: any): AxiosPromise { + return localVarFp.setKeychainEntryV1(setKeychainEntryRequest, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * DefaultApi - object-oriented interface + * @export + * @class DefaultApi + * @extends {BaseAPI} + */ +export class DefaultApi extends BaseAPI { + /** + * + * @summary Retrieves the contents of a keychain entry from the backend. + * @param {GetKeychainEntryRequest} getKeychainEntryRequest Request body to obtain a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getKeychainEntryV1(getKeychainEntryRequest: GetKeychainEntryRequest, options?: any) { + return DefaultApiFp(this.configuration).getKeychainEntryV1(getKeychainEntryRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Sets a value under a key on the keychain backend. + * @param {SetKeychainEntryRequest} setKeychainEntryRequest Request body to write/update a keychain entry via its key + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public setKeychainEntryV1(setKeychainEntryRequest: SetKeychainEntryRequest, options?: any) { + return DefaultApiFp(this.configuration).setKeychainEntryV1(setKeychainEntryRequest, options).then((request) => request(this.axios, this.basePath)); + } +} + + diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/base.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/base.ts new file mode 100644 index 00000000000..5bdd7d5a901 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/base.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus - Keychain API + * Contains/describes the Keychain API types/paths for Hyperledger Cactus. + * + * The version of the OpenAPI document: 0.3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from "./configuration"; +// Some imports not used depending on template conditions +// @ts-ignore +import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; + +export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: any; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath || this.basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + name: "RequiredError" = "RequiredError"; + constructor(public field: string, msg?: string) { + super(msg); + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/common.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/common.ts new file mode 100644 index 00000000000..551dfb0d3cc --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/common.ts @@ -0,0 +1,138 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus - Keychain API + * Contains/describes the Keychain API types/paths for Hyperledger Cactus. + * + * The version of the OpenAPI document: 0.3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from "./configuration"; +import { RequiredError, RequestArgs } from "./base"; +import { AxiosInstance } from 'axios'; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com' + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); + } +} + +/** + * + * @export + */ +export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +} + +/** + * + * @export + */ +export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { + if (configuration && (configuration.username || configuration.password)) { + object["auth"] = { username: configuration.username, password: configuration.password }; + } +} + +/** + * + * @export + */ +export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object["Authorization"] = "Bearer " + accessToken; + } +} + +/** + * + * @export + */ +export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object["Authorization"] = "Bearer " + localVarAccessTokenValue; + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + for (const object of objects) { + for (const key in object) { + if (Array.isArray(object[key])) { + searchParams.delete(key); + for (const item of object[key]) { + searchParams.append(key, item); + } + } else { + searchParams.set(key, object[key]); + } + } + } + url.search = searchParams.toString(); +} + +/** + * + * @export + */ +export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { + const nonString = typeof value !== 'string'; + const needsSerialization = nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : (value || ""); +} + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash +} + +/** + * + * @export + */ +export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/configuration.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/configuration.ts new file mode 100644 index 00000000000..51c912ecd9a --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/configuration.ts @@ -0,0 +1,101 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus - Keychain API + * Contains/describes the Keychain API types/paths for Hyperledger Cactus. + * + * The version of the OpenAPI document: 0.3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface ConfigurationParameters { + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.baseOptions = param.baseOptions; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/index.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/index.ts new file mode 100644 index 00000000000..dece72213b3 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/generated/openapi/typescript-axios/index.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus - Keychain API + * Contains/describes the Keychain API types/paths for Hyperledger Cactus. + * + * The version of the OpenAPI document: 0.3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export * from "./api"; +export * from "./configuration"; + diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.ts new file mode 100644 index 00000000000..87cb558397c --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.ts @@ -0,0 +1 @@ +export * from "./public-api"; diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.web.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.web.ts new file mode 100644 index 00000000000..bdf54028d23 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/index.web.ts @@ -0,0 +1 @@ +export * from "./generated/openapi/typescript-axios/index"; diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-factory-keychain.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-factory-keychain.ts new file mode 100644 index 00000000000..b9edb78dcc0 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-factory-keychain.ts @@ -0,0 +1,27 @@ +import { v4 as uuidv4 } from "uuid"; +import { + IPluginFactoryOptions, + PluginFactory, +} from "@hyperledger/cactus-core-api"; + +import { + IPluginKeychainAzureKvOptions, + PluginKeychainAzureKv, +} from "./plugin-keychain-azure-kv"; + +export class PluginFactoryKeychain extends PluginFactory< + PluginKeychainAzureKv, + IPluginKeychainAzureKvOptions, + IPluginFactoryOptions +> { + async create( + pluginOptions: IPluginKeychainAzureKvOptions = { + instanceId: uuidv4(), + keychainId: uuidv4(), + azureEndpoint: "", + logLevel: "TRACE", + }, + ): Promise { + return new PluginKeychainAzureKv(pluginOptions); + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-keychain-azure-kv.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-keychain-azure-kv.ts new file mode 100644 index 00000000000..a433f666787 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-keychain-azure-kv.ts @@ -0,0 +1,232 @@ +import type { Server } from "http"; +import type { Server as SecureServer } from "https"; + +import type { Express } from "express"; +import { Optional } from "typescript-optional"; + +import { + Logger, + Checks, + LogLevelDesc, + LoggerProvider, +} from "@hyperledger/cactus-common"; +import { + ICactusPlugin, + ICactusPluginOptions, + IPluginKeychain, + IPluginWebService, + IWebServiceEndpoint, +} from "@hyperledger/cactus-core-api"; + +import { KeyVaultSecret, SecretClient } from "@azure/keyvault-secrets"; +import { + UsernamePasswordCredential, + DefaultAzureCredential, +} from "@azure/identity"; + +// TODO: Writing the getExpressRequestHandler() method for +// GetKeychainEntryEndpointV1 and SetKeychainEntryEndpointV1 +// import { GetKeychainEntryEndpointV1 } from "./web-services/get-keychain-entry-endpoint-v1"; +// import { SetKeychainEntryEndpointV1 } from "./web-services/set-keychain-entry-endpoint-v1"; + +export enum AzureCredentialType { + LocalFile = "LOCAL_FILE", + InMemory = "IN_MEMORY", +} + +export interface IAzureInMemoryCredentials { + azureTenantId: string; + azureClientId: string; + azureUsername: string; + azurePassword: string; +} + +export interface IPluginKeychainAzureKvOptions extends ICactusPluginOptions { + logLevel?: LogLevelDesc; + keychainId: string; + instanceId: string; + azureEndpoint: string; + azureCredentialType?: AzureCredentialType; + azureInMemoryCredentials?: IAzureInMemoryCredentials; + backend?: SecretClient; +} + +export class PluginKeychainAzureKv + implements ICactusPlugin, IPluginWebService, IPluginKeychain { + public static readonly CLASS_NAME = "PluginKeychainAzureKv"; + + readonly vaultUrl: string; + private readonly log: Logger; + private readonly instanceId: string; + private endpoints: IWebServiceEndpoint[] | undefined; + private azureKvClient: SecretClient; + + public get className() { + return PluginKeychainAzureKv.CLASS_NAME; + } + + constructor(public readonly opts: IPluginKeychainAzureKvOptions) { + const fnTag = `${this.className}#constructor()`; + Checks.truthy(opts, `${fnTag} arg options`); + Checks.truthy(opts.keychainId, `${fnTag} arg options.keychainId`); + Checks.truthy(opts.instanceId, `${fnTag} options.instanceId`); + Checks.nonBlankString(opts.keychainId, `${fnTag} options.keychainId`); + Checks.nonBlankString(opts.azureEndpoint, `${fnTag} options.azureEndpoint`); + if ( + opts.azureCredentialType && + opts.azureInMemoryCredentials && + opts.azureCredentialType == AzureCredentialType.InMemory + ) { + Checks.nonBlankString( + opts.azureInMemoryCredentials.azureTenantId, + `${fnTag} opts.azureInMemoryCredentials.azureTenantId`, + ); + Checks.nonBlankString( + opts.azureInMemoryCredentials.azureClientId, + `${fnTag} opts.azureInMemoryCredentials.azureClientId`, + ); + Checks.nonBlankString( + opts.azureInMemoryCredentials.azureUsername, + `${fnTag} opts.azureInMemoryCredentials.azureUsername`, + ); + Checks.nonBlankString( + opts.azureInMemoryCredentials.azurePassword, + `${fnTag} opts.azureInMemoryCredentials.azurePassword`, + ); + } + + const level = this.opts.logLevel || "INFO"; + const label = this.className; + this.log = LoggerProvider.getOrCreate({ level, label }); + + this.instanceId = this.opts.instanceId; + this.vaultUrl = this.opts.azureEndpoint; + + if (opts.backend) { + this.azureKvClient = opts.backend; + } else if ( + !opts.backend && + opts.azureCredentialType == AzureCredentialType.InMemory && + opts.azureInMemoryCredentials + ) { + const azureCredentials = new UsernamePasswordCredential( + opts.azureInMemoryCredentials.azureTenantId, + opts.azureInMemoryCredentials.azureClientId, + opts.azureInMemoryCredentials.azureUsername, + opts.azureInMemoryCredentials.azurePassword, + ); + this.azureKvClient = new SecretClient(this.vaultUrl, azureCredentials); + } else { + const azureCredentials = new DefaultAzureCredential(); + this.azureKvClient = new SecretClient(this.vaultUrl, azureCredentials); + } + + this.log.info(`Created ${this.className}. KeychainID=${opts.keychainId}`); + } + + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + await Promise.all(webServices.map((ws) => ws.registerExpress(app))); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } + const endpoints: IWebServiceEndpoint[] = []; + + // TODO: Writing the getExpressRequestHandler() method for + // GetKeychainEntryEndpointV1 and SetKeychainEntryEndpointV1 + + // { + // const ep = new GetKeychainEntryEndpointV1({ + // logLevel: this.opts.logLevel, + // }); + // ep.registerExpress(expressApp); + // endpoints.push(ep); + // } + // { + // const ep = new SetKeychainEntryEndpointV1({ + // logLevel: this.opts.logLevel, + // }); + // ep.registerExpress(expressApp); + // endpoints.push(ep); + // } + this.endpoints = endpoints; + + return endpoints; + } + + public getHttpServer(): Optional { + return Optional.empty(); + } + + public async shutdown(): Promise { + throw new Error("Method not implemented."); + } + + public getInstanceId(): string { + return this.instanceId; + } + + public getKeychainId(): string { + return this.opts.keychainId; + } + + public async onPluginInit(): Promise { + return; + } + + public getPackageName(): string { + return `@hyperledger/cactus-plugin-keychain-vault`; + } + + async rotateEncryptionKeys(): Promise { + throw new Error("Method not implemented."); + } + + public getEncryptionAlgorithm(): string { + return null as any; + } + + public getAzureKvClient(): SecretClient { + return this.azureKvClient; + } + + async get(key: string): Promise { + const keyVaultSecret: KeyVaultSecret = await this.azureKvClient.getSecret( + key, + ); + if (keyVaultSecret) { + const result = keyVaultSecret.value; + return (result as unknown) as T; + } else { + throw new Error(`${key} secret not found`); + } + } + + /** + * Detects the presence of a key by trying to read it and then + * observing whether an HTTP 404 NOT FOUND error is returned or + * not and deciding whether the keychain has the entry ot not + * based on this. + */ + + async has(key: string): Promise { + const keyVaultSecret = await this.azureKvClient.getSecret(key); + if (keyVaultSecret) { + return true; + } else { + return false; + } + } + + async set(key: string, value: T): Promise { + await this.azureKvClient.setSecret(key, (value as unknown) as string); + } + + async delete(key: string): Promise { + await this.azureKvClient.beginDeleteSecret(key); + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/public-api.ts b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/public-api.ts new file mode 100644 index 00000000000..70b45e0015c --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/main/typescript/public-api.ts @@ -0,0 +1,18 @@ +export * from "./generated/openapi/typescript-axios/index"; + +import { IPluginFactoryOptions } from "@hyperledger/cactus-core-api"; + +import { PluginFactoryKeychain } from "./plugin-factory-keychain"; +export { PluginFactoryKeychain } from "./plugin-factory-keychain"; + +export { + IPluginKeychainAzureKvOptions, + PluginKeychainAzureKv, + AzureCredentialType, +} from "./plugin-keychain-azure-kv"; + +export async function createPluginFactory( + pluginFactoryOptions: IPluginFactoryOptions, +): Promise { + return new PluginFactoryKeychain(pluginFactoryOptions); +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/integration/plugin-keychain-azure-kv.test.ts b/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/integration/plugin-keychain-azure-kv.test.ts new file mode 100644 index 00000000000..3432888f532 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/integration/plugin-keychain-azure-kv.test.ts @@ -0,0 +1,59 @@ +import test, { Test } from "tape-promise/tape"; + +import { v4 as uuidv4 } from "uuid"; + +import { LogLevelDesc } from "@hyperledger/cactus-common"; + +import { + IPluginKeychainAzureKvOptions, + PluginKeychainAzureKv, +} from "../../../main/typescript/public-api"; + +import { SecretClientMock } from "../mock/plugin-keychain-azure-kv-mock"; + +const logLevel: LogLevelDesc = "TRACE"; + +test("get,set,has,delete alters state as expected for AzureCredentialType.InMemory", async (t: Test) => { + const options: IPluginKeychainAzureKvOptions = { + instanceId: uuidv4(), + keychainId: uuidv4(), + logLevel: logLevel, + azureEndpoint: "testEndpoint", + backend: new SecretClientMock({ + azureKvUrl: "testUrl", + logLevel: logLevel, + }), + }; + const plugin = new PluginKeychainAzureKv(options); + + t.equal(plugin.getKeychainId(), options.keychainId, "Keychain ID set OK"); + t.equal(plugin.getInstanceId(), options.instanceId, "Instance ID set OK"); + + const key = uuidv4(); + const value = uuidv4(); + + const hasPrior = await plugin.has(key); + + t.false(hasPrior, "hasPrior === false OK"); + + await plugin.set(key, value); + + const hasAfter = await plugin.has(key); + t.true(hasAfter, "hasAfter === true OK"); + + const valueAfter = await plugin.get(key); + t.ok(valueAfter, "valueAfter truthy OK"); + t.equal(valueAfter, value, "valueAfter === value OK"); + + await plugin.delete(key); + + const hasAfterDelete = await plugin.has(key); + t.false(hasAfterDelete, "hasAfterDelete === false OK"); + + const valueAfterDelete = plugin.get(key); + const regExp = new RegExp(/secret not found*/); + const rejectMsg = "valueAfterDelete === throws OK"; + await t.rejects(valueAfterDelete, regExp, rejectMsg); + + t.end(); +}); diff --git a/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/mock/plugin-keychain-azure-kv-mock.ts b/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/mock/plugin-keychain-azure-kv-mock.ts new file mode 100644 index 00000000000..01f92b4a2c1 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/mock/plugin-keychain-azure-kv-mock.ts @@ -0,0 +1,146 @@ +/** + * This class mocks the SecretClient class of "@azure/keyvault-secrets" library + * by overriding the SecretClient class methods and storing the secrets In-Memory + * TO DO: This class shall be replaced with actual usage of SecretClient class in + * the main class located at packages/cactus-plugin-keychain-azure-kv/src/main/typescript/plugin-keychain-azure-kv.ts + */ +import { + Logger, + Checks, + LogLevelDesc, + LoggerProvider, +} from "@hyperledger/cactus-common"; + +import { + SecretClient, + KeyVaultSecret, + SecretProperties, + PollerLike, + PollOperationState, + DeletedSecret, + PagedAsyncIterableIterator, +} from "@azure/keyvault-secrets"; + +export interface ISecretClientMock { + azureKvUrl: string; + logLevel?: LogLevelDesc; +} + +export class SecretClientMock implements SecretClient { + public static readonly CLASS_NAME = "SecretClientMock"; + private readonly log: Logger; + readonly vaultUrl: string; + private readonly secrets: Map; + + public get className(): string { + return SecretClientMock.CLASS_NAME; + } + + constructor(public readonly options: ISecretClientMock) { + const fnTag = `${this.className}#constructor()`; + Checks.truthy(options, `${fnTag} arg options`); + + const level = this.options.logLevel || "INFO"; + const label = this.className; + this.vaultUrl = this.options.azureKvUrl; + this.secrets = new Map(); + this.log = LoggerProvider.getOrCreate({ level, label }); + } + + async setSecret(secretName: string, value: string): Promise { + this.secrets.set(secretName, value); + const secretProperties: SecretProperties = { + vaultUrl: this.vaultUrl, + name: secretName, + }; + const keyVaultSecret: KeyVaultSecret = { + properties: secretProperties, + name: secretName, + }; + return keyVaultSecret; + } + + async beginDeleteSecret( + name: string, + ): Promise, DeletedSecret>> { + this.secrets.delete(name); + const secretProperties = { + vaultUrl: this.vaultUrl, + name: name, + } as SecretProperties; + const deletedSecret = { + properties: secretProperties, + } as DeletedSecret; + const pollOperationsState = deletedSecret as PollOperationState< + DeletedSecret + >; + const pollerLike = pollOperationsState as PollerLike< + PollOperationState, + DeletedSecret + >; + return pollerLike; + } + + async updateSecretProperties(): Promise { + throw new Error("Method not implemented."); + } + + async getSecret(secretName: string): Promise { + const result = this.secrets.get(secretName)?.toString(); + if (result == undefined) { + return (null as unknown) as KeyVaultSecret; + } else { + const secretProperties: SecretProperties = { + vaultUrl: this.vaultUrl, + name: secretName, + }; + const keyVaultSecret: KeyVaultSecret = { + properties: secretProperties, + name: secretName, + value: result, + }; + return keyVaultSecret; + } + } + + async hasSecret(secretName: string): Promise { + const result = this.secrets.has(secretName); + return result; + } + + async getDeletedSecret(): Promise { + throw new Error("Method not implemented"); + } + + async purgeDeletedSecret(): Promise { + throw new Error("Method not implemented"); + } + + async beginRecoverDeletedSecret(): Promise< + PollerLike, SecretProperties> + > { + throw new Error("Method not implemented"); + } + + async backupSecret(): Promise { + throw new Error("Method not implemented"); + } + + async restoreSecretBackup(): Promise { + throw new Error("Method not implemented"); + } + + listPropertiesOfSecretVersions(): PagedAsyncIterableIterator< + SecretProperties + > { + throw new Error("Method not implemented"); + } + + listPropertiesOfSecrets(): PagedAsyncIterableIterator { + throw new Error("Method not implemented"); + } + + listDeletedSecrets(): PagedAsyncIterableIterator { + throw new Error("Method not implemented"); + } +} diff --git a/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/unit/api-surface.test.ts b/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/unit/api-surface.test.ts new file mode 100644 index 00000000000..a44efd79231 --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/src/test/typescript/unit/api-surface.test.ts @@ -0,0 +1,7 @@ +import test, { Test } from "tape"; +import * as publicApi from "../../../main/typescript/public-api"; + +test("Library can be loaded", (assert: Test) => { + assert.ok(publicApi); + assert.end(); +}); diff --git a/packages/cactus-plugin-keychain-azure-kv/tsconfig.json b/packages/cactus-plugin-keychain-azure-kv/tsconfig.json new file mode 100644 index 00000000000..d90c929ef9b --- /dev/null +++ b/packages/cactus-plugin-keychain-azure-kv/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist/lib/", /* Redirect output structure to the directory. */ + "declarationDir": "dist/types", + }, + "include": [ + "./src" + ] +} \ No newline at end of file diff --git a/packages/cactus-plugin-keychain-vault/package.json b/packages/cactus-plugin-keychain-vault/package.json index 4b8e3a8bc38..b04162cd20d 100644 --- a/packages/cactus-plugin-keychain-vault/package.json +++ b/packages/cactus-plugin-keychain-vault/package.json @@ -84,7 +84,6 @@ "devDependencies": { "@hyperledger/cactus-test-tooling": "0.6.0", "@types/express": "4.17.8", - "@types/express-serve-static-core": "4.17.17", "@types/request": "2.48.5", "internal-ip": "6.2.0", "openapi-types": "7.2.2" diff --git a/webpack.prod.node.js b/webpack.prod.node.js index 32e7b2d0561..a1e8b896900 100644 --- a/webpack.prod.node.js +++ b/webpack.prod.node.js @@ -72,5 +72,6 @@ module.exports = { npm: "npm", "fabric-client": "fabric-client", "fabric-ca-client": "fabric-ca-client", + "@azure/identity": "@azure/identity", }, };