From 5a68b85ef86fa466c5ab94330f20edf892780a92 Mon Sep 17 00:00:00 2001 From: Nicolas Humbert Date: Wed, 4 Sep 2024 15:04:38 +0200 Subject: [PATCH] VLTCLT-51 Add client method to get or create encryption key id (cherry picked from commit a4b098e042188948a284f3d67b93e6ca879ffbbf) --- lib/IAMClient.js | 34 ++++++++ package.json | 2 +- tests/unit/getOrCreateEncryptionKeyId.js | 104 +++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 tests/unit/getOrCreateEncryptionKeyId.js diff --git a/lib/IAMClient.js b/lib/IAMClient.js index 0bf0b473..38d65418 100644 --- a/lib/IAMClient.js +++ b/lib/IAMClient.js @@ -977,6 +977,40 @@ class VaultClient { }, data, options.reqUid, null, options.logger); } + /** + * Retrieves the default encryption key id for the given account's canonical id, + * or creates one if it does not exist. + * + * @param {String} canonicalId - The canonical id of the account. + * @param {Object} options - Additional arguments. + * @param {string} options.reqUid - The request UID. + * @param {Function} callback + * - `error` (Error|null) - error object if the operation failed, otherwise null. + * - `result` (Object) - result object on success, containing raw response data and HTTP status code. + * @returns {void} + */ + getOrCreateEncryptionKeyId(canonicalId, options, callback) { + assert(canonicalId !== undefined, 'canonicalId need to be specified'); + assert(typeof canonicalId === 'string', 'canonicalId should be a string'); + assert(canonicalId !== '', 'canonicalId should not be empty string'); + const data = { + Action: 'GetOrCreateEncryptionKeyId', + canonicalId, + }; + this.request('POST', '/', false, (err, data, code) => { + if (err) { + return callback(err); + } + return callback(null, { + message: { + body: data, + code, + message: 'Encryption key retrieved or created', + }, + }); + }, data, options.reqUid, null); + } + healthcheck(reqUid, callback) { this.request('GET', '/_/healthcheck', false, callback, null, reqUid, null); diff --git a/package.json b/package.json index db3d05cb..f4abb7bb 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "engines": { "node": ">=16" }, - "version": "7.10.13", + "version": "7.10.13-1", "description": "Client library and binary for Vault, the user directory and key management service", "main": "index.js", "repository": "scality/vaultclient", diff --git a/tests/unit/getOrCreateEncryptionKeyId.js b/tests/unit/getOrCreateEncryptionKeyId.js new file mode 100644 index 00000000..b95000f1 --- /dev/null +++ b/tests/unit/getOrCreateEncryptionKeyId.js @@ -0,0 +1,104 @@ +'use strict'; // eslint-disable-line + +const assert = require('assert'); +const http = require('http'); +const IAMClient = require('../../lib/IAMClient'); + +const encryptionKeyId = '9c07eb04-d85a-48c4-8bc4-87f5ca2b9d5d'; +const canonicalId = '79a59dfb37cfe5b3b1b4e58734c14e02b6e9e081ca135a3b02e6b8cc993b6dc7'; + +const output = { + canonicalId, + encryptionKeyId, + action: 'created', +}; + +describe('getOrCreateEncryptionKeyId Test', () => { + let server; + let client; + const handler = (req, res) => { + res.writeHead(200); + return res.end(JSON.stringify(output)); + }; + + beforeEach('start server', done => { + server = http.createServer(handler).listen(8500, () => { + client = new IAMClient('127.0.0.1', 8500); + done(); + }).on('error', done); + }); + + afterEach('stop server', () => { server.close(); }); + + it('should retrieve getOrCreateEncryptionKeyId response', done => { + client.getOrCreateEncryptionKeyId(canonicalId, + { reqUid: '123' }, + (err, response) => { + assert(!err); + assert.deepStrictEqual(response.message.body, output); + done(); + }); + }); + + it('should throw error if canonical id is undefined', () => { + assert.throws( + () => client.getOrCreateEncryptionKeyId(undefined, { reqUid: '123' }, () => {}), err => { + assert(err instanceof assert.AssertionError); + assert.strictEqual(err.message, 'canonicalId need to be specified'); + return true; + }, + ); + }); + + it('should throw error if canonical id is not a string', () => { + assert.throws( + () => client.getOrCreateEncryptionKeyId(0, { reqUid: '123' }, () => {}), err => { + assert(err instanceof assert.AssertionError); + assert.strictEqual(err.message, 'canonicalId should be a string'); + return true; + }, + ); + }); + + it('should throw error if canonical id is an empty string', () => { + assert.throws( + () => client.getOrCreateEncryptionKeyId('', { reqUid: '123' }, () => {}), err => { + assert(err instanceof assert.AssertionError); + assert.strictEqual(err.message, 'canonicalId should not be empty string'); + return true; + }, + ); + }); +}); + +describe('getOrCreateEncryptionKeyId with server error', () => { + let server; + let client; + const erroredHandler = (req, res) => { + res.writeHead(200); + const serverError = '' + + 'ServiceFailureServer error: the request processing has ' + + 'failed because of an unknown error, exception or failure.' + + '3ac25e70c649bd4a6394:897ac94c0240b2a65f96'; + return res.end(serverError); + }; + + beforeEach('start server', done => { + server = http.createServer(erroredHandler).listen(8500, () => { + client = new IAMClient('127.0.0.1', 8500); + done(); + }).on('error', done); + }); + + afterEach('stop server', () => { server.close(); }); + + it('should return an error', done => { + client.getOrCreateEncryptionKeyId(canonicalId, + { reqUid: '123' }, + (err, response) => { + assert(!err); + assert(response.message.body.ErrorResponse); + done(); + }); + }); +});