Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel ACLs #79

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 37 additions & 130 deletions chatcommands.lua
Original file line number Diff line number Diff line change
@@ -1,51 +1,39 @@
local channel_created_string = "|#${channel_name}| Channel created"
local channel_updated_string = "|#${channel_name}| Channel updated"
local channel_invitation_string = "|#${channel_name}| Channel invite from (${from_player}), "
.. "to join the channel, do /jc ${channel_name},${channel_password} after "
.. "which you can send messages to the channel via #${channel_name}: message"
local channel_invited_string = "|#${channel_name}| Invite sent to ${to_player}"
local channel_deleted_string = "|#${channel_name}| Channel deleted"
local channel_left_string = "|#${channel_name}| Left channel"
local channel_already_deleted_string = "|#${channel_name}| Channel seems to have already "
.. "been deleted, will unregister channel from your list of channels"
local channel_created_string = "|#${channel}| Channel created"
local channel_updated_string = "|#${channel}| Channel updated"
local channel_deleted_string = "|#${channel}| Channel deleted"
local channel_left_string = "|#${channel}| Left channel"
local nochannel_string = "|#${channel}| Channel does not exist, will unregister channel from your list of channels"

local leave_channel_sound = "beerchat_chirp" -- Sound when you leave a channel
local channel_invite_sound = "beerchat_chirp" -- Sound when sending/ receiving an invite to a channel
local leave_channel_sound = "beerchat_chirp" -- Sound when you leave a channel

local create_channel = {
params = "<Channel Name>,<Password (optional)>,<Color (optional, default is #ffffff)>",
description = "Create or edit a channel named <Channel Name> with optional <Password> and "
.. "hexadecimal <Color> starting with # (e.g. #00ff00 for green). Use comma's "
.. "to separate the arguments, e.g. "
.. "/cc my secret channel,#0000ff for a blue colored my secret channel without password",
params = "<Channel Name>[[,<Password>],<Color>]",
description = "Create or edit a channel named <Channel Name> with optional <Password> and hexadecimal <Color> "
.. "starting with # (e.g. #00ff00 for green, defaults to #ffffff). Use commas to separate the arguments, e.g. "
.. "/cc my-secret-channel,#0000ff for a blue colored my-secret-channel without password",
func = function(lname, param)
local lowner = lname

if not param or param == "" then
return false, "ERROR: Invalid number of arguments. Please supply the channel name as a minimum."
end

local str = string.split(param:gsub("^#",""), ",")
local str = param:gsub("^#",""):split(",")
if #str > 3 then
return false, "ERROR: Invalid number of arguments. 4 parameters passed, "
.. "maximum of 3 allowed: <Channel Name>,<Password>,<Color>"
end

local lchannel_name = string.trim(str[1] or ""):gsub("%s", "-")
local lchannel_name = (str[1] or ""):trim():gsub("%s", "-")
if lchannel_name == "" then
return false, "ERROR: You must supply a channel name"
end

if lchannel_name == beerchat.main_channel_name then
elseif lchannel_name == beerchat.main_channel_name then
return false, "ERROR: You cannot use channel name \"" .. beerchat.main_channel_name .. "\""
end

local msg = channel_created_string
if beerchat.channels[lchannel_name] then
local cowner = beerchat.channels[lchannel_name].owner
if not cowner or cowner == "" or cowner ~= lowner then
return false, "ERROR: Channel " .. lchannel_name
.. " already exists, owned by player " .. beerchat.channels[lchannel_name].owner
if not cowner or cowner == "" or cowner ~= lname then
return false, "ERROR: Channel " .. lchannel_name .. " already exists, owned by player " .. cowner
end
msg = channel_updated_string
end
Expand All @@ -66,13 +54,12 @@ local create_channel = {
lcolor = string.lower(str[3])
end

beerchat.channels[lchannel_name] = { owner = lowner, name = lchannel_name,
password = lpassword, color = lcolor }
beerchat.channels[lchannel_name] = { owner = lname, name = lchannel_name, password = lpassword, color = lcolor }
beerchat.mod_storage:set_string("channels", minetest.write_json(beerchat.channels))

beerchat.add_player_channel(lowner, lchannel_name, "owner")
beerchat.sound_play(lowner, beerchat.channel_management_sound)
minetest.chat_send_player(lowner, beerchat.format_message(msg, { channel_name = lchannel_name }))
beerchat.add_player_channel(lname, lchannel_name, "owner")
beerchat.sound_play(lname, beerchat.channel_management_sound)
minetest.chat_send_player(lname, beerchat.format_message(msg, { channel = lchannel_name }))
return true
end
}
Expand Down Expand Up @@ -106,7 +93,7 @@ local delete_channel = {

beerchat.sound_play(name, beerchat.channel_management_sound)
minetest.chat_send_player(name, beerchat.format_message(
channel_deleted_string, { channel_name = delete.channel, color = color }
channel_deleted_string, { channel = delete.channel, color = color }
))
return true
end
Expand All @@ -127,47 +114,30 @@ local my_channels = {
beerchat.sound_play(name, beerchat.channel_management_sound)
minetest.chat_send_player(name, dump2(beerchat.channels[param]))
else
minetest.chat_send_player(name, "ERROR: Channel not in your channel list")
return false
return false, "ERROR: Channel is not in your channel list."
end
end
return true
end
}

local join_channel = {
params = "<Channel Name>,<Password (only mandatory if channel was created using "
.. "a password)>",
params = "<Channel Name>",
description = "Join channel named <Channel Name>. After joining you will see messages "
.. "sent to that channel (in addition to the other channels you have joined)",
func = function(name, param)
if not param or param == "" then
return false, "ERROR: Invalid number of arguments. Please supply the channel "
.. "name as a minimum."
end

local str = string.split(param:gsub("^#",""), ",")
local channel_name = str[1] or "<empty>"

if not beerchat.channels[channel_name] then
return false, "ERROR: Channel " .. channel_name .. " does not exist."
end

if beerchat.playersChannels[name] and beerchat.playersChannels[name][channel_name] then
return false, "ERROR: You already joined "..channel_name..", no need to rejoin"
.. "sent to that channel in addition to the other channels you have joined.",
func = function(name, channel)
if not channel or channel == "" then
return false, "ERROR: Invalid arguments. Please supply the channel name."
end

if beerchat.channels[channel_name].password and beerchat.channels[channel_name].password ~= "" then
if #str == 1 then
return false, "ERROR: This channel requires that you supply a password. "
.. "Supply it in the following format: /jc my channel,password01"
end
if str[2] ~= beerchat.channels[channel_name].password then
return false, "ERROR: Invalid password."
end
channel = channel:match("^#?(%S+)")
if not channel or not beerchat.channels[channel] then
return false, "ERROR: Channel " .. (channel or "<empty>") .. " does not exist."
elseif beerchat.playersChannels[name] and beerchat.playersChannels[name][channel] then
return false, "ERROR: You already joined " .. channel .. ", no need to rejoin"
end

return beerchat.join_channel(name, channel_name)
beerchat.join_channel(name, channel)
end
}

Expand All @@ -178,84 +148,23 @@ local leave_channel = {
.. "NOTE: You can also leave the main channel",
func = function(name, channel)
if not channel or channel == "" then
return false, "ERROR: Invalid number of arguments. Please supply the channel name."
return false, "ERROR: Invalid arguments. Please supply the channel name."
end

channel = channel:match("^#?(%S+)")
if not beerchat.playersChannels[name][channel] then
return false, "ERROR: You are not member of " .. channel .. ", no need to leave."
end

if not beerchat.execute_callbacks('before_leave', name, channel) then
elseif not beerchat.execute_callbacks('before_leave', name, channel) then
return false
end

beerchat.remove_player_channel(name, channel)

beerchat.sound_play(name, leave_channel_sound)
if not beerchat.channels[channel] then
minetest.chat_send_player(name,
beerchat.format_message(channel_already_deleted_string,
{ channel_name = channel })
)
else
minetest.chat_send_player(name,
beerchat.format_message(channel_left_string,
{ channel_name = channel })
)
end
return true
end
}

local invite_channel = {
params = "<Channel Name>,<Player Name>",
description = "Invite player named <Player Name> to channel named <Channel Name>. "
.. "You must be the owner of the channel in order to invite others.",
func = function(name, param)
if not param or param == "" then
return false, "ERROR: Invalid number of arguments. Please supply the channel "
.. "name and the player name."
end

local channel_name, player_name = string.match(param, "#?(.*),(.*)")

if not channel_name or channel_name == "" then
return false, "ERROR: Channel name is empty."
end

if not player_name or player_name == "" then
return false, "ERROR: Player name not supplied or empty."
end

if not beerchat.channels[channel_name] then
return false, "ERROR: Channel " .. channel_name .. " does not exist."
end

if name ~= beerchat.channels[channel_name].owner then
return false, "ERROR: You are not the owner of channel " .. param .. "."
end

if not minetest.get_player_by_name(player_name) then
return false, "ERROR: " .. player_name .. " does not exist or is not online."
minetest.chat_send_player(name, beerchat.format_message(nochannel_string, { channel = channel }))
else
if not beerchat.execute_callbacks('before_invite', name, player_name, channel_name) then
return false
end
if not beerchat.has_player_muted_player(player_name, name) then
beerchat.sound_play(player_name, channel_invite_sound)
-- Sending the message
minetest.chat_send_player(
player_name,
beerchat.format_message(channel_invitation_string,
{ channel_name = channel_name, from_player = name })
)
end
beerchat.sound_play(name, channel_invite_sound)
minetest.chat_send_player(
name,
beerchat.format_message(channel_invited_string,
{ channel_name = channel_name, to_player = player_name })
)
minetest.chat_send_player(name, beerchat.format_message(channel_left_string, { channel = channel }))
end
return true
end
Expand All @@ -273,5 +182,3 @@ minetest.register_chatcommand("jc", join_channel)
minetest.register_chatcommand("join_channel", join_channel)
minetest.register_chatcommand("lc", leave_channel)
minetest.register_chatcommand("leave_channel", leave_channel)
minetest.register_chatcommand("ic", invite_channel)
minetest.register_chatcommand("invite_channel", invite_channel)
11 changes: 6 additions & 5 deletions common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ beerchat.fix_player_channel = function(name, notify)
beerchat.set_player_channel(name, beerchat.main_channel_name)
end

beerchat.join_channel = function(name, channel, set_default)
if not beerchat.execute_callbacks('before_join', name, channel) then
beerchat.join_channel = function(name, channel, data)
data = type(data) == "table" and data or { set_default = data }
data.channel = channel
if not beerchat.execute_callbacks('before_join', name, channel, data) then
return false
end
(set_default and beerchat.set_player_channel or beerchat.add_player_channel)(name, channel)
;(data.set_default and beerchat.set_player_channel or beerchat.add_player_channel)(name, data.channel)
beerchat.sound_play(name, "beerchat_chirp")
local msg = beerchat.format_message("|#${channel_name}| Joined channel", { channel_name = channel })
minetest.chat_send_player(name, msg)
minetest.chat_send_player(name, beerchat.format_message("|#${channel}| Joined channel", { channel = data.channel }))
return true
end

Expand Down
6 changes: 3 additions & 3 deletions format_message.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ beerchat.format_message = function(s, tab)
local owner
local password
local color = beerchat.default_channel_color
local channel_name = tab.channel_name or ""
local channel_name = tab.channel or ""

if beerchat.channels[channel_name] then
owner = beerchat.channels[channel_name].owner
Expand All @@ -36,9 +36,9 @@ beerchat.format_message = function(s, tab)
end

local params = {
channel_name = channel_name,
channel = channel_name,
channel_owner = owner,
channel_password = password,
password = password,
from_player = tab.from_player,
to_player = tab.to_player,
message = colorize_target_name(tab.message, tab.to_player),
Expand Down
2 changes: 1 addition & 1 deletion init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ beerchat = {
-- Sound when a message is sent to a channel
channel_message_sound = "beerchat_chime",

main_channel_message_string = "|#${channel_name}| <${from_player}> ${message}",
main_channel_message_string = "|#${channel}| <${from_player}> ${message}",

moderator_channel_name = minetest.settings:get("beerchat.moderator_channel_name"),

Expand Down
4 changes: 2 additions & 2 deletions message.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
-- player names at the end of the chat message, etc.
--
-- The following parameters are available and can be specified :
-- ${channel_name} name of the channel
-- ${channel} name of the channel
-- ${channel_owner} owner of the channel
-- ${channel_password} password to use when joining the channel, used e.g. for invites
-- ${password} password to use when joining the channel, used e.g. for invites
-- ${from_player} the player that is sending the message
-- ${to_player} player to which the message is sent, will contain multiple player names
-- e.g. when sending a PM to multiple players
Expand Down
61 changes: 61 additions & 0 deletions plugin/acl.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
--luacheck: no_unused_args

--
-- Load ACL core functionality and ACL modules
--

local srcdir = minetest.get_modpath("beerchat").."/plugin/acl"

local acls = dofile(srcdir .. "/acls.lua")(
minetest.deserialize(beerchat.mod_storage:get("acl.acls")),
function (data) beerchat.mod_storage:set_string("acl.acls", minetest.serialize(data)) end
)

local password_protected_join = dofile(srcdir .. "/password.lua")

loadfile(srcdir .. "/chatcommands.lua")(acls)

--
-- Access level / authorization checks for player actions
--

beerchat.register_callback('before_join', function(name, _, data)
return password_protected_join(name, data)
end)

beerchat.register_callback('before_join', function(name, _, data)
return acls:check_access(data.channel, name)
end)

beerchat.register_callback('after_joinplayer', function(player)
local name = player:get_player_name()
if name and beerchat.playersChannels[name] then
for channel in pairs(beerchat.playersChannels[name]) do
local success, message = acls:check_access(channel, name)
if success == false then
beerchat.remove_player_channel(name, channel)
minetest.chat_send_player(name, message)
end
end
end
end)

beerchat.register_callback('before_invite', function(name, data)
if data.role == "owner" or data.role == "manager" then
return acls:check_access(data.channel, name, "owner")
end
return acls:check_access(data.channel, name, "manager")
end)

beerchat.register_callback("before_send_on_channel", function(name, msg)
return acls:check_access(msg.channel, name, "write", "write")
end)

beerchat.register_callback('before_switch_chan', function(name, switch)
return acls:check_access(switch.to, name)
end)

beerchat.register_callback('on_forced_join', function(name, target, channel, from_channel)
-- INJECT EVERYTHING THAT IS REQUIRED TO HAVE FULL ACCESS TO CHANNEL SO THAT
-- PLAYERS WITH THE FORCE CAN MOVE ANYONE TO ANY CHANNEL, ALSO TO LOCKED CHANNELS.
end)
Loading
Loading