]> git.lizzy.rs Git - minetest.git/blob - builtin/chatcommands.lua
Don't allow /granting unknown privileges
[minetest.git] / builtin / chatcommands.lua
1 -- Minetest: builtin/chatcommands.lua
2
3 --
4 -- Chat commands
5 --
6
7 minetest.chatcommands = {}
8 function minetest.register_chatcommand(cmd, def)
9         def = def or {}
10         def.params = def.params or ""
11         def.description = def.description or ""
12         def.privs = def.privs or {}
13         minetest.chatcommands[cmd] = def
14 end
15
16 -- Register the help command
17 minetest.register_chatcommand("help", {
18         privs = {},
19         params = "(nothing)/all/privs/<cmd>",
20         description = "Get help for commands or list privileges",
21         func = function(name, param)
22                 local format_help_line = function(cmd, def)
23                         local msg = "/"..cmd
24                         if def.params and def.params ~= "" then msg = msg .. " " .. def.params end
25                         if def.description and def.description ~= "" then msg = msg .. ": " .. def.description end
26                         return msg
27                 end
28                 if param == "" then
29                         local msg = ""
30                         cmds = {}
31                         for cmd, def in pairs(minetest.chatcommands) do
32                                 if minetest.check_player_privs(name, def.privs) then
33                                         table.insert(cmds, cmd)
34                                 end
35                         end
36                         minetest.chat_send_player(name, "Available commands: "..table.concat(cmds, " "))
37                         minetest.chat_send_player(name, "Use '/help <cmd>' to get more information, or '/help all' to list everything.")
38                 elseif param == "all" then
39                         minetest.chat_send_player(name, "Available commands:")
40                         for cmd, def in pairs(minetest.chatcommands) do
41                                 if minetest.check_player_privs(name, def.privs) then
42                                         minetest.chat_send_player(name, format_help_line(cmd, def))
43                                 end
44                         end
45                 elseif param == "privs" then
46                         minetest.chat_send_player(name, "Available privileges:")
47                         for priv, def in pairs(minetest.registered_privileges) do
48                                 minetest.chat_send_player(name, priv..": "..def.description)
49                         end
50                 else
51                         local cmd = param
52                         def = minetest.chatcommands[cmd]
53                         if not def then
54                                 minetest.chat_send_player(name, "Command not available: "..cmd)
55                         else
56                                 minetest.chat_send_player(name, format_help_line(cmd, def))
57                         end
58                 end
59         end,
60 })
61
62 -- Register C++ commands without functions
63 minetest.register_chatcommand("me", {params = nil, description = "chat action (eg. /me orders a pizza)"})
64 minetest.register_chatcommand("status", {description = "print server status line"})
65 minetest.register_chatcommand("shutdown", {params = "", description = "shutdown server", privs = {server=true}})
66 minetest.register_chatcommand("setting", {params = "<name> = <value>", description = "set line in configuration file", privs = {server=true}})
67 minetest.register_chatcommand("clearobjects", {params = "", description = "clear all objects in world", privs = {server=true}})
68 minetest.register_chatcommand("time", {params = "<0...24000>", description = "set time of day", privs = {settime=true}})
69 minetest.register_chatcommand("ban", {params = "<name>", description = "ban IP of player", privs = {ban=true}})
70 minetest.register_chatcommand("unban", {params = "<name/ip>", description = "remove IP ban", privs = {ban=true}})
71
72 -- Register some other commands
73 minetest.register_chatcommand("privs", {
74         params = "<name>",
75         description = "print out privileges of player",
76         func = function(name, param)
77                 if param == "" then
78                         param = name
79                 else
80                         if not minetest.check_player_privs(name, {privs=true}) then
81                                 minetest.chat_send_player(name, "Privileges of "..param.." are hidden from you.")
82                         end
83                 end
84                 minetest.chat_send_player(name, "Privileges of "..param..": "..minetest.privs_to_string(minetest.get_player_privs(param), ' '))
85         end,
86 })
87 minetest.register_chatcommand("grant", {
88         params = "<name> <privilege>|all",
89         description = "Give privilege to player",
90         privs = {privs=true},
91         func = function(name, param)
92                 local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
93                 if not grantname or not grantprivstr then
94                         minetest.chat_send_player(name, "Invalid parameters (see /help grant)")
95                         return
96                 end
97                 local grantprivs = minetest.string_to_privs(grantprivstr)
98                 if grantprivstr == "all" then
99                         grantprivs = minetest.registered_privileges
100                 end
101                 local privs = minetest.get_player_privs(grantname)
102                 local privs_known = true
103                 for priv, _ in pairs(grantprivs) do
104                         if not minetest.registered_privileges[priv] then
105                                 minetest.chat_send_player(name, "Unknown privilege: "..priv)
106                                 privs_known = false
107                         end
108                         privs[priv] = true
109                 end
110                 if not privs_known then
111                         return
112                 end
113                 minetest.set_player_privs(grantname, privs)
114                 minetest.chat_send_player(name, "Privileges of "..grantname..": "..minetest.privs_to_string(minetest.get_player_privs(grantname), ' '))
115                 if grantname ~= name then
116                         minetest.chat_send_player(grantname, name.." granted you privileges: "..minetest.privs_to_string(grantprivs, ' '))
117                 end
118         end,
119 })
120 minetest.register_chatcommand("revoke", {
121         params = "<name> <privilege>|all",
122         description = "Remove privilege from player",
123         privs = {privs=true},
124         func = function(name, param)
125                 local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
126                 if not revokename or not revokeprivstr then
127                         minetest.chat_send_player(name, "Invalid parameters (see /help revoke)")
128                         return
129                 end
130                 local revokeprivs = minetest.string_to_privs(revokeprivstr)
131                 local privs = minetest.get_player_privs(revokename)
132                 if revokeprivstr == "all" then
133                         privs = {}
134                 else
135                         for priv, _ in pairs(revokeprivs) do
136                                 privs[priv] = nil
137                         end
138                 end
139                 minetest.set_player_privs(revokename, privs)
140                 minetest.chat_send_player(name, "Privileges of "..revokename..": "..minetest.privs_to_string(minetest.get_player_privs(revokename), ' '))
141                 if revokename ~= name then
142                         minetest.chat_send_player(revokename, name.." revoked privileges from you: "..minetest.privs_to_string(revokeprivs, ' '))
143                 end
144         end,
145 })
146 minetest.register_chatcommand("setpassword", {
147         params = "<name> <password>",
148         description = "set given password",
149         privs = {password=true},
150         func = function(name, param)
151                 if param == "" then
152                         minetest.chat_send_player(name, "Password field required")
153                         return
154                 end
155                 minetest.set_player_password(name, param)
156                 minetest.chat_send_player(name, "Password set")
157         end,
158 })
159 minetest.register_chatcommand("clearpassword", {
160         params = "<name>",
161         description = "set empty password",
162         privs = {password=true},
163         func = function(name, param)
164                 minetest.set_player_password(name, '')
165                 minetest.chat_send_player(name, "Password cleared")
166         end,
167 })
168
169 minetest.register_chatcommand("auth_reload", {
170         params = "",
171         description = "reload authentication data",
172         privs = {server=true},
173         func = function(name, param)
174                 local done = minetest.auth_reload()
175                 if done then
176                         minetest.chat_send_player(name, "Done.")
177                 else
178                         minetest.chat_send_player(name, "Failed.")
179                 end
180         end,
181 })
182
183 minetest.register_chatcommand("teleport", {
184         params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
185         description = "teleport to given position",
186         privs = {teleport=true},
187         func = function(name, param)
188                 -- Returns (pos, true) if found, otherwise (pos, false)
189                 local function find_free_position_near(pos)
190                         local tries = {
191                                 {x=1,y=0,z=0},
192                                 {x=-1,y=0,z=0},
193                                 {x=0,y=0,z=1},
194                                 {x=0,y=0,z=-1},
195                         }
196                         for _, d in ipairs(tries) do
197                                 local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z}
198                                 local n = minetest.env:get_node(p)
199                                 if not minetest.registered_nodes[n.name].walkable then
200                                         return p, true
201                                 end
202                         end
203                         return pos, false
204                 end
205
206                 local teleportee = nil
207                 local p = {}
208                 p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
209                 teleportee = minetest.env:get_player_by_name(name)
210                 if teleportee and p.x and p.y and p.z then
211                         minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")")
212                         teleportee:setpos(p)
213                         return
214                 end
215                 
216                 local teleportee = nil
217                 local p = nil
218                 local target_name = nil
219                 target_name = string.match(param, "^([^ ]+)$")
220                 teleportee = minetest.env:get_player_by_name(name)
221                 if target_name then
222                         local target = minetest.env:get_player_by_name(target_name)
223                         if target then
224                                 p = target:getpos()
225                         end
226                 end
227                 if teleportee and p then
228                         p = find_free_position_near(p)
229                         minetest.chat_send_player(name, "Teleporting to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
230                         teleportee:setpos(p)
231                         return
232                 end
233                 
234                 if minetest.check_player_privs(name, {bring=true}) then
235                         local teleportee = nil
236                         local p = {}
237                         local teleportee_name = nil
238                         teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
239                         if teleportee_name then
240                                 teleportee = minetest.env:get_player_by_name(teleportee_name)
241                         end
242                         if teleportee and p.x and p.y and p.z then
243                                 minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to ("..p.x..", "..p.y..", "..p.z..")")
244                                 teleportee:setpos(p)
245                                 return
246                         end
247                         
248                         local teleportee = nil
249                         local p = nil
250                         local teleportee_name = nil
251                         local target_name = nil
252                         teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$")
253                         if teleportee_name then
254                                 teleportee = minetest.env:get_player_by_name(teleportee_name)
255                         end
256                         if target_name then
257                                 local target = minetest.env:get_player_by_name(target_name)
258                                 if target then
259                                         p = target:getpos()
260                                 end
261                         end
262                         if teleportee and p then
263                                 p = find_free_position_near(p)
264                                 minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
265                                 teleportee:setpos(p)
266                                 return
267                         end
268                 end
269
270                 minetest.chat_send_player(name, "Invalid parameters (\""..param.."\") or player not found (see /help teleport)")
271                 return
272         end,
273 })
274
275 --
276 -- Builtin chat handler
277 --
278
279 minetest.register_on_chat_message(function(name, message)
280         local cmd, param = string.match(message, "/([^ ]+) *(.*)")
281         if not param then
282                 param = ""
283         end
284         local cmd_def = minetest.chatcommands[cmd]
285         if cmd_def then
286                 if not cmd_def.func then
287                         -- This is a C++ command
288                         return false
289                 else
290                         local has_privs, missing_privs = minetest.check_player_privs(name, cmd_def.privs)
291                         if has_privs then
292                                 cmd_def.func(name, param)
293                         else
294                                 minetest.chat_send_player(name, "You don't have permission to run this command (missing privileges: "..table.concat(missing_privs, ", ")..")")
295                         end
296                         return true -- handled chat message
297                 end
298         end
299         return false
300 end)
301
302