Skip to content

Commit 9e9c365

Browse files
committed
NC | CLI | List accounts when decrypt access keys fails
Signed-off-by: shirady <[email protected]>
1 parent a3bc7dd commit 9e9c365

File tree

3 files changed

+100
-20
lines changed

3 files changed

+100
-20
lines changed

src/cmd/manage_nsfs.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ async function list_account_config_files(wide, show_secrets, filters = {}) {
597597
const options = {
598598
show_secrets: show_secrets || should_filter,
599599
decrypt_secret_key: show_secrets,
600+
// in case we have an error on secret_key decryption
601+
// we will return the encrypted_secret_key
602+
// and also decryption_err with the error we had
603+
return_encrypted_on_decryption_error: true,
600604
silent_if_missing: true
601605
};
602606

src/sdk/config_fs.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,13 @@ class ConfigFS {
231231
* and decrypts the account's secret_key if decrypt_secret_key is true
232232
* if silent_if_missing is true -
233233
* if the config file was deleted (encounter ENOENT error) - continue (returns undefined)
234+
* if decrypt_secret_key is true and the decryption failed with rpc error of INVALID_MASTER_KEY
235+
* and return_encrypted_on_decryption_error is true -
236+
* add a property decryption_err with the error we've got
237+
* if return_encrypted_on_decryption_error is false - throw the error (as it was before)
234238
* @param {string} config_file_path
235-
* @param {{show_secrets?: boolean, decrypt_secret_key?: boolean, silent_if_missing?: boolean}} [options]
239+
* @param {{show_secrets?: boolean, decrypt_secret_key?: boolean, silent_if_missing?: boolean,
240+
* return_encrypted_on_decryption_error?: boolean}} [options]
236241
* @returns {Promise<Object>}
237242
*/
238243
async get_identity_config_data(config_file_path, options = {}) {
@@ -241,7 +246,18 @@ class ConfigFS {
241246
const data = await this.get_config_data(config_file_path, options);
242247
if (!data && silent_if_missing) return;
243248
const config_data = _.omit(data, show_secrets ? [] : ['access_keys']);
244-
if (decrypt_secret_key) config_data.access_keys = await nc_mkm.decrypt_access_keys(config_data);
249+
if (decrypt_secret_key) {
250+
try {
251+
config_data.access_keys = await nc_mkm.decrypt_access_keys(config_data);
252+
} catch (err) {
253+
dbg.warn('get_identity_config_data: with config_file_path', config_file_path, 'got an error', err);
254+
if (err.rpc_code === 'INVALID_MASTER_KEY' && options.return_encrypted_on_decryption_error) {
255+
config_data.decryption_err = err.message;
256+
} else {
257+
throw err;
258+
}
259+
}
260+
}
245261
return config_data;
246262
} catch (err) {
247263
dbg.warn('get_identity_config_data: with config_file_path', config_file_path, 'got an error', err);

src/test/unit_tests/jest_tests/test_nc_account_invalid_mkm_integration.test.js

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,30 @@ const { exec_manage_cli, set_path_permissions_and_owner, TMP_PATH, set_nc_config
1111
const { TYPES, ACTIONS } = require('../../../manage_nsfs/manage_nsfs_constants');
1212
const ManageCLIError = require('../../../manage_nsfs/manage_nsfs_cli_errors').ManageCLIError;
1313
const ManageCLIResponse = require('../../../manage_nsfs/manage_nsfs_cli_responses').ManageCLIResponse;
14+
const { get_process_fs_context } = require('../../../util/native_fs_utils');
15+
const nb_native = require('../../../util/nb_native');
1416

1517
const tmp_fs_path = path.join(TMP_PATH, 'test_nc_nsfs_account_cli');
1618
const config_root = path.join(tmp_fs_path, 'config_root_account_mkm_integration');
1719
const root_path = path.join(tmp_fs_path, 'root_path_account_mkm_integration/');
18-
const defaults = {
19-
_id: 'account1',
20+
const defaults_account1 = {
2021
type: TYPES.ACCOUNT,
2122
name: 'account1',
22-
new_buckets_path: `${root_path}new_buckets_path_mkm_integration/`,
23-
uid: 999,
24-
gid: 999,
23+
new_buckets_path: `${root_path}new_buckets_path_mkm_integration_account1/`,
24+
uid: 1001,
25+
gid: 1001,
2526
access_key: 'GIGiFAnjaaE7OKD5N7hA',
2627
secret_key: 'U2AYaMpU3zRDcRFWmvzgQr9MoHIAsD+3oEXAMPLE',
2728
};
29+
const defaults_account2 = {
30+
type: TYPES.ACCOUNT,
31+
name: 'account2',
32+
new_buckets_path: `${root_path}new_buckets_path_mkm_integration_account2/`,
33+
uid: 1002,
34+
gid: 1002,
35+
access_key: 'HIHiFAnjaaE7OKD5N7hA',
36+
secret_key: 'U3BYaMpU3zRDcRFWmvzgQr9MoHIAsD+3oEXAMPLE',
37+
};
2838

2939
describe('manage nsfs cli account flow + fauly master key flow', () => {
3040
describe('cli account ops - master key is missing', () => {
@@ -49,13 +59,13 @@ describe('manage nsfs cli account flow + fauly master key flow', () => {
4959
});
5060

5161
it('cli account list', async () => {
52-
const { name } = defaults;
62+
const { name } = defaults_account1;
5363
const list_res = await list_account_flow();
5464
expect(list_res.response.reply[0].name).toBe(name);
5565
});
5666

5767
it('cli account status', async () => {
58-
const { name, uid, gid, new_buckets_path } = defaults;
68+
const { name, uid, gid, new_buckets_path } = defaults_account1;
5969
const status_res = await status_account();
6070
expect(status_res.response.reply.name).toBe(name);
6171
expect(status_res.response.reply.email).toBe(name);
@@ -99,7 +109,7 @@ describe('manage nsfs cli account flow + fauly master key flow', () => {
99109

100110
it('should fail | cli create account', async () => {
101111
try {
102-
await create_account({ ...defaults, name: 'account_corrupted_mk' });
112+
await create_account({ ...defaults_account1, name: 'account_corrupted_mk' });
103113
fail('should have failed with InvalidMasterKey');
104114
} catch (err) {
105115
expect(JSON.parse(err.stdout).error.code).toBe(ManageCLIError.InvalidMasterKey.code);
@@ -116,13 +126,13 @@ describe('manage nsfs cli account flow + fauly master key flow', () => {
116126
});
117127

118128
it('cli account list', async () => {
119-
const { name } = defaults;
129+
const { name } = defaults_account1;
120130
const list_res = await list_account_flow();
121131
expect(list_res.response.reply[0].name).toBe(name);
122132
});
123133

124134
it('cli account status', async () => {
125-
const { name, uid, gid, new_buckets_path } = defaults;
135+
const { name, uid, gid, new_buckets_path } = defaults_account1;
126136
const status_res = await status_account();
127137
expect(status_res.response.reply.name).toBe(name);
128138
expect(status_res.response.reply.email).toBe(name);
@@ -165,7 +175,7 @@ describe('manage nsfs cli account flow + fauly master key flow', () => {
165175

166176
it('should fail | cli create account', async () => {
167177
try {
168-
await create_account({ ...defaults, name: 'account_corrupted_mk' });
178+
await create_account({ ...defaults_account1, name: 'account_corrupted_mk' });
169179
fail('should have failed with InvalidMasterKey');
170180
} catch (err) {
171181
expect(JSON.parse(err.stdout).error.code).toBe(ManageCLIError.InvalidMasterKey.code);
@@ -182,13 +192,13 @@ describe('manage nsfs cli account flow + fauly master key flow', () => {
182192
});
183193

184194
it('cli account list', async () => {
185-
const { name } = defaults;
195+
const { name } = defaults_account1;
186196
const list_res = await list_account_flow();
187197
expect(list_res.response.reply[0].name).toBe(name);
188198
});
189199

190200
it('cli account status', async () => {
191-
const { name, uid, gid, new_buckets_path } = defaults;
201+
const { name, uid, gid, new_buckets_path } = defaults_account1;
192202
const status_res = await status_account();
193203
expect(status_res.response.reply.name).toBe(name);
194204
expect(status_res.response.reply.email).toBe(name);
@@ -211,6 +221,33 @@ describe('manage nsfs cli account flow + fauly master key flow', () => {
211221
expect(delete_res.response.code).toBe(ManageCLIResponse.AccountDeleted.code);
212222
});
213223
});
224+
225+
describe('cli with renamed master key file (invalid)', () => {
226+
const type = TYPES.ACCOUNT;
227+
228+
beforeEach(async () => {
229+
await setup_nc_system_and_first_account();
230+
await setup_account(defaults_account2);
231+
await master_key_file_rename(true);
232+
});
233+
234+
afterEach(async () => {
235+
await master_key_file_rename(false);
236+
await fs_utils.folder_delete(`${config_root}`);
237+
await fs_utils.folder_delete(`${root_path}`);
238+
});
239+
240+
it('cli list with wide and show_secrets flags (will show encrypted_secret_key and warning property)', async () => {
241+
const action = ACTIONS.LIST;
242+
const account_options = { config_root, wide: true, show_secrets: true };
243+
const res = await exec_manage_cli(type, action, account_options);
244+
const account_array_res = JSON.parse(res).response.reply;
245+
for (const account_res of account_array_res) {
246+
expect(account_res.access_keys[0].encrypted_secret_key).toBeDefined();
247+
expect(account_res.decryption_err).toBeDefined();
248+
}
249+
});
250+
});
214251
});
215252

216253
async function create_account(account_options) {
@@ -224,7 +261,7 @@ async function create_account(account_options) {
224261

225262
async function update_account() {
226263
const action = ACTIONS.UPDATE;
227-
const { type, name, new_buckets_path } = defaults;
264+
const { type, name, new_buckets_path } = defaults_account1;
228265
const new_uid = '1111';
229266
const account_options = { config_root, name, new_buckets_path, uid: new_uid };
230267
const res = await exec_manage_cli(type, action, account_options);
@@ -234,7 +271,7 @@ async function update_account() {
234271

235272
async function status_account(show_secrets) {
236273
const action = ACTIONS.STATUS;
237-
const { type, name } = defaults;
274+
const { type, name } = defaults_account1;
238275
const account_options = { config_root, name, show_secrets };
239276
const res = await exec_manage_cli(type, action, account_options);
240277
const parsed_res = JSON.parse(res);
@@ -243,7 +280,7 @@ async function status_account(show_secrets) {
243280

244281
async function list_account_flow() {
245282
const action = ACTIONS.LIST;
246-
const { type } = defaults;
283+
const { type } = defaults_account1;
247284
const account_options = { config_root };
248285
const res = await exec_manage_cli(type, action, account_options);
249286
const parsed_res = JSON.parse(res);
@@ -252,7 +289,7 @@ async function list_account_flow() {
252289

253290
async function delete_account_flow() {
254291
const action = ACTIONS.DELETE;
255-
const { type, name } = defaults;
292+
const { type, name } = defaults_account1;
256293
const account_options = { config_root, name };
257294
const res = await exec_manage_cli(type, action, account_options);
258295
const parsed_res = JSON.parse(res);
@@ -269,11 +306,34 @@ function fail(reason) {
269306
async function setup_nc_system_and_first_account() {
270307
await fs_utils.create_fresh_path(root_path);
271308
set_nc_config_dir_in_config(config_root);
309+
await setup_account(defaults_account1);
310+
}
311+
312+
async function setup_account(account_defaults) {
272313
const action = ACTIONS.ADD;
273-
const { type, name, new_buckets_path, uid, gid } = defaults;
314+
const { type, name, new_buckets_path, uid, gid } = account_defaults;
274315
const account_options = { config_root, name, new_buckets_path, uid, gid };
275316
await fs_utils.create_fresh_path(new_buckets_path);
276317
await fs_utils.file_must_exist(new_buckets_path);
277318
await set_path_permissions_and_owner(new_buckets_path, account_options, 0o700);
278319
await exec_manage_cli(type, action, account_options);
279320
}
321+
322+
323+
/**
324+
* master_key_file_rename will rename the master_keys.json file
325+
* to mock a situation where master_key_id points to a missing master key
326+
* use the to_rename_temp false to rename it back (after the test)
327+
* @param {boolean} to_rename_temp
328+
*/
329+
async function master_key_file_rename(to_rename_temp) {
330+
const default_fs_config = get_process_fs_context();
331+
const source_path = path.join(config_root, 'master_keys.json');
332+
const dest_path = path.join(config_root, 'temp_master_keys.json');
333+
// eliminate the master key file by renaming it
334+
if (to_rename_temp) {
335+
await nb_native().fs.rename(default_fs_config, source_path, dest_path);
336+
} else {
337+
await nb_native().fs.rename(default_fs_config, dest_path, source_path);
338+
}
339+
}

0 commit comments

Comments
 (0)