mirror of
https://github.com/inspircd/inspircd.git
synced 2025-03-09 10:39:02 -04:00
393 lines
12 KiB
C++
393 lines
12 KiB
C++
/*
|
|
* InspIRCd -- Internet Relay Chat Daemon
|
|
*
|
|
* Copyright (C) 2020-2024 Sadie Powell <sadie@witchery.services>
|
|
*
|
|
* This file is part of InspIRCd. InspIRCd is free software: you can
|
|
* redistribute it and/or modify it under the terms of the GNU General Public
|
|
* License as published by the Free Software Foundation, version 2.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#pragma once
|
|
|
|
#ifndef INSPIRCD_EXTBAN
|
|
# define INSPIRCD_EXTBAN
|
|
#endif
|
|
|
|
namespace ExtBan
|
|
{
|
|
class Acting;
|
|
class ActingBase;
|
|
class Base;
|
|
class EventListener;
|
|
class MatchingBase;
|
|
class Manager;
|
|
class ManagerRef;
|
|
|
|
/** All possible results for CompareResult. */
|
|
enum class Comparison
|
|
: uint8_t
|
|
{
|
|
/** The value passed to CompareResult is not an extban. */
|
|
NOT_AN_EXTBAN,
|
|
|
|
/** The extban is equivalent to the specified value. */
|
|
MATCH,
|
|
|
|
/** The extban is not equivalent to the specified value. */
|
|
NOT_MATCH,
|
|
};
|
|
|
|
/** All possible extban formats. */
|
|
enum class Format
|
|
: uint8_t
|
|
{
|
|
/** Do not perform any normalisation of extbans. */
|
|
ANY,
|
|
|
|
/** Normalise extbans to use their name (e.g. mute). */
|
|
NAME,
|
|
|
|
/** Normalise extbans to use their letter (e.g. m). */
|
|
LETTER,
|
|
};
|
|
|
|
/** All possible types of extban. */
|
|
enum class Type
|
|
: uint8_t
|
|
{
|
|
/** The extban takes action against specific behaviour (e.g. nokicks). */
|
|
ACTING,
|
|
|
|
/** The extban matches against a specific pattern (e.g. sslfp). */
|
|
MATCHING
|
|
};
|
|
|
|
/** The underlying type of an extban letter. */
|
|
using Letter = std::string::value_type;
|
|
|
|
/** Parses a ban entry and extracts an extban from it.
|
|
* @param banentry The ban entry to parse.
|
|
* @param name The parsed name of the extban.
|
|
* @param value The parsed value of the extban.
|
|
* @param inverted Whether the extban is inverted.
|
|
* @return True if an extban was extracted from the ban entry; otherwise, false.
|
|
*/
|
|
inline bool Parse(const std::string& banentry, std::string& name, std::string& value, bool& inverted);
|
|
}
|
|
|
|
/** Manager for the extban system. */
|
|
class ExtBan::Manager
|
|
: public DataProvider
|
|
{
|
|
protected:
|
|
/** Initializes an instance of the ExtBan::Base class.
|
|
* @param mod The module which created this instance.
|
|
*/
|
|
Manager(Module* mod)
|
|
: DataProvider(mod, "extbanmanager")
|
|
{
|
|
}
|
|
|
|
public:
|
|
/** A mapping of extban letters to their associated object. */
|
|
typedef std::unordered_map<ExtBan::Letter, ExtBan::Base*> LetterMap;
|
|
|
|
/** A mapping of extban names to their associated objects. */
|
|
typedef std::unordered_map<std::string, ExtBan::Base*, irc::insensitive, irc::StrHashComp> NameMap;
|
|
|
|
/** Registers an extban with the manager.
|
|
* @param extban The extban instance to register.
|
|
*/
|
|
virtual void AddExtBan(Base* extban) = 0;
|
|
|
|
/** Canonicalises a list mode entry if it is an extban.
|
|
* @param text The list mode entry to canonicalize.
|
|
* @return True if the text was a valid extban and was canonicalised. Otherwise, false.
|
|
*/
|
|
virtual bool Canonicalize(std::string& text) const = 0;
|
|
|
|
/** Compares an entry from this list with the specified value.
|
|
* @param lm The list mode which is the entry exists on.
|
|
* @param entry The list entry to compare against.
|
|
* @param value The value to compare to.
|
|
* @return MATCH if the entries match and NOT_MATCH if the entries do not match.
|
|
*/
|
|
virtual Comparison CompareEntry(const ListModeBase* lm, const std::string& entry, const std::string& value) const = 0;
|
|
|
|
/** Unregisters an extban from the manager.
|
|
* @param extban The extban instance to unregister.
|
|
*/
|
|
virtual void DelExtBan(Base* extban) = 0;
|
|
|
|
/** Retrieves the method used for normalising extbans. */
|
|
virtual Format GetFormat() const = 0;
|
|
|
|
/** Retrieves a mapping of extban letters to their associated object. */
|
|
virtual const LetterMap& GetLetterMap() const = 0;
|
|
|
|
/** Retrieves a mapping of extban names to their associated object. */
|
|
virtual const NameMap& GetNameMap() const = 0;
|
|
|
|
/** Retrieves the status of an acting extban.
|
|
* @param extban The extban to get the status of.
|
|
* @param user The user to match the extban against.
|
|
* @param channel The channel which the extban is set on.
|
|
* @return MOD_RES_ALLOW if the user is exempted, MOD_RES_DENY if the user is banned, or
|
|
* MOD_RES_PASSTHRU if the extban is not set.
|
|
*/
|
|
virtual ModResult GetStatus(ActingBase* extban, User* user, Channel* channel) const = 0;
|
|
|
|
/** Finds an extban by name or letter.
|
|
* @param xbname The name or letter of the extban to find.
|
|
*/
|
|
Base* Find(const std::string& xbname) const { return xbname.length() == 1 ? FindLetter(xbname[0]) : FindName(xbname); }
|
|
|
|
/** Finds an extban by letter.
|
|
* @param xbletter The letter of the extban to find.
|
|
*/
|
|
virtual Base* FindLetter(ExtBan::Letter xbletter) const = 0;
|
|
|
|
/** Finds an extban by name.
|
|
* @param xbname The name of the extban to find.
|
|
*/
|
|
virtual Base* FindName(const std::string& xbname) const = 0;
|
|
};
|
|
|
|
/** Dynamic reference to the extban manager class. */
|
|
class ExtBan::ManagerRef final
|
|
: public dynamic_reference_nocheck<ExtBan::Manager>
|
|
{
|
|
public:
|
|
ManagerRef(Module* mod)
|
|
: dynamic_reference_nocheck<ExtBan::Manager>(mod, "extbanmanager")
|
|
{
|
|
}
|
|
};
|
|
|
|
/** Base class for types of extban. */
|
|
class ExtBan::Base
|
|
: public ServiceProvider
|
|
, private dynamic_reference_base::CaptureHook
|
|
{
|
|
private:
|
|
/** Whether this ExtBan is currently enabled. */
|
|
bool active = false;
|
|
|
|
/** The character used in bans to signify this extban (e.g. z). */
|
|
ExtBan::Letter letter;
|
|
|
|
/** A reference to the extban manager. */
|
|
dynamic_reference<Manager> manager;
|
|
|
|
/** @copydoc dynamic_reference_base::CaptureHook::OnCapture */
|
|
void OnCapture() override
|
|
{
|
|
if (active)
|
|
SetActive(true);
|
|
}
|
|
|
|
protected:
|
|
/** Initializes an instance of the ExtBan::Base class.
|
|
* @param mod The module which created this instance.
|
|
* @param xbname The name used in bans to signify this extban.
|
|
* @param xbletter The character used in bans to signify this extban.
|
|
*/
|
|
Base(Module* mod, const std::string& xbname, ExtBan::Letter xbletter)
|
|
: ServiceProvider(mod, xbname, SERVICE_CUSTOM)
|
|
, letter(ServerInstance->Config->ConfValue("extbans")->getCharacter(xbname, xbletter, true))
|
|
, manager(mod, "extbanmanager")
|
|
{
|
|
}
|
|
|
|
~Base() override
|
|
{
|
|
SetActive(false);
|
|
}
|
|
|
|
public:
|
|
/** Canonicalises a value for this extban.
|
|
* @param text The value to canonicalize.
|
|
*/
|
|
virtual void Canonicalize(std::string& text) { }
|
|
|
|
/** Retrieves the character used in bans to signify this extban. */
|
|
ExtBan::Letter GetLetter() const { return letter; }
|
|
|
|
/** Retrieves a pointer to the extban manager. */
|
|
Manager* GetManager() { return manager ? *manager : nullptr; }
|
|
|
|
/** Retrieves the name used in bans to signify this extban. */
|
|
const std::string& GetName() const { return name; }
|
|
|
|
/** Retrieves the type of this extban. */
|
|
virtual Type GetType() const = 0;
|
|
|
|
/** Retrieves whether this extban is enabled. */
|
|
bool IsActive() const { return active; }
|
|
|
|
/** Determines whether the specified user matches this extban.
|
|
* @param user The user to match the text against.
|
|
* @param channel The channel which the extban is set on.
|
|
* @param text The string to match the user against.
|
|
* @return True if the user matches the extban; otherwise, false.
|
|
*/
|
|
virtual bool IsMatch(User* user, Channel* channel, const std::string& text) = 0;
|
|
|
|
/** @copydoc ServiceProvider::RegisterService */
|
|
void RegisterService() override
|
|
{
|
|
manager.SetCaptureHook(this);
|
|
SetActive(true);
|
|
}
|
|
|
|
/** Toggles the active status of this extban.
|
|
* @param Active Whether this extban is active or not.
|
|
*/
|
|
void SetActive(bool Active)
|
|
{
|
|
active = Active;
|
|
if (manager)
|
|
{
|
|
if (active)
|
|
manager->AddExtBan(this);
|
|
else
|
|
manager->DelExtBan(this);
|
|
}
|
|
}
|
|
};
|
|
|
|
/** Base class for acting extbans. */
|
|
class ExtBan::ActingBase
|
|
: public Base
|
|
{
|
|
protected:
|
|
/** Initializes an instance of the ExtBan::ActingBase class.
|
|
* @param mod The module which created this instance.
|
|
* @param xbname The name used in bans to signify this extban.
|
|
* @param xbletter The character used in bans to signify this extban.
|
|
*/
|
|
ActingBase(Module* mod, const std::string& xbname, ExtBan::Letter xbletter)
|
|
: Base(mod, xbname, xbletter)
|
|
{
|
|
}
|
|
|
|
public:
|
|
/** @copydoc ExtBan::Base::Canonicalize */
|
|
void Canonicalize(std::string& text) override
|
|
{
|
|
if (!GetManager() || !GetManager()->Canonicalize(text))
|
|
ModeParser::CleanMask(text);
|
|
}
|
|
|
|
/** @copydoc ExtBan::Base::GetType */
|
|
Type GetType() const override { return ExtBan::Type::ACTING; }
|
|
|
|
/** @copydoc ExtBan::Base::IsMatch */
|
|
bool IsMatch(User* user, Channel* channel, const std::string& text) override
|
|
{
|
|
return channel->CheckBan(user, text);
|
|
}
|
|
};
|
|
|
|
/** A simple acting extban that has no fields. */
|
|
class ExtBan::Acting
|
|
: public ActingBase
|
|
{
|
|
public:
|
|
/** Initializes an instance of the ExtBan::Acting class.
|
|
* @param mod The module which created this instance.
|
|
* @param xbname The name used in bans to signify this extban.
|
|
* @param xbletter The character used in bans to signify this extban.
|
|
*/
|
|
Acting(Module* mod, const std::string& xbname, ExtBan::Letter xbletter)
|
|
: ActingBase(mod, xbname, xbletter)
|
|
{
|
|
}
|
|
|
|
/** Determines whether the specified user matches this acting extban on the specified channel.
|
|
* @param user The user to check.
|
|
* @param channel The channel to check on.
|
|
* @return MOD_RES_ALLOW to explicitly allow their action, MOD_RES_DENY to expicitly deny their
|
|
* action, or MOD_RES_PASSTHRU to let the default behaviour apply.
|
|
*/
|
|
ModResult GetStatus(User* user, Channel* channel)
|
|
{
|
|
if (!GetManager())
|
|
return MOD_RES_PASSTHRU;
|
|
|
|
return GetManager()->GetStatus(this, user, channel);
|
|
}
|
|
};
|
|
|
|
/** Base class for matching extbans. */
|
|
class ExtBan::MatchingBase
|
|
: public Base
|
|
{
|
|
protected:
|
|
/** Initializes an instance of the ExtBan::MatchingBase class.
|
|
* @param mod The module which created this instance.
|
|
* @param xbname The name used in bans to signify this extban.
|
|
* @param xbletter The character used in bans to signify this extban.
|
|
*/
|
|
MatchingBase(Module* mod, const std::string& xbname, ExtBan::Letter xbletter)
|
|
: Base(mod, xbname, xbletter)
|
|
{
|
|
}
|
|
|
|
public:
|
|
/** @copydoc ExtBan::Base::GetType */
|
|
Type GetType() const override { return ExtBan::Type::MATCHING; }
|
|
|
|
/** @copydoc ExtBan::Base::IsMatch */
|
|
virtual bool IsMatch(User* user, Channel* channel, const std::string& text) override = 0;
|
|
};
|
|
|
|
/** Provides events relating to extbans. */
|
|
class ExtBan::EventListener
|
|
: public Events::ModuleEventListener
|
|
{
|
|
protected:
|
|
EventListener(Module* mod, unsigned int eventprio = DefaultPriority)
|
|
: ModuleEventListener(mod, "event/extban", eventprio)
|
|
{
|
|
}
|
|
|
|
public:
|
|
/** Called when an extban is being checked.
|
|
* @param user The user which the extban is being checked against.
|
|
* @param chan The channel which the extban is set on.
|
|
* @param extban The extban which is being checked against.
|
|
*/
|
|
virtual ModResult OnExtBanCheck(User* user, Channel* chan, ExtBan::Base* extban) = 0;
|
|
};
|
|
|
|
inline bool ExtBan::Parse(const std::string& banentry, std::string& name, std::string& value, bool& inverted)
|
|
{
|
|
// The mask must be in the format [!]<letter>:<value> or [!]<name>:<value>.
|
|
inverted = false;
|
|
size_t startpos = 0;
|
|
if (banentry[0] == '!')
|
|
{
|
|
inverted = true;
|
|
startpos++;
|
|
}
|
|
|
|
size_t endpos = banentry.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", startpos);
|
|
if (endpos == std::string::npos || banentry[endpos] != ':')
|
|
return false;
|
|
|
|
name.assign(banentry, startpos, endpos - startpos);
|
|
value.assign(banentry, endpos + 1);
|
|
return true;
|
|
}
|