Skip to content

Commit

Permalink
NC | CLI | CLI errors handling when master key is invalid
Browse files Browse the repository at this point in the history
Signed-off-by: Romy <35330373+romayalon@users.noreply.github.com>
  • Loading branch information
romayalon committed May 30, 2024
1 parent 0c1ba1c commit f29eb7b
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 23 deletions.
8 changes: 5 additions & 3 deletions src/cmd/manage_nsfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,8 @@ async function fetch_account_data(action, user_input) {
if (action === ACTIONS.UPDATE || action === ACTIONS.DELETE) {
// @ts-ignore
data = _.omitBy(data, _.isUndefined);
data = await fetch_existing_account_data(action, data);
const decrypt_secret_key = action === ACTIONS.UPDATE;
data = await fetch_existing_account_data(action, data, decrypt_secret_key);
}

// override values
Expand Down Expand Up @@ -375,14 +376,14 @@ async function fetch_account_data(action, user_input) {
return data;
}

async function fetch_existing_account_data(action, target) {
async function fetch_existing_account_data(action, target, decrypt_secret_key) {
let source;
try {
const account_path = target.name ?
get_config_file_path(accounts_dir_path, target.name) :
get_symlink_config_file_path(access_keys_dir_path, target.access_keys[0].access_key);
source = await get_config_data(config_root_backend, account_path, true);
source.access_keys = await nc_mkm.decrypt_access_keys(source);
if (decrypt_secret_key) source.access_keys = await nc_mkm.decrypt_access_keys(source);
} catch (err) {
dbg.log1('NSFS Manage command: Could not find account', target, err);
if (err.code === 'ENOENT') {
Expand Down Expand Up @@ -536,6 +537,7 @@ async function get_account_status(data, show_secrets) {
if (config_data.access_keys) config_data.access_keys = await nc_mkm.decrypt_access_keys(config_data);
write_stdout_response(ManageCLIResponse.AccountStatus, config_data);
} catch (err) {
if (err.code !== 'ENOENT') throw err;
if (_.isUndefined(data.name)) {
throw_cli_error(ManageCLIError.NoSuchAccountAccessKey, data.access_keys[0].access_key.unwrap());
} else {
Expand Down
9 changes: 8 additions & 1 deletion src/manage_nsfs/manage_nsfs_cli_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ ManageCLIError.WhiteListIPUpdateFailed = Object.freeze({
http_code: 500,
});

ManageCLIError.InvalidMasterKey = Object.freeze({
code: 'InvalidMasterKey',
message: 'Master key manager had issues loading master key, can not decrypt/encrypt secrets.',
http_code: 500,
});

////////////////////////
//// ACCOUNT ERRORS ////
////////////////////////
Expand Down Expand Up @@ -404,7 +410,8 @@ ManageCLIError.FS_ERRORS_TO_MANAGE = Object.freeze({

ManageCLIError.RPC_ERROR_TO_MANAGE = Object.freeze({
INVALID_SCHEMA: ManageCLIError.InvalidSchema,
NO_SUCH_USER: ManageCLIError.InvalidAccountDistinguishedName
NO_SUCH_USER: ManageCLIError.InvalidAccountDistinguishedName,
INVALID_MASTER_KEY: ManageCLIError.InvalidMasterKey
});

const NSFS_CLI_ERROR_EVENT_MAP = {
Expand Down
45 changes: 30 additions & 15 deletions src/manage_nsfs/nc_master_key_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ const TYPE_EXEC = 'executable';
const ACTIVE_MASTER_KEY = 'active_master_key';
const EXEC_KEY_SUFFIX = 'master_keys';

///////////////////////////////
////// MASTER KEY ERRORS //////
///////////////////////////////

const INVALID_MASTER_KEY = 'INVALID_MASTER_KEY';

/**
* @typedef {{
* id: nb.ID,
Expand Down Expand Up @@ -68,7 +74,7 @@ class NCMasterKeysManager {
} else if (store_type === TYPE_EXEC) {
return this._init_from_exec();
}
throw new Error(`Invalid Master keys store type - ${store_type} - ${TYPE_EXEC}`);
throw new RpcError(INVALID_MASTER_KEY, `Invalid Master keys store type - ${store_type} - ${TYPE_EXEC}`);
}

/**
Expand All @@ -77,20 +83,21 @@ class NCMasterKeysManager {
* @returns {MasterKey}
*/
_set_keys(master_keys) {
if (!master_keys.active_master_key || !master_keys.master_keys_by_id) throw new RpcError('INVALID_MASTER_KEYS_FILE', 'Invalid master_keys.json file');
if (!master_keys.active_master_key || !master_keys.master_keys_by_id) throw new RpcError(INVALID_MASTER_KEY, 'Invalid master_keys.json');
for (const [master_key_id, master_key] of Object.entries(master_keys.master_keys_by_id)) {
try {
this.master_keys_by_id[master_key.id] = get_buffered_master_key(master_key);
if (master_key_id === master_keys.active_master_key) {
this.active_master_key = this.master_keys_by_id[master_key.id];
}
} catch (err) {
dbg.error('couldn\'t load master_keys.json file', err);
throw new RpcError('INVALID_MASTER_KEYS_FILE', 'Invalid master_keys.json file');
dbg.error('couldn\'t set master keys', err);
throw new RpcError(INVALID_MASTER_KEY, 'couldn\'t set master keys');
}
}

if (!this.active_master_key) {
throw new RpcError('INVALID_MASTER_KEYS_FILE', 'Invalid master_keys.json file, couldn\'t find active master key in master_keys_by_id');
throw new RpcError(INVALID_MASTER_KEY, 'Invalid master_keys.json, couldn\'t find active master key in master_keys_by_id');
}
dbg.log1('_set_keys: master_key_manager updated successfully!');
return this.active_master_key;
Expand All @@ -115,7 +122,7 @@ class NCMasterKeysManager {
} else if (store_type === TYPE_EXEC) {
return this._create_master_keys_exec(stringed_master_key);
}
throw new Error(`Invalid Master keys store type - ${store_type}`);
throw new RpcError(INVALID_MASTER_KEY, `Invalid Master keys store type - ${store_type}`);
}

////////////////
Expand All @@ -142,7 +149,7 @@ class NCMasterKeysManager {
if (err.code === 'ENOENT') {
dbg.warn('init_from_file: couldn\'t find master keys file', master_keys_path);
await this._create_master_key();
} else if (err.rpc_code === 'INVALID_MASTER_KEYS_FILE') {
} else if (err.rpc_code === INVALID_MASTER_KEY) {
dbg.error('init_from_file: master keys file is invalid', master_keys_path);
throw err;
} else {
Expand All @@ -152,7 +159,7 @@ class NCMasterKeysManager {
}
}
}
throw new Error('init_from_file exhausted');
throw new RpcError(INVALID_MASTER_KEY, 'init_from_file exhausted');
}


Expand Down Expand Up @@ -250,15 +257,15 @@ class NCMasterKeysManager {
dbg.warn(`init_from_exec: get master keys failed with status=${status}, creating a new master key`);
await this._create_master_key();
} else {
throw new Error(`init_from_exec: get master keys failed with status=${status}`);
throw new RpcError(INVALID_MASTER_KEY, `init_from_exec: get master keys failed with status=${status}`);
}
} catch (err) {
dbg.error(`init_from_exec: get master keys failed with error=${err} retries=${retries} max_retries=${config.MASTER_KEYS_EXEC_MAX_RETRIES}`);
retries += 1;
await P.delay(1000);
}
}
throw new Error('init_from_exec exhausted');
throw new RpcError(INVALID_MASTER_KEY, 'init_from_exec exhausted');
}

/**
Expand All @@ -279,8 +286,7 @@ class NCMasterKeysManager {
* @returns {string}
*/
encryptSync(secret_key, master_key_id = this.active_master_key?.id) {
if (!this.master_keys_by_id || !master_key_id) throw new Error('Invalid master key manager');
if (!this.master_keys_by_id[master_key_id]) throw new Error(`master key id is missing in master_keys_by_id`);
this._validate_master_key_manager(master_key_id);
const { cipher_key, cipher_iv, encryption_type } = this.master_keys_by_id[master_key_id];
const cipher = crypto.createCipheriv(encryption_type, cipher_key, cipher_iv);
const updated_value = cipher.update(Buffer.from(secret_key));
Expand All @@ -306,8 +312,7 @@ class NCMasterKeysManager {
* @returns {string}
*/
decryptSync(secret_key, master_key_id) {
if (!this.master_keys_by_id || !master_key_id) throw new Error('Invalid master key manager');
if (!this.master_keys_by_id[master_key_id]) throw new Error(`master key id is missing in master_keys_by_id`);
this._validate_master_key_manager(master_key_id);
const { cipher_key, cipher_iv, encryption_type } = this.master_keys_by_id[master_key_id];
const decipher = crypto.createDecipheriv(encryption_type, cipher_key, cipher_iv);
const decrypted_secret_key = decipher.update(Buffer.from(secret_key, 'base64')).toString();
Expand Down Expand Up @@ -341,6 +346,16 @@ class NCMasterKeysManager {
})));
return decrypted_access_keys;
}

/**
* _validate_master_key_manager validates the master keys before decrypt/encrypt
* @param {nb.ID} master_key_id
*/
_validate_master_key_manager(master_key_id) {
if (!this.master_keys_by_id) throw new RpcError(INVALID_MASTER_KEY, 'master_keys_by_id object is undefined');
if (!master_key_id) throw new RpcError(INVALID_MASTER_KEY, 'Master key id is undefined');
if (!this.master_keys_by_id[master_key_id]) throw new RpcError(INVALID_MASTER_KEY, 'master key id is missing in master_keys_by_id');
}
}

/**
Expand All @@ -357,7 +372,7 @@ function get_buffered_master_key(master_key) {
};
return buffered_master_key;
} catch (err) {
throw new RpcError('INVALID_MASTER_KEYS_FILE', 'Invalid master_keys.json file');
throw new RpcError(INVALID_MASTER_KEY, 'Could not convert master key strings to buffers');
}
}

Expand Down
Loading

0 comments on commit f29eb7b

Please sign in to comment.