Add !fflags and !ftemplate

These allow for access control, and work pretty much exactly like they
do in atheme's ChanServ (the /cs flags and /cs template commands).

Also remove unused things from botconfig.py.example.
This commit is contained in:
skizzerz 2016-06-07 17:02:12 -05:00
parent a6ea55a8fe
commit 2151df4fef
5 changed files with 225 additions and 4 deletions

View File

@ -22,11 +22,7 @@ CMD_CHAR = "!"
SERVER_PASS = "{account}:{password}"
OWNERS = ("unaffiliated/wolfbot_admin1",) # The comma is required at the end if there is only one owner.
ADMINS = ("unaffiliated/wolfbot_admin2", "unaffiliated/wolfbot_test*")
OWNERS_ACCOUNTS = ("1owner_acc",)
ADMINS_ACCOUNTS = ("1admin_acc", "2admin_acc")
ALLOWED_NORMAL_MODE_COMMANDS = [] # Debug mode commands to be allowed in normal mode
OWNERS_ONLY_COMMANDS = [] # Commands that should only be allowed for owners, regardless of their original permissions

View File

@ -846,6 +846,19 @@
"fwarn_view_deny": "denied {0}.",
"fwarn_reason_required": "A public warning reason is required.",
"warn_unacked": "You have unacknowledged warnings and cannot join at this time. Use \"warn list\" to view them.",
"no_templates": "There are no access templates defined.",
"template_not_found": "There is no template named {0}.",
"template_set": "Set template {0} to flags +{1}.",
"template_deleted": "Removed template {0}. Any access entries using this template have also been deleted.",
"access_set_account": "Set access for account {0} to +{1}.",
"access_set_host": "Set access for host {0} to +{1}.",
"access_deleted_account": "Deleted access for account {0}.",
"access_deleted_host": "Deleted access for host {0}.",
"invalid_flag": "Invalid flag {0}. Valid flags are +{1}.",
"no_access_account": "Account {0} does not have any access.",
"access_account": "Account {0} has access +{1}.",
"no_access_host": "Host {0} does not have any access.",
"access_host": "Host {0} has access +{1}.",
"_": " vim: set sw=4 expandtab:"
}

View File

@ -168,6 +168,56 @@ def expire_stasis():
stasis_expires IS NOT NULL
AND stasis_expires <= datetime('now')""")
def get_template(name):
c = conn.cursor()
c.execute("SELECT id, flags FROM access_template WHERE name = ?", (name,))
row = c.fetchone()
if row is None:
return (None, set())
return (row[0], row[1])
def get_templates():
c = conn.cursor()
c.execute("SELECT name, flags FROM access_template ORDER BY name ASC")
tpls = []
for name, flags in c:
tpls.append((name, flags))
return tpls
def update_template(name, flags):
with conn:
tid, _ = get_template(name)
c = conn.cursor()
if tid is None:
c.execute("INSERT INTO access_template (name, flags) VALUES (?, ?)", (name, flags))
else:
c.execute("UPDATE access_template SET flags = ? WHERE id = ?", (flags, tid))
def delete_template(name):
with conn:
tid, _ = get_template(name)
if tid is not None:
c = conn.cursor()
c.execute("DELETE FROM access WHERE template = ?", (tid,))
c.execute("DELETE FROM template WHERE id = ?", (tid,))
def set_access(acc, hostmask, flags=None, tid=None):
peid, plid = _get_ids(acc, hostmask)
if peid is None:
return
with conn:
c = conn.cursor()
if flags is None and tid is None:
c.execute("DELETE FROM access WHERE person = ?", (peid,))
elif tid is not None:
c.execute("""INSERT OR REPLACE INTO access
(person, template, flags)
VALUES (?, ?, NULL)""", (peid, tid))
else:
c.execute("""INSERT OR REPLACE INTO access
(person, template, flags)
VALUES (?, NULL, ?)""", (peid, flags))
def toggle_simple(acc, hostmask):
_toggle_thing("simple", acc, hostmask)

View File

@ -319,6 +319,7 @@ DISABLED_ROLES = frozenset()
GIF_CHANCE = 1/50
FORTUNE_CHANCE = 1/25
ALL_FLAGS = frozenset("AaDdFjms")
RULES = (botconfig.CHANNEL + " channel rules: http://wolf.xnrand.com/rules")

View File

@ -8581,6 +8581,167 @@ def fwarn(cli, nick, chan, rest):
else:
reply(cli, nick, chan, messages["fwarn_added"].format(warn_id))
@cmd("ftemplate", "F", pm=True)
def ftemplate(cli, nick, chan, rest):
params = re.split(" +", rest)
if params[0] == "":
# display a list of all templates
tpls = db.get_templates()
if not tpls:
reply(cli, nick, chan, messages["no_templates"])
else:
tpls = ["{0} (+{1})".format(name, "".join(sorted(flags))) for name, flags in tpls]
reply(cli, nick, chan, var.break_long_message(tpls, ", "))
elif len(params) == 1:
reply(cli, nick, chan, messages["not_enough_parameters"])
else:
name = params[0].upper()
flags = params[1]
tid, cur_flags = db.get_template(name)
if flags[0] != "+" and flags[0] != "-":
# flags is a template name
tpl_name = flags.upper()
tpl_id, tpl_flags = db.get_template(tpl_name)
if tpl_id is None:
reply(cli, nick, chan, messages["template_not_found"].format(tpl_name))
return
tpl_flags = "".join(sorted(tpl_flags))
db.update_template(name, tpl_flags)
reply(cli, nick, chan, messages["template_set"].format(name, tpl_flags))
else:
adding = True
for flag in flags:
if flag == "+":
adding = True
continue
elif flag == "-":
adding = False
continue
elif flag == "*":
if adding:
cur_flags = cur_flags | (var.ALL_FLAGS - {"F"})
else:
cur_flags = set()
continue
elif flag not in var.ALL_FLAGS:
reply(cli, nick, chan, messages["invalid_flag"].format(flag, "".join(sorted(var.ALL_FLAGS))))
return
elif adding:
cur_flags.add(flag)
else:
cur_flags.discard(flag)
if cur_flags:
tpl_flags = "".join(sorted(cur_flags))
db.update_template(name, tpl_flags)
reply(cli, nick, chan, messages["template_set"].format(name, tpl_flags))
elif tid is None:
reply(cli, nick, chan, messages["template_not_found"].format(name))
else:
db.delete_template(name)
reply(cli, nick, chan, messages["template_deleted"].format(name))
# re-init var.FLAGS and var.FLAGS_ACCS since they may have changed
db.init_vars()
@cmd("fflags", flag="F", pm=True)
def fflags(cli, nick, chan, rest):
params = re.split(" +", rest)
if params[0] == "":
# display a list of all access
parts = []
for acc, flags in var.FLAGS_ACCS.items():
if not flags:
continue
if var.ACCOUNTS_ONLY:
parts.append("{0} (+{1})".format(acc, "".join(sorted(flags))))
else:
parts.append("{0} (Account) (+{1})".format(acc, "".join(sorted(flags))))
for hm, flags in var.FLAGS.items():
if not flags:
continue
if var.DISABLE_ACCOUNTS:
parts.append("{0} (+{1})".format(hm, "".join(sorted(flags))))
else:
parts.append("{0} (Host) (+{1})".format(hm, "".join(sorted(flags))))
if not parts:
reply(cli, nick, chan, messages["no_access"])
else:
reply(cli, nick, chan, var.break_long_message(parts, ", "))
elif len(params) == 1:
# display access for the given user
acc, hm = parse_warning_target(params[0])
if acc is not None:
if not var.FLAGS_ACCS[acc]:
msg = messages["no_access_account"].format(acc)
else:
msg = messages["access_account"].format(acc, "".join(sorted(var.FLAGS_ACCS[acc])))
elif hm is not None:
if not var.FLAGS[hm]:
msg = messages["no_access_host"].format(hm)
else:
msg = messages["access_host"].format(acc, "".join(sorted(var.FLAGS[hm])))
reply(cli, nick, chan, msg)
else:
acc, hm = parse_warning_target(params[0])
flags = params[1]
cur_flags = set(var.FLAGS_ACCS[acc] + var.FLAGS[hm])
if flags[0] != "+" and flags[0] != "-":
# flags is a template name
tpl_name = flags.upper()
tpl_id, tpl_flags = db.get_template(tpl_name)
if tpl_id is None:
reply(cli, nick, chan, messages["template_not_found"].format(tpl_name))
return
tpl_flags = "".join(sorted(tpl_flags))
db.set_access(acc, hm, tid=tpl_id)
if acc is not None:
reply(cli, nick, chan, messages["access_set_account"].format(acc, tpl_flags))
else:
reply(cli, nick, chan, messages["access_set_host"].format(hm, tpl_flags))
else:
adding = True
for flag in flags:
if flag == "+":
adding = True
continue
elif flag == "-":
adding = False
continue
elif flag == "*":
if adding:
cur_flags = cur_flags | (var.ALL_FLAGS - {"F"})
else:
cur_flags = set()
continue
elif flag not in var.ALL_FLAGS:
reply(cli, nick, chan, messages["invalid_flag"].format(flag, "".join(sorted(var.ALL_FLAGS))))
return
elif adding:
cur_flags.add(flag)
else:
cur_flags.discard(flag)
if cur_flags:
flags = "".join(sorted(cur_flags))
db.set_access(acc, hm, flags=flags)
if acc is not None:
reply(cli, nick, chan, messages["access_set_account"].format(acc, flags))
else:
reply(cli, nick, chan, messages["access_set_host"].format(hm, flags))
else:
db.set_access(acc, hm, flags=None)
if acc is not None:
reply(cli, nick, chan, messages["access_deleted_account"].format(acc))
else:
reply(cli, nick, chan, messages["access_deleted_host"].format(hm))
# re-init var.FLAGS and var.FLAGS_ACCS since they may have changed
db.init_vars()
@cmd("wait", "w", playing=True, phases=("join",))
def wait(cli, nick, chan, rest):
"""Increases the wait time until !start can be used."""