fix(api): validate command names in nvim_add_user_command (#17406)

This uses the same validation used when defining commands with
`:command`.
This commit is contained in:
Gregory Anders 2022-02-15 13:08:40 -07:00 committed by GitHub
parent 3449405f38
commit 238b944e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 10 deletions

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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()