1
0
mirror of https://github.com/anope/anope.git synced 2026-06-30 15:26:38 +02:00

Rewrite access path system to be simplier and use recursion

Show where access is "from" in chanserv/status
This commit is contained in:
Adam
2016-02-13 14:16:29 -05:00
parent addd2a1987
commit 4e2ca31cf5
9 changed files with 165 additions and 113 deletions
+42 -51
View File
@@ -250,8 +250,10 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
return access;
}
bool ChanAccess::Matches(const User *u, const NickCore *acc, Path &p) const
bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo* &next) const
{
next = NULL;
if (this->nc)
return this->nc == acc;
@@ -276,28 +278,7 @@ bool ChanAccess::Matches(const User *u, const NickCore *acc, Path &p) const
if (IRCD->IsChannelValid(this->mask))
{
ChannelInfo *tci = ChannelInfo::Find(this->mask);
if (tci)
{
for (unsigned i = 0; i < tci->GetAccessCount(); ++i)
{
ChanAccess *a = tci->GetAccess(i);
std::pair<const ChanAccess *, const ChanAccess *> pair = std::make_pair(this, a);
std::pair<Set::iterator, Set::iterator> range = p.first.equal_range(this);
for (; range.first != range.second; ++range.first)
if (range.first->first == pair.first && range.first->second == pair.second)
goto cont;
p.first.insert(pair);
if (a->Matches(u, acc, p))
p.second.insert(pair);
cont:;
}
return p.second.count(this) > 0;
}
next = ChannelInfo::Find(this->mask);
}
return false;
@@ -347,37 +328,30 @@ bool ChanAccess::operator<=(const ChanAccess &other) const
return !(*this > other);
}
AccessGroup::AccessGroup() : std::vector<ChanAccess *>()
AccessGroup::AccessGroup()
{
this->ci = NULL;
this->nc = NULL;
this->super_admin = this->founder = false;
}
static bool HasPriv(const AccessGroup &ag, const ChanAccess *access, const Anope::string &name)
static bool HasPriv(const ChanAccess::Path &path, const Anope::string &name)
{
EventReturn MOD_RESULT;
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
if (MOD_RESULT == EVENT_ALLOW || access->HasPriv(name))
if (path.empty())
return false;
for (unsigned int i = 0; i < path.size(); ++i)
{
typedef std::multimap<const ChanAccess *, const ChanAccess *> path;
std::pair<path::const_iterator, path::const_iterator> it = ag.path.second.equal_range(access);
if (it.first != it.second)
/* check all of the paths for this entry */
for (; it.first != it.second; ++it.first)
{
const ChanAccess *a = it.first->second;
/* if only one path fully matches then we are ok */
if (HasPriv(ag, a, name))
return true;
}
else
/* entry is the end of a chain, all entries match, ok */
return true;
ChanAccess *access = path[i];
EventReturn MOD_RESULT;
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
if (MOD_RESULT != EVENT_ALLOW && !access->HasPriv(name))
return false;
}
/* entry does not match or none of the chains fully match */
return false;
return true;
}
bool AccessGroup::HasPriv(const Anope::string &name) const
@@ -393,7 +367,7 @@ bool AccessGroup::HasPriv(const Anope::string &name) const
bool auto_mode = !name.find("AUTO");
/* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */
if ((!auto_mode || this->empty()) && this->founder)
if ((!auto_mode || paths.empty()) && this->founder)
return true;
EventReturn MOD_RESULT;
@@ -401,23 +375,40 @@ bool AccessGroup::HasPriv(const Anope::string &name) const
if (MOD_RESULT != EVENT_CONTINUE)
return MOD_RESULT == EVENT_ALLOW;
for (unsigned i = this->size(); i > 0; --i)
for (unsigned int i = paths.size(); i > 0; --i)
{
ChanAccess *access = this->at(i - 1);
const ChanAccess::Path &path = paths[i - 1];
if (::HasPriv(*this, access, name))
if (::HasPriv(path, name))
return true;
}
return false;
}
static ChanAccess *HighestInPath(const ChanAccess::Path &path)
{
ChanAccess *highest = NULL;
for (unsigned int i = 0; i < path.size(); ++i)
if (highest == NULL || *path[i] > *highest)
highest = path[i];
return highest;
}
const ChanAccess *AccessGroup::Highest() const
{
ChanAccess *highest = NULL;
for (unsigned i = 0; i < this->size(); ++i)
if (highest == NULL || *this->at(i) > *highest)
highest = this->at(i);
for (unsigned int i = 0; i < paths.size(); ++i)
{
ChanAccess *hip = HighestInPath(paths[i]);
if (highest == NULL || *hip > *highest)
highest = hip;
}
return highest;
}
+68 -34
View File
@@ -384,6 +384,39 @@ ChanAccess *ChannelInfo::GetAccess(unsigned index) const
return acc;
}
static void FindMatchesRecurse(ChannelInfo *ci, const User *u, const NickCore *account, unsigned int depth, std::vector<ChanAccess::Path> &paths, ChanAccess::Path &path)
{
if (depth > ChanAccess::MAX_DEPTH)
return;
for (unsigned int i = 0; i < ci->GetAccessCount(); ++i)
{
ChanAccess *a = ci->GetAccess(i);
ChannelInfo *next = NULL;
if (a->Matches(u, u->Account(), next))
{
ChanAccess::Path next_path = path;
next_path.push_back(a);
paths.push_back(next_path);
}
else if (next)
{
ChanAccess::Path next_path = path;
next_path.push_back(a);
FindMatchesRecurse(next, u, account, depth + 1, paths, next_path);
}
}
}
static void FindMatches(AccessGroup &group, ChannelInfo *ci, const User *u, const NickCore *account)
{
ChanAccess::Path path;
FindMatchesRecurse(ci, u, account, 0, group.paths, path);
}
AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
{
AccessGroup group;
@@ -404,20 +437,20 @@ AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
group.ci = this;
group.nc = nc;
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i)
{
ChanAccess *a = this->GetAccess(i);
if (a->Matches(u, u->Account(), group.path))
group.push_back(a);
}
FindMatches(group, this, u, u->Account());
if (group.founder || !group.empty())
if (group.founder || !group.paths.empty())
{
if (updateLastUsed)
this->last_used = Anope::CurTime;
for (unsigned i = 0; i < group.size(); ++i)
group[i]->last_seen = Anope::CurTime;
for (unsigned i = 0; i < group.paths.size(); ++i)
{
ChanAccess::Path &p = group.paths[i];
for (unsigned int j = 0; j < p.size(); ++j)
p[j]->last_seen = Anope::CurTime;
}
}
return group;
@@ -431,14 +464,9 @@ AccessGroup ChannelInfo::AccessFor(const NickCore *nc, bool updateLastUsed)
group.ci = this;
group.nc = nc;
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i)
{
ChanAccess *a = this->GetAccess(i);
if (a->Matches(NULL, nc, group.path))
group.push_back(a);
}
FindMatches(group, this, NULL, nc);
if (group.founder || !group.empty())
if (group.founder || !group.paths.empty())
if (updateLastUsed)
this->last_used = Anope::CurTime;
@@ -452,28 +480,34 @@ unsigned ChannelInfo::GetAccessCount() const
return this->access->size();
}
unsigned ChannelInfo::GetDeepAccessCount() const
static unsigned int GetDeepAccessCount(const ChannelInfo *ci, std::set<const ChannelInfo *> &seen, unsigned int depth)
{
ChanAccess::Path path;
for (unsigned i = 0, end = this->GetAccessCount(); i < end; ++i)
if (depth > ChanAccess::MAX_DEPTH || seen.count(ci))
return 0;
seen.insert(ci);
unsigned int total = 0;
for (unsigned int i = 0; i < ci->GetAccessCount(); ++i)
{
ChanAccess *a = this->GetAccess(i);
a->Matches(NULL, NULL, path);
ChanAccess::Path path;
ChanAccess *a = ci->GetAccess(i);
ChannelInfo *next = NULL;
a->Matches(NULL, NULL, next);
++total;
if (next)
total += GetDeepAccessCount(ci, seen, depth + 1);
}
unsigned count = this->GetAccessCount();
std::set<const ChannelInfo *> channels;
channels.insert(this);
for (ChanAccess::Set::iterator it = path.first.begin(); it != path.first.end(); ++it)
{
const ChannelInfo *ci = it->first->ci;
if (!channels.count(ci))
{
channels.count(ci);
count += ci->GetAccessCount();
}
}
return count;
return total;
}
unsigned ChannelInfo::GetDeepAccessCount() const
{
std::set<const ChannelInfo *> seen;
return ::GetDeepAccessCount(this, seen, 0);
}
ChanAccess *ChannelInfo::EraseAccess(unsigned index)