diff options
author | Gregory Anders <8965202+gpanders@users.noreply.github.com> | 2022-02-15 13:08:40 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-15 13:08:40 -0700 |
commit | 238b944e58d12a28245be996e69bf36a2a452a90 (patch) | |
tree | 363c9b25822888223c4b5f703c615a0a99b9b419 | |
parent | 3449405f38961ac297638ced6377d75cfcb610ca (diff) | |
download | rneovim-238b944e58d12a28245be996e69bf36a2a452a90.tar.gz rneovim-238b944e58d12a28245be996e69bf36a2a452a90.tar.bz2 rneovim-238b944e58d12a28245be996e69bf36a2a452a90.zip |
fix(api): validate command names in nvim_add_user_command (#17406)
This uses the same validation used when defining commands with
`:command`.
-rw-r--r-- | src/nvim/api/private/helpers.c | 5 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 33 | ||||
-rw-r--r-- | test/functional/api/command_spec.lua | 22 |
3 files changed, 50 insertions, 10 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index ddcfff0097..2b107a3f27 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1384,6 +1384,11 @@ void add_user_command(String name, Object command, Dict(user_command) *opts, int LuaRef luaref = LUA_NOREF; LuaRef compl_luaref = LUA_NOREF; + if (!uc_validate_name(name.data)) { + api_set_error(err, kErrorTypeValidation, "Invalid command name"); + goto err; + } + if (mb_islower(name.data[0])) { api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter"); goto err; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 4dba0b97ed..87f8865133 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5164,6 +5164,24 @@ char_u *get_command_name(expand_T *xp, int idx) return cmdnames[idx].cmd_name; } +/// Check for a valid user command name +/// +/// If the given {name} is valid, then a pointer to the end of the valid name is returned. +/// Otherwise, returns NULL. +char *uc_validate_name(char *name) +{ + if (ASCII_ISALPHA(*name)) { + while (ASCII_ISALNUM(*name)) { + name++; + } + } + if (!ends_excmd(*name) && !ascii_iswhite(*name)) { + return NULL; + } + + return name; +} + int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def, int flags, int compl, char_u *compl_arg, LuaRef compl_luaref, cmd_addr_T addr_type, LuaRef luaref, bool force) @@ -5679,23 +5697,18 @@ static void ex_command(exarg_T *eap) // Get the name (if any) and skip to the following argument. name = p; - if (ASCII_ISALPHA(*p)) { - while (ASCII_ISALNUM(*p)) { - p++; - } - } - if (!ends_excmd(*p) && !ascii_iswhite(*p)) { + end = (char_u *)uc_validate_name((char *)name); + if (!end) { emsg(_("E182: Invalid command name")); return; } - end = p; - name_len = (int)(end - name); + name_len = (size_t)(end - name); // If there is nothing after the name, and no attributes were specified, // we are listing commands p = skipwhite(end); if (!has_attr && ends_excmd(*p)) { - uc_list(name, end - name); + uc_list(name, name_len); } else if (!ASCII_ISUPPER(*name)) { emsg(_("E183: User defined commands must start with an uppercase letter")); } else if (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0) { @@ -5703,7 +5716,7 @@ static void ex_command(exarg_T *eap) } else if (compl > 0 && (argt & EX_EXTRA) == 0) { emsg(_(e_complete_used_without_nargs)); } else { - uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, LUA_NOREF, + uc_add_command(name, name_len, p, argt, def, flags, compl, compl_arg, LUA_NOREF, addr_type_arg, LUA_NOREF, eap->forceit); } } diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index d64d324a88..de22c9078c 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -180,6 +180,28 @@ describe('nvim_add_user_command', function() feed('<C-U>Test b<Tab>') eq('Test bbb', funcs.getcmdline()) end) + + it('does not allow invalid command names', function() + matches("'name' must begin with an uppercase letter", pcall_err(exec_lua, [[ + vim.api.nvim_add_user_command('test', 'echo "hi"', {}) + ]])) + + matches('Invalid command name', pcall_err(exec_lua, [[ + vim.api.nvim_add_user_command('t@', 'echo "hi"', {}) + ]])) + + matches('Invalid command name', pcall_err(exec_lua, [[ + vim.api.nvim_add_user_command('T@st', 'echo "hi"', {}) + ]])) + + matches('Invalid command name', pcall_err(exec_lua, [[ + vim.api.nvim_add_user_command('Test!', 'echo "hi"', {}) + ]])) + + matches('Invalid command name', pcall_err(exec_lua, [[ + vim.api.nvim_add_user_command('💩', 'echo "hi"', {}) + ]])) + end) end) describe('nvim_del_user_command', function() |