| #0 | PDO->__construct |
| #1 | Phalcon\Db\Adapter\Pdo\AbstractPdo->connect |
| #2 | Phalcon\Db\Adapter\Pdo\AbstractPdo->__construct /srv/ChatHispanoEngine/releases/20250927141530/config/services.php (77) <?php
$di['config'] = $config;
$di['session'] = function () use ($di, $config) {
$env = trim(file_get_contents(__DIR__ . '/environment.txt'));
$node = trim(file_get_contents(__DIR__ . '/node.txt'));
$path = $config->session->path;
$manager = new \Phalcon\Session\Manager();
$serializer = new \Phalcon\Storage\SerializerFactory();
if ($env == 'prod') {
$factory = new \Phalcon\Storage\AdapterFactory($serializer, [
'redisCluster' => \ChatHispanoEngine\Core\Library\Phalcon\Storage\Adapter\RedisCluster::class,
]);
$options = [
'adapter' => 'redisCluster',
'servers' => [
'10.234.60.7:6379',
'10.234.60.8:6379',
'10.234.60.9:6379',
'10.234.60.11:6379',
'10.234.60.12:6379',
'10.234.60.13:6379',
],
'persistent' => false,
'prefix' => $config->session->name . '::',
'lifetime' => 3600,
//'ssl' => [
// 'verify_peer' => true,
// 'verify_peer_name' => false,
// 'allow_self_signed' => true,
//],
];
$manager->setAdapter(new \Phalcon\Session\Adapter\Redis($factory, $options));
} else {
$factory = new \Phalcon\Storage\AdapterFactory($serializer);
$o = new \Phalcon\Session\Adapter\Redis($factory, [
'host' => '127.0.0.1',
'port' => 6379,
'uniqueId' => $config->session->name,
//'ssl' => [
// 'verify_peer' => false,
// 'verify_peer_name' => false,
// 'allow_self_signed' => true,
//],
]);
$manager->setAdapter($o);
}
$manager->start();
return $manager;
};
$di['flash'] = function () {
return new \Phalcon\Flash\Direct([
'error' => 'alert alert-danger alert-dismissible fade show',
'success' => 'alert alert-success alert-dismissible fade show',
'notice' => 'alert alert-info alert-dismissible fade show',
'warning' => 'alert alert-warning alert-dismissible fade show',
]);
};
$di['flashSession'] = function () {
return new \ChatHispanoEngine\Core\Library\Flash();
};
$di['security'] = function () {
$o = new \Phalcon\Encryption\Security();
$o->setWorkFactor(12);
return $o;
};
$di['db'] = function () use ($config) {
$node = trim(file_get_contents(__DIR__ . '/node.txt'));
$conf = $config->database->toArray();
$connection = new \Phalcon\Db\Adapter\Pdo\Mysql([
'host' => $conf[$node]['host'],
'username' => $conf[$node]['username'],
'password' => $conf[$node]['password'],
'dbname' => $conf[$node]['dbname'],
'options' => [
\PDO::ATTR_CASE => \PDO::CASE_LOWER,
],
'persistent' => true,
]);
$connection->execute('SET NAMES ' . $conf[$node]['charset']);
return $connection;
};
$di['postgresql'] = function () use ($config) {
$conf = $config->postgresql->toArray();
$connection = new \Phalcon\Db\Adapter\Pdo\Postgresql($conf);
return $connection;
};
$di['mongo'] = function () use ($config) {
try {
$mongo = new \MongoDB\Client($config->mongodb->uri);
return $mongo->selectDatabase('ChatHispanoEngine');
} catch (\Exception $e) {
return;
}
};
$di['redis_cluster'] = function () use ($config) {
$node = trim(file_get_contents(__DIR__ . '/node.txt'));
$env = trim(file_get_contents(__DIR__ . '/environment.txt'));
$path = $config->session->path;
$ssl_options = [
'stream' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
],
];
if ($env == 'dev') {
$o = new \Redis();
$o->connect($path[$node]['host'], $path[$node]['port'], 0, null, 0, 0);
//$o->connect($path[$node]['host'], $path[$node]['port'], 0, null, 0, 0, $ssl_options);
} else {
$o = new \RedisCluster(null, [
$path['even']['host'] . ':' . $path['even']['port'],
$path['odd']['host'] . ':' . $path['odd']['port'],
], 2.5, 2.5, false, null);
//], 2.5, 2.5, false, null, $ssl_options['stream']);
}
return $o;
};
$di['url'] = function () {
return new \Phalcon\Mvc\Url();
};
$di['voltService'] = function ($view) use ($config) {
$di = $this;
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$cache_dir = $config->view->cache->dir;
if (!is_dir($cache_dir)) {
mkdir($cache_dir, 0o777, true);
}
$env = trim(file_get_contents(__DIR__ . '/environment.txt'));
$volt->setOptions([
'path' => $cache_dir,
'extension' => '.compiled',
'always' => $env == 'prod' ? false : true,
]);
$compiler = $volt->getCompiler();
$compiler->addFunction('assets', function ($resolvedArgs, $exprArgs) use ($di) {
return $di->get('assets');
});
$compiler->addFunction('_t', function ($resolvedArgs, $exprArgs) use ($di) {
return '$this->translate->translate(' . $resolvedArgs . ')';
});
$compiler->addFunction('flashSession', function ($resolvedArgs, $exprArgs) use ($di) {
return '$this->flashSession->output()';
});
$compiler->addFunction('rand', function ($resolvedArgs, $exprArgs) use ($di) {
return 'rand(' . $resolvedArgs . ')';
});
$compiler->addFunction('isset', 'isset');
$compiler->addFilter('round', function ($resolvedArgs, $exprArgs) {
return 'round(' . $resolvedArgs . ', PHP_ROUND_HALF_DOWN)';
});
$compiler->addFilter('urlencode', function ($resolvedArgs, $exprArgs) {
return 'urlencode(' . $resolvedArgs . ')';
});
$compiler->addFilter('rawurlencode', function ($resolvedArgs, $exprArgs) {
return 'rawurlencode(' . $resolvedArgs . ')';
});
$compiler->addFilter('urldecode', function ($resolvedArgs, $exprArgs) {
return 'urldecode(' . $resolvedArgs . ')';
});
$compiler->addFilter('utf8encode', function ($resolvedArgs, $exprArgs) {
return 'utf8_encode(' . $resolvedArgs . ')';
});
$compiler->addFilter('utf8decode', function ($resolvedArgs, $exprArgs) {
return 'utf8_decode(' . $resolvedArgs . ')';
});
$compiler->addFilter('escapetahead', function ($resolvedArgs, $exprArgs) {
return 'str_replace(["\'","à","á","è","é","í","ò","ó","ú"], ["'","à","á","è","é","í","ò","ó","ú"], ' . $resolvedArgs . ')';
});
$compiler->addFunction('isArray', function ($resolvedArgs, $exprArgs) {
return 'is_array(' . $resolvedArgs . ')';
});
$compiler->addFunction('in_array', function ($resolvedArgs, $exprArgs) {
return 'in_array(' . $resolvedArgs . ')';
});
$compiler->addFunction('implode', function ($resolvedArgs, $exprArgs) {
return 'implode(' . $resolvedArgs . ')';
});
$compiler->addFunction('date', function ($resolvedArgs, $exprArgs) {
return 'date(' . $resolvedArgs . ')';
});
$compiler->addFunction('max', function ($resolvedArgs, $exprArgs) {
return 'max(' . $resolvedArgs . ')';
});
$compiler->addFunction('min', function ($resolvedArgs, $exprArgs) {
return 'min(' . $resolvedArgs . ')';
});
$compiler->addFunction('htmlspecialchars', function ($resolvedArgs, $exprArgs) {
return 'htmlspecialchars(' . $resolvedArgs . ')';
});
$compiler->addFunction('mb_strtolower', function ($resolvedArgs, $exprArgs) {
return 'mb_strtolower(' . $resolvedArgs . ')';
});
return $volt;
};
$di['auth'] = function () {
return new \ChatHispanoEngine\Core\Auth\Auth();
};
$di['mail'] = function () use ($di) {
return new \ChatHispanoEngine\Core\Library\Mail(
$di['redis_cluster']
);
};
$di['acl'] = function () {
return new \Phalcon\UserPlugin\Acl\Acl();
};
$di['cache'] = function () use ($di, $config) {
return new \Phalcon\Cache\Adapter\Redis(new \Phalcon\Storage\SerializerFactory(), [
'host' => '127.0.0.1',
'port' => 6379,
'prefix' => $config->session->name . '::',
]);
};
$di['modelsCache'] = function () use ($di, $config) {
$serializerFactory = new \Phalcon\Storage\SerializerFactory();
$adapterFactory = new \Phalcon\Cache\AdapterFactory($serializerFactory);
$options = [
'defaultSerializer' => 'Php',
'lifetime' => 7200,
];
$adapter = $adapterFactory->newInstance('apcu', $options);
return new \Phalcon\Cache\Cache($adapter);
};
$di['viewCache'] = $di['cache'];
$di['model_manager'] = function () {
return new \Phalcon\Mvc\Model\Manager();
};
$di['translate'] = function () use ($di, $config) {
$available = $config->i18n->available_languages->toArray();
$default = $config->i18n->default_locale;
$language = null;
if (php_sapi_name() != 'cli') {
$language = $di['session']->get('lang');
}
if (null === $language || false === $language || $language == '') {
/**
* We try to get the language from http request
* They are sort from highest priority to low priority
* so the first one we support is the one we will use.
* If none is found, the default is taken.
*/
$found = false;
if (php_sapi_name() != 'cli') {
$request = new \Phalcon\Http\Request();
$langs = $request->getLanguages();
foreach ($langs as $l) {
if (isset($available[$l['language']])) {
$language = $available[$l['language']];
$found = true;
break;
}
}
}
if (false === $found) {
$language = $default;
}
}
if (!file_exists(__DIR__ . '/../I18N/' . $language)) {
$language = $default;
}
return new \iwalkalone\Translator($available, $language, __DIR__ . '/../I18N/', $language, [
'creg',
'chan',
'nick',
'admin',
'oper',
'memo',
'clones',
'ipvirtual',
'docking',
'datacenter',
'proxyscanner',
'garbagecollector',
'wormhunter',
'ayuda',
'errmsg',
'web',
'login',
'shorten',
'foro',
'date',
'bugslayer',
]);
};
$di['logger'] = function () {
return new \iwalkalone\Logger();
};
$di['oauth2_storage'] = function () {
return new \ChatHispanoEngine\Core\Library\OAuth2\EmailStorage();
};
$di['assets'] = function () {
return new \Phalcon\Assets\Manager(new \Phalcon\Html\TagFactory(new \Phalcon\Html\Escaper()));
};
include 'managers.php';
|
| #3 | Application->{closure:/srv/ChatHispanoEngine/releases/20250927141530/config/services.php:74} |
| #4 | Phalcon\Di\Service->resolve |
| #5 | Phalcon\Di\Di->get |
| #6 | Phalcon\Di\Di->getShared |
| #7 | Phalcon\Mvc\Model\Manager->getConnection |
| #8 | Phalcon\Mvc\Model\Manager->getReadConnection |
| #9 | Phalcon\Mvc\Model->getReadConnection |
| #10 | Phalcon\Mvc\Model\Query->getReadConnection |
| #11 | Phalcon\Mvc\Model\Query->executeSelect |
| #12 | Phalcon\Mvc\Model\Query->execute |
| #13 | Phalcon\Mvc\Model::find /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/ChannelManager.php (4200) <?php
namespace ChatHispanoEngine\Core\Managers\InspIRCd;
use ChatHispanoEngine\Core\Library\Cdn\DefaultCdn as Cdn;
use ChatHispanoEngine\Core\Library\Graphics;
use ChatHispanoEngine\Core\Models\User;
use ChatHispanoEngine\Core\Models\Channel\Datasheet;
use ChatHispanoEngine\Core\Models\Channel\Override;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\History;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Forbid;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Section;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Access;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick\Hit;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick\Exception as AkickException;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Akick\Exception\Hit as ExceptionHit;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel\Status;
use ChatHispanoEngine\Core\Models\InspIRCd\Gline;
use ChatHispanoEngine\Core\Models\InspIRCd\Nick\History as NickHistory;
use ChatHispanoEngine\Core\Exception\Exception;
use ChatHispanoEngine\Core\Exception\ErrorCodes;
use Phalcon\Mvc\Model\Transaction\Manager as PhalconTxManager;
class ChannelManager extends \Phalcon\Mvc\Model\Manager
{
public const PAGE_SIZE = 20;
public const CHANNEL_WARN_EXPIRE_DAYS = 21;
public const CHANNEL_EXPIRE_DAYS = 30;
public const REDIS_HASH_CHANNEL_IDENTIFY = 'chathispano_hash_channel_identify';
public const SUCCESSOR_LEVEL = 499;
public const CHANNEL_MODES = [
'C' => ['params' => ['on' => 0, 'off' => 0], ],
'd' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+$/'], ],
'E' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^[\*~]{0,1}\d+:\d+(:\d+(:\d+)?)?$/'], ],
'F' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+$/'], ],
'f' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\*{0,1}\d+:\d+$/'], ],
'H' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+[yMmdh]{0,1}$/'], ],
'i' => ['params' => ['on' => 0, 'off' => 0], ],
'J' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+$/'], ],
'j' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+$/'], ],
'K' => ['params' => ['on' => 0, 'off' => 0], ],
'k' => ['params' => ['on' => 1, 'off' => 1], ],
'l' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+$/'], ],
'M' => ['params' => ['on' => 0, 'off' => 0], ],
'm' => ['params' => ['on' => 0, 'off' => 0], ],
'N' => ['params' => ['on' => 0, 'off' => 0], ],
'n' => ['params' => ['on' => 0, 'off' => 0], ],
'O' => ['params' => ['on' => 0, 'off' => 0], ],
'p' => ['params' => ['on' => 0, 'off' => 0], ],
'Q' => ['params' => ['on' => 0, 'off' => 0], ],
'R' => ['params' => ['on' => 0, 'off' => 0], ],
'r' => ['params' => ['on' => 0, 'off' => 0], ],
'S' => ['params' => ['on' => 0, 'off' => 0], ],
's' => ['params' => ['on' => 0, 'off' => 0], ],
'T' => ['params' => ['on' => 0, 'off' => 0], ],
't' => ['params' => ['on' => 0, 'off' => 0], ],
'u' => ['params' => ['on' => 0, 'off' => 0], ],
'W' => ['params' => ['on' => 0, 'off' => 0], ],
'x' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^[\*~]{0,1}\d+:\d+$/'], ],
'y' => ['params' => ['on' => 1, 'off' => 0, 'pattern' => '/^\d+:\d+$/'], ],
'z' => ['params' => ['on' => 0, 'off' => 0], ],
];
protected $channel_public_columns = 'name,founder,successor,section,description,is_suspended,suspend_ts,suspend_duration,suspend_reason,time_registered,last_topic,last_topic_by,last_topic_time';
protected $default_levels = [
'AUTOOP' => 300,
'AUTOVOICE' => 100,
'AUTODEOP' => 200,
'AUTODEVOICE' => 50,
'NOJOIN' => -1,
'INVITE' => 300,
'AKICK-CHANGE' => 500,
'AKICK-LIST' => 300,
'SET' => 500,
'CLEAR' => 500,
'TOPIC' => 500,
'UNBAN' => 300,
'OPDEOP' => 100,
'VOICEDEVOICE' => 100,
'ACC-LIST' => 0,
'ACC-CHANGE' => 500,
'MEMO-RECV' => 500,
'MEMO-SEND' => 0,
'BLOGGER' => 500,
'FORUM' => 500,
'IDENTIFY' => 0,
];
public function getDefaultLevels()
{
return $this->default_levels;
}
public function listSections($limit = 0)
{
if ($limit > 0) {
return Section::find([
'order' => 'section_order ASC, code ASC',
'limit' => $limit,
]);
} else {
return Section::find([
'order' => 'section_order ASC, code ASC',
]);
}
}
public function getSection($code)
{
$o = Section::findFirst([
'code = :code:',
'bind' => [
'code' => mb_strtoupper($code),
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_NOT_FOUND);
}
return $o;
}
public function getSectionBySlug($slug)
{
$o = Section::findFirst([
'slug = :slug:',
'bind' => [
'slug' => mb_strtolower($slug),
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_NOT_FOUND);
}
return $o;
}
protected function checkSectionParameters(array $data)
{
if (!isset($data['name']) || strlen($data['name']) == "") {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [
'messages' => ['Name cannot be empty'],
]);
}
if (!isset($data['description']) || strlen($data['description']) < 10) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [
'messages' => ['Description must have 10 characters at least'],
]);
}
}
public function newSection(array $data)
{
if (!isset($data['code']) || strlen($data['code']) != 3) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [
'messages' => ['Code must be 3 letter string'],
]);
}
$this->checkSectionParameters($data);
$data['code'] = mb_strtoupper($data['code']);
$o = new Section();
$o->assign($data);
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
public function updateSection($code, array $data)
{
$o = $this->getSection($code);
$this->checkSectionParameters($data);
$o->assign($data);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
public function deleteSection($code)
{
$o = $this->getSection($code);
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
public function countListBot($pattern, $nick, $ip)
{
if (strlen($pattern) > 0) {
$pattern = str_replace('*', '%', mb_strtolower($pattern));
return Channel::count([
'name LIKE :pattern:',
'bind' => [
'pattern' => $pattern,
],
]);
} else {
return Channel::count([
'bind' => [
'pattern' => $pattern,
],
]);
}
}
public function getAll()
{
return Channel::find();
}
public function getListBot($pattern, $page, $nick, $ip)
{
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($nick, 'preoper');
if (strlen($pattern) > 0) {
$pattern = str_replace('*', '%', mb_strtolower($pattern));
return Channel::find([
'name LIKE :pattern:',
'bind' => [
'pattern' => $pattern,
],
'order' => 'name ASC',
'limit' => self::PAGE_SIZE,
'offset' => ($page - 1) * self::PAGE_SIZE,
]);
} else {
return Channel::find([
'order' => 'name ASC',
'limit' => self::PAGE_SIZE,
'offset' => ($page - 1) * self::PAGE_SIZE,
]);
}
}
public function getListSuspended()
{
return Channel::find([
'is_suspended = 1',
'order' => 'name ASC',
]);
}
public function countListGI()
{
return Channel::count([
'ig = 1',
'order' => 'name ASC',
]);
}
public function getListGIAll()
{
return Channel::find([
'ig = 1',
'order' => 'name ASC',
]);
}
public function getListGI($page, $nick)
{
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($nick, 'preoper');
return Channel::find([
'ig = 1',
'order' => 'name ASC',
'limit' => self::PAGE_SIZE,
'offset' => ($page - 1) * self::PAGE_SIZE,
]);
}
public function count()
{
return Channel::count();
}
public function countByUrl($url)
{
return Channel::count([
'ig = :ig: AND (LOWER(description) like :url: or LOWER(entrymsg) like :url: or LOWER(last_topic) like :url:)',
'bind' => [
'ig' => 1,
'url' => '%' . mb_strtolower($url) . '%',
],
]);
}
public function listAll()
{
return Channel::find();
}
public function listIg()
{
return Channel::find([
'ig = :ig:',
'bind' => [
'ig' => 1,
],
]);
}
public function listSuspendExpired()
{
return Channel::find([
'is_suspended = 1 AND suspend_ts + suspend_duration <= :ts:',
'bind' => [
'ts' => time(),
],
]);
}
public function getList($name, $order = 'name ASC', $from = 0, $num = 100, $full = false)
{
if ($full) {
$columns = '*';
} else {
$columns = $this->channel_public_columns;
}
if (strlen($name) > 0) {
$conditions = 'LOWER(name) LIKE :name:';
$bind = [
'name' => '%' . mb_strtolower($name) . '%',
];
} else {
$conditions = '';
$bind = [];
}
if ($conditions == '') {
return Channel::find([
'columns' => $columns,
'order' => $order,
'limit' => $num,
'offset' => $from,
]);
} else {
return Channel::find([
$conditions,
'bind' => $bind,
'columns' => $columns,
'order' => $order,
'limit' => $num,
'offset' => $from,
]);
}
}
public function getImportant()
{
$config = $this->getDI()->get('config');
$redis = $this->getDI()->get('redis_cluster');
$list = $redis->hGetAll('chathispano_channels_hash_name');
$data = [];
foreach ($list as $item) {
$o = json_decode($item, true);
$cnt = $o['cnt_members'];
if ($cnt < $config->channels->important->minimum_nicks) {
continue;
}
if (preg_match('/[sp]/', $o['modes'])) {
continue;
}
if (!isset($data[$cnt])) {
$data[$cnt] = [];
}
$data[$cnt][] = [
'name' => $o['name'],
'description' => $o['topic'],
'users' => $o['cnt_members'],
'important' => 0,
];
}
krsort($data, SORT_NUMERIC);
$result = [];
foreach ($data as $cnt => $channels) {
foreach ($channels as $c) {
$result[] = $c;
}
}
return $result;
}
public function get($name, $full = false, $cached = false)
{
if ($cached === true) {
$o = Channel::findFirst([
'columns' => $full ? '*' : $this->channel_public_columns,
'name = :name:',
'bind' => [
'name' => mb_strtolower($name),
],
'cache' => [
'key' => 'inspircd-channel-' . mb_strtolower($name) . ($full ? '-full' : ''),
'lifetime' => 300,
],
]);
} else {
$o = Channel::findFirst([
'columns' => $full ? '*' : $this->channel_public_columns,
'name = :name:',
'bind' => [
'name' => mb_strtolower($name),
],
]);
}
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_NOT_FOUND);
}
return $o;
}
protected function levelExists($level)
{
return isset($this->default_levels[mb_strtoupper($level)]);
}
public function normalizeLevels(array $data)
{
foreach ($data as $key => $value) {
if (!isset($this->default_levels[$key])) {
unset($data[$key]);
}
}
$data = array_merge($this->default_levels, $data);
return $data;
}
public function checkName($name)
{
return preg_match("/^#[A-Za-z0-9áàéèíòóúñç_\.^\\\\\/#%&@=-]{1,29}$/", $name);
}
protected function checkChannel($name)
{
$o = null;
try {
$o = $this->get($name, true);
} catch (\Exception $e) {
}
if ($o) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_ALREADY_REGISTERED);
}
if (!$this->checkName($name)) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_INVALID);
}
}
public function countHistory($channel, $nick, $type = 'DEFAULT')
{
$manager = $this->getDI()->get('inspircd_nick_manager');
$manager->checkOperator($nick, 'preoper');
switch ($type) {
case 'ALL':
return History::count([
[
'channel' => mb_strtolower($channel),
],
]);
break;
case 'ACCESS':
return History::count([
[
'channel' => mb_strtolower($channel),
'event' => new \MongoDB\BSON\Regex('^(REGA|REGS|REGD|REGE|DELA)$'),
],
]);
break;
case 'AKICKS':
return History::count([
[
'channel' => mb_strtolower($channel),
'event' => new \MongoDB\BSON\Regex('^(AKA|AKS|AKD|AKE)$'),
],
]);
break;
case 'TOPICS':
return History::count([
[
'channel' => mb_strtolower($channel),
'event' => 'ST',
],
]);
break;
default:
return History::count([
[
'channel' => mb_strtolower($channel),
'event' => new \MongoDB\BSON\Regex('^(?!(REGA|REGS|REGD|REGE|DELA|AKA|AKS|AKD|AKE|ST))[A-Z]+$'),
],
]);
break;
}
}
public function getHistory($channel, $nick, $page = 1, $type = 'DEFAULT')
{
$manager = $this->getDI()->get('inspircd_nick_manager');
$manager->checkOperator($nick, 'preoper');
switch ($type) {
case 'ALL':
return History::find([
[
'channel' => mb_strtolower($channel),
],
'sort' => [
'date' => -1,
],
'limit' => self::PAGE_SIZE,
'skip' => self::PAGE_SIZE * ($page - 1),
]);
break;
case 'ACCESS':
return History::find([
[
'channel' => mb_strtolower($channel),
'event' => new \MongoDB\BSON\Regex('^(REGA|REGS|REGD|REGE|DELA)$'),
],
'sort' => [
'date' => -1,
],
'limit' => self::PAGE_SIZE,
'skip' => self::PAGE_SIZE * ($page - 1),
]);
break;
case 'AKICKS':
return History::find([
[
'channel' => mb_strtolower($channel),
'event' => new \MongoDB\BSON\Regex('^(AKA|AKD|AKE)$'),
],
'sort' => [
'date' => -1,
],
'limit' => self::PAGE_SIZE,
'skip' => self::PAGE_SIZE * ($page - 1),
]);
break;
case 'TOPICS':
return History::find([
[
'channel' => mb_strtolower($channel),
'event' => 'ST',
],
'sort' => [
'date' => -1,
],
'limit' => self::PAGE_SIZE,
'skip' => self::PAGE_SIZE * ($page - 1),
]);
break;
default:
return History::find([
[
'channel' => mb_strtolower($channel),
'event' => new \MongoDB\BSON\Regex('^(?!(REGA|REGS|REGD|REGE|DELA|AKA|AKD|AKE|ST))[A-Z]+$'),
],
'sort' => [
'date' => -1,
],
'limit' => self::PAGE_SIZE,
'skip' => self::PAGE_SIZE * ($page - 1),
]);
break;
}
}
public function getHistoryToCleanup(int $ts, int $limit = 1000)
{
return History::find([
[
'ip' => [
'$ne' => '-',
],
'date' => [
'$lt' => new \MongoDB\BSON\UTCDateTime($ts * 1000),
],
],
'sort' => [
'date' => 1,
],
'limit' => $limit,
]);
}
public function getHistoryAll($channel)
{
return History::find([
[
'channel' => mb_strtolower($channel),
],
'sort' => [
'date' => -1,
],
]);
}
public function createHistory($channel, $event, $ip, array $parameters)
{
$o = new History();
$o->date = new \MongoDB\BSON\UTCDateTime((int) round(microtime(true) * 1000));
$o->channel = mb_strtolower($channel);
$o->event = $event;
$o->ip = $ip;
$o->parameters = $parameters;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
protected function create(array $data, $ip)
{
$this->checkChannel($data['name']);
$defaults = [
'successor' => new \Phalcon\Db\RawValue("NULL"),
'section' => new \Phalcon\Db\RawValue("NULL"),
'url' => new \Phalcon\Db\RawValue("NULL"),
'email' => new \Phalcon\Db\RawValue("NULL"),
'levels' => json_encode($this->normalizeLevels([])),
'mlock' => '+',
'is_suspended' => 0,
'suspend_by' => new \Phalcon\Db\RawValue("NULL"),
'suspend_ts' => new \Phalcon\Db\RawValue("NULL"),
'suspend_duration' => new \Phalcon\Db\RawValue("NULL"),
'suspend_reason' => new \Phalcon\Db\RawValue("NULL"),
'time_registered' => time(),
'time_last_use' => time(),
'last_modes' => '',
'last_topic' => new \Phalcon\Db\RawValue("NULL"),
'last_topic_by' => new \Phalcon\Db\RawValue("NULL"),
'last_topic_time' => new \Phalcon\Db\RawValue("NULL"),
];
$data = array_merge($defaults, $data);
$data['founder'] = mb_strtolower($data['founder']);
$data['password'] = $this->getDI()->get('security')->hash($data['password']);
$o = new Channel();
$o->assign($data);
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->setStatus($data['name'], Status::STATUS_REGISTERED, $ip, $data['founder']);
return $o;
}
protected function checkFounder($founder)
{
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$o = $nick_manager->get($founder, true);
if ($o->getTimeRegistered() > time() - 7 * 24 * 3600) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_WAIT);
}
return $o;
}
public function new(array $data, $oper, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel');
$o = $this->create(array_merge($data, [
'founder' => $oper,
]), $ip);
$this->createHistory($data['name'], History::EVENT_REGISTER, $ip, [
'who' => $oper,
]);
$dbTx->commit();
return $o;
}
public function registerRequest(array $data, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$this->checkChannel($data['name']);
$n = $this->checkFounder($data['founder']);
$o = $this->getStatus($data['name']);
if ($o) {
switch ($o->status) {
case Status::STATUS_DENIED:
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_DENIED);
break;
case Status::STATUS_REJECTED:
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_REJECTED);
break;
case Status::STATUS_DROPPED:
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_DROPPED);
break;
case Status::STATUS_REQUESTED:
if ($o->nick == mb_strtolower($data['founder'])) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_ALREADY_REQUESTED);
} else {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_ALREADY_IN_PROCESS);
}
break;
default:
break;
}
} else {
$cnt = Status::count([
[
'status' => (int) Status::STATUS_REQUESTED,
'nick' => mb_strtolower($data['founder']),
],
]);
if ($cnt > 0) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_WAIT);
}
}
$this->setStatus($data['name'], Status::STATUS_REQUESTED, $ip, $data['founder'], '', $data['password'], $data['description'], $n->getEmail());
$this->createHistory($data['name'], History::EVENT_REQUEST, $ip, [
'who' => $data['founder'],
]);
$dbTx->commit();
}
public function registerAccept($name, $oper, $section, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel', 'canregister');
$status = $this->getStatus($name);
if (!$status || $status->status != Status::STATUS_REQUESTED) {
if ($status && ($status->status == Status::STATUS_REJECTED || $status->status == Status::STATUS_DENIED) && $status->founder) {
try {
$nick_manager->checkOperator($oper, 'devel');
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED);
}
} else {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED);
}
}
$this->checkChannel($status->channel);
$f = $this->checkFounder($status->founder);
$o = $this->create([
'name' => $status->channel,
'section' => mb_strtoupper($section),
'founder' => $status->founder,
'password' => $status->password,
'description' => $status->description,
], $ip);
$this->createHistory($status->channel, History::EVENT_ACCEPT, $ip, [
'who' => $oper,
]);
$this->createHistory($status->channel, History::EVENT_REGISTER, $ip, [
'who' => $status->founder,
]);
$dbTx->commit();
$o = $this->get($name, true);
$this->enqueue($o);
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$n = $irc_manager->getNick($status->founder);
if ($n) {
$msg = $this->getDI()->get('translate')->translate('Channel %name% registration has been approved.', [
'name' => $status->channel,
], 'creg');
$irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $msg);
}
$mailer = $this->getDI()->get('mail');
$mailer->addTo($f->getEmail());
$mailer->setLanguage('es');
$mailer->send(
'Chat Hispano',
'[ChatHispano] El registro del canal canal ' . $status->channel . ' ha sido aceptado',
'creg_accept',
null,
[
'nick' => $f->getNick(),
'channel' => $status->channel,
'images' => [
'logo' => 'public/assets/backoffice/img/logo-medium.jpg',
],
]
);
return $o;
}
public function registerCancel($name, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$status = $this->getStatus($name);
if (!$status || $status->status != Status::STATUS_REQUESTED) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED);
}
if (mb_strtolower($nick) != $status->nick) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
$this->setStatus($status->channel, Status::STATUS_NOT_REGISTERED, $ip, $status->nick);
$dbTx->commit();
$this->createHistory($name, History::EVENT_CANCEL, $ip, [
'who' => $nick,
]);
}
public function registerDeny($name, $oper, $ip, $reason)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel', 'canregister');
$status = $this->getStatus($name);
if (!$status || $status->status != Status::STATUS_REQUESTED) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED);
}
$this->setStatus($status->channel, Status::STATUS_DENIED, $ip, $status->nick, $reason, $status->password, $status->description, $status->email);
$this->createHistory($name, History::EVENT_DENY, $ip, [
'who' => $oper,
'reason' => $reason,
]);
$dbTx->commit();
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$n = $irc_manager->getNick($status->nick);
if ($n) {
$msg = $this->getDI()->get('translate')->translate('Channel %name% registration has been denied:', [
'name' => $status->channel,
], 'creg');
$irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $msg);
$irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $reason);
}
$f = $this->checkFounder($status->nick);
$mailer = $this->getDI()->get('mail');
$mailer->addTo($f->getEmail());
$mailer->setLanguage('es');
$mailer->send(
'Chat Hispano',
'[ChatHispano] El registro del canal canal ' . $status->channel . ' ha sido denegado',
'creg_denied',
null,
[
'nick' => $f->getNick(),
'channel' => $status->channel,
'reason' => $reason,
'images' => [
'logo' => 'public/assets/backoffice/img/logo-medium.jpg',
],
]
);
}
public function registerReject($name, $oper, $ip, $reason)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel', 'canregister');
$status = $this->getStatus($name);
if (!$status || $status->status != Status::STATUS_REQUESTED) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_REQUESTED);
}
$this->setStatus($status->channel, Status::STATUS_REJECTED, $ip, $status->nick, $reason, $status->password, $status->description, $status->email);
$this->createHistory($name, History::EVENT_REJECT, $ip, [
'who' => $oper,
'reason' => $reason,
]);
$dbTx->commit();
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$n = $irc_manager->getNick($status->nick);
if ($n) {
$msg = $this->getDI()->get('translate')->translate('Channel %name% registration has been rejected:', [
'name' => $status->channel,
], 'creg');
$irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $msg);
$irc_manager->privmsgOrderEnqueue('AAAAAA', $n['uid'], $reason);
}
$f = $this->checkFounder($status->nick);
$mailer = $this->getDI()->get('mail');
$mailer->addTo($f->getEmail());
$mailer->setLanguage('es');
$mailer->send(
'Chat Hispano',
'[ChatHispano] El registro del canal canal ' . $status->channel . ' ha sido rechazado',
'creg_reject',
null,
[
'nick' => $f->getNick(),
'channel' => $status->channel,
'reason' => $reason,
'images' => [
'logo' => 'public/assets/backoffice/img/logo-medium.jpg',
],
]
);
}
public function registerAllow($name, $oper, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'preoper');
$status = $this->getStatus($name);
if (!$status || ($status && $status->status != Status::STATUS_DROPPED && $status->status != Status::STATUS_REJECTED && $status->status != Status::STATUS_DENIED)) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_CHANNEL_NOT_DENIED);
}
$this->setStatus($status->channel, Status::STATUS_NOT_REGISTERED, $ip, $status->nick);
$this->createHistory($name, History::EVENT_PERMIT, $ip, [
'who' => $oper,
]);
$dbTx->commit();
}
protected function update(Channel $o, array $data)
{
$o->assign($data);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
public function suspend($name, $oper, $reason, $duration, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$operator = $nick_manager->checkOperator($oper, 'preoper', '');
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ALREADY_SUSPENDED);
}
$seconds = new \Khill\Duration\Duration(str_replace('+', '', $duration));
if (!$operator->isAdmin() && $seconds->toSeconds() > 10 * 24 * 3600) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPEND_TOO_MUCH_TIME);
}
if ($seconds->toSeconds() < 3600) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPEND_TOO_SHORT);
}
$o = $this->update($o, [
'is_suspended' => 1,
'suspend_by' => mb_strtolower($oper),
'suspend_ts' => time(),
'suspend_duration' => $seconds->toSeconds(),
'suspend_reason' => $reason,
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->setStatus($name, Status::STATUS_SUSPENDED, $ip, $oper, $reason);
$this->createHistory($name, History::EVENT_SUSPEND, $ip, [
'who' => $oper,
'reason' => $reason,
]);
$dbTx->commit();
return $o;
}
public function unsuspend($name, $oper, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'preoper');
$o = $this->get($name, true);
if ($o->getIsSuspended() != 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_NOT_SUSPENDED);
}
$o = $this->update($o, [
'is_suspended' => 0,
'suspend_by' => new \Phalcon\Db\RawValue("NULL"),
'suspend_ts' => new \Phalcon\Db\RawValue("NULL"),
'suspend_duration' => new \Phalcon\Db\RawValue("NULL"),
'suspend_reason' => new \Phalcon\Db\RawValue("NULL"),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->setStatus($name, Status::STATUS_REGISTERED, $ip, $oper);
$this->createHistory($name, History::EVENT_REHAB, $ip, [
'who' => $oper,
]);
$dbTx->commit();
return $o;
}
public function accessList($name, $op, $orderby = 'nick ASC')
{
$c = $this->get($name, true);
$oper = false;
if (false === $this->checkLevel($c, 'ACC-LIST', $op)) {
try {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
return Access::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => $orderby,
]);
}
public function accessCount($name, $op)
{
$c = $this->get($name, true);
$oper = false;
if (false === $this->checkLevel($c, 'ACC-LIST', $op)) {
try {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
return Access::count([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
]);
}
public function accessAdd($name, $nick, $level, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$name = mb_strtolower($name);
$nick = mb_strtolower($nick);
$c = $this->get($name, true);
if ($c->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$oper = false;
if (false === $this->checkLevel($c, 'ACC-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
} else {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
}
}
if ($level < -1 || $level >= 500 || $level == 0) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_BAD_LEVEL);
}
if ($oper === false) {
$oplvl = $this->getLevel($c, $op);
if ($level >= $oplvl) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => $name,
'nick' => $nick,
],
]);
if ($o) {
if ($oper === false) {
if ($o->getLevel() >= $oplvl) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
if ($level == $o->getLevel()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_CHANGED, [
'nick' => $nick,
'level' => $level,
]);
}
$o->assign([
'level' => $level,
'set_by' => $op,
'set_on' => time(),
]);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($c->getName());
$this->createHistory($name, History::EVENT_ACCESS_SET, $ip, [
$nick,
$level,
$op,
]);
$nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_SET, $ip, [
$name,
$nick,
$level,
]);
} else {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$n = $nick_manager->get($nick, true);
if ($n->getOptions()['nochaccess']) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NICK_HAS_NOCHACCESS, [
'nick' => $nick,
]);
}
$o = new Access();
$o->assign([
'channel' => mb_strtolower($name),
'nick' => mb_strtolower($nick),
'level' => $level,
'set_by' => $op,
'set_on' => time(),
]);
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($c->getName());
$this->createHistory($name, History::EVENT_ACCESS_ADD, $ip, [
$nick,
$level,
$op,
]);
$nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_ADD, $ip, [
$name,
$nick,
$level,
]);
}
$nick_manager->createHistory($nick, NickHistory::EVENT_ACCESS_RECV, $ip, [
$name,
$level,
$op,
]);
$dbTx->commit();
return $o;
}
public function accessDel($name, $nick, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$name = mb_strtolower($name);
$nick = mb_strtolower($nick);
$c = $this->get($name, true);
if ($c->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$oper = false;
if (false === $this->checkLevel($c, 'ACC-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
} else {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
}
}
$o = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => $name,
'nick' => $nick,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_FOUND);
} else {
if ($oper === false) {
$oplvl = $this->getLevel($c, $op);
if ($o->getLevel() >= $oplvl) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
}
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($c->getName());
$this->createHistory($name, History::EVENT_ACCESS_DEL, $ip, [
$nick,
$op,
]);
$nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_DEL, $ip, [
$name,
$nick,
]);
$nick_manager->createHistory($nick, NickHistory::EVENT_ACCESS_TAKEN, $ip, [
$name,
$op,
]);
$dbTx->commit();
return $o;
}
public function accessClear($name, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$name = mb_strtolower($name);
$c = $this->get($name, true);
if ($c->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$oper = false;
if (mb_strtolower($op) != $c->getFounder() && mb_strtolower($op) != $c->getSuccessor()) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
} else {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
}
}
$list = $c->getAccess();
foreach ($list as $o) {
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->createHistory($name, History::EVENT_ACCESS_DEL, $ip, [
$o->getNick(),
$op,
]);
$nick_manager->createHistory($op, NickHistory::EVENT_ACCESS_DEL, $ip, [
$name,
$o->getNick(),
]);
$nick_manager->createHistory($o->getNick(), NickHistory::EVENT_ACCESS_TAKEN, $ip, [
$name,
$op,
]);
}
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($c->getName());
$dbTx->commit();
return $c;
}
public function accessHit($name, $nick, $ts = 0)
{
$name = mb_strtolower($name);
$nick = mb_strtolower($nick);
$o = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => $name,
'nick' => $nick,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_FOUND);
} else {
if ($ts == 0) {
$o->setLastUse(time());
} else {
$o->setLastUse($ts);
}
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_UPDATE, [
'message' => join(". ", $o->getMessages()),
]);
}
}
return $o;
}
protected function checkMlock($mlock, array $parameters)
{
$op = 'on';
$on = false;
$off = false;
$modes = [];
$params = 0;
$ml_modes = [];
$ml_params = [];
for ($i = 0; $i < strlen($mlock); $i++) {
$m = substr($mlock, $i, 1);
if ($m == '+') {
if ($on == true || $off == true) {
return [
'status' => false,
'errmsg' => $this->getDI()->get('translate')->translate('Symbol %symbol% more than once', ['symbol' => '+']),
];
}
$modes[] = '+';
$ml_modes[] = '+';
$on = true;
$op = 'on';
} elseif ($m == '-') {
if ($off == true) {
return [
'status' => false,
'errmsg' => $this->getDI()->get('translate')->translate('Symbol %symbol more than once', ['symbol' => '-']),
];
}
$modes[] = '-';
$ml_modes[] = '-';
$off = true;
$op = 'off';
} else {
if (in_array($m, $modes)) {
return [
'status' => false,
'errmsg' => $this->getDI()->get('translate')->translate('Mode %mode% found more than once', ['mode' => $m]),
];
}
if (!isset(self::CHANNEL_MODES[$m])) {
return [
'status' => false,
'errmsg' => $this->getDI()->get('translate')->translate('Unknown mode %mode%', ['mode' => $m]),
];
}
if ($m != 'r') { // we exclude +r parameter
$modes[] = $m;
if (self::CHANNEL_MODES[$m]['params'][$op] > 0) {
if (!isset($parameters[$params])) {
return [
'status' => false,
'errmsg' => $this->getDI()->get('translate')->translate('Missing parameter for mode %mode%', ['mode' => $m]),
];
}
if (isset(self::CHANNEL_MODES[$m]['params']['pattern']) && !preg_match(self::CHANNEL_MODES[$m]['params']['pattern'], $parameters[$params])) {
return [
'status' => false,
'errmsg' => $this->getDI()->get('translate')->translate('Wrong parameter %param% for mode %mode%', [
'mode' => $m,
'param' => $parameters[$params],
]),
];
}
}
$ml_modes[] = $m;
if ($m != 'k') {
if (self::CHANNEL_MODES[$m]['params'][$op] > 0) {
$ml_params[] = $parameters[$params];
}
}
$params += self::CHANNEL_MODES[$m]['params'][$op];
}
}
}
if (count($ml_params) > 0) {
$mlock = join('', $ml_modes) . ' ' . join(' ', $ml_params);
} else {
$mlock = join('', $ml_modes);
}
if (count($parameters) > 0) {
$mode = join('', $modes) . ' ' . join(' ', $parameters);
} else {
$mode = join('', $modes);
}
return [
'status' => true,
'mlock' => $mlock,
'mode' => $mode,
];
}
public function setMlock($name, $mlock, array $parameters, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$c = $this->get($name, true);
if ($c->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$oper = false;
if (false === $this->checkLevel($c, 'SET', $nick)) {
try {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$result = $this->checkMlock($mlock, $parameters);
if ($result['status'] === false) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_MLOCK_BAD_FORMAT, [
'errmsg' => $result['errmsg'],
]);
}
$o = $this->update($c, [
'mlock' => $result['mlock'],
]);
$this->createHistory($name, History::EVENT_SET_MLOCK, $ip, [
'mlock' => $result['mlock'],
'who' => $nick,
]);
$dbTx->commit();
return [
'mlock' => $result['mlock'],
'mode' => $result['mode'],
'obj' => $o,
];
}
public function setPassword($name, $password, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'password' => $this->getDI()->get('security')->hash($password),
]);
$this->unidentifyChannel($name);
$this->createHistory($name, History::EVENT_SET_PASSWORD, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function checkPassword($name, $password)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
if (!$this->getDI()->get('security')->checkHash($password, $o->getPassword())) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_BAD_PASSWORD);
}
return $o;
}
public function setFounder($name, $nick, $founder, $ip, $checkCredentials = true)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
if ($checkCredentials === true) {
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
}
$f = $nick_manager->get($founder, true);
if ($f->getOptions()['nochaccess']) {
$a = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => mb_strtolower($name),
'nick' => mb_strtolower($founder),
],
]);
if (!$a) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SET_FOUNDER_NICK_HAS_NOCHACCESS, [
'nick' => $founder,
]);
}
}
if (mb_strtolower($founder) == $o->getSuccessor()) {
$o = $this->update($o, [
'founder' => mb_strtolower($founder),
'successor' => new \Phalcon\Db\RawValue("NULL"),
]);
} else {
$o = $this->update($o, [
'founder' => mb_strtolower($founder),
]);
}
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->unidentifyChannel($name);
$this->createHistory($name, History::EVENT_SET_FOUNDER, $ip, [
'founder' => $founder,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setSuccessor($name, $nick, $successor, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$s = $nick_manager->get($successor, true);
if ($s->getOptions()['nochaccess']) {
$a = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => mb_strtolower($name),
'nick' => mb_strtolower($successor),
],
]);
if (!$a) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SET_SUCCESSOR_NICK_HAS_NOCHACCESS, [
'nick' => $successor,
]);
}
}
$o = $this->update($o, [
'successor' => mb_strtolower($successor),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->createHistory($name, History::EVENT_SET_SUCCESSOR, $ip, [
'successor' => $successor,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function unsetSuccessor($name, $nick, $ip, $checkCredentials = true)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
if ($checkCredentials === true) {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
}
if (strlen($o->getSuccessor()) <= 0) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_NO_SUCCESSOR);
}
$o = $this->update($o, [
'successor' => new \Phalcon\Db\RawValue("NULL"),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->createHistory($name, History::EVENT_UNSET_SUCCESSOR, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setSection($name, $nick, $section, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
try {
$nick_manager->checkOperator($nick, 'devel', 'canregister');
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
$section = mb_strtoupper($section);
$s = $this->getSection($section);
$o = $this->update($o, [
'section' => $section,
]);
$this->createHistory($name, History::EVENT_SET_SECTION, $ip, [
'section' => $section,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setDescription($name, $nick, $description, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'devel', 'canregister');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'description' => $description,
]);
$this->createHistory($name, History::EVENT_SET_DESCRIPTION, $ip, [
'description' => $description,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setGi($name, $nick, $value, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($nick, 'devel');
$o = $this->update($o, [
'ig' => mb_strtolower($value) == 'on' ? 1 : 0,
]);
$event = $o->getIg() == 1 ? History::EVENT_SET_GENERAL_INTEREST : History::EVENT_UNSET_GENERAL_INTEREST;
$this->createHistory($name, $event, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setUrl($name, $nick, $url, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'url' => $url,
]);
$this->createHistory($name, History::EVENT_SET_URL, $ip, [
'url' => $url,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function unsetUrl($name, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'url' => new \Phalcon\Db\RawValue("NULL"),
]);
$this->createHistory($name, History::EVENT_UNSET_URL, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setEmail($name, $nick, $email, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'email' => $email,
]);
$this->createHistory($name, History::EVENT_SET_EMAIL, $ip, [
'email' => $email,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function unsetEmail($name, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'email' => new \Phalcon\Db\RawValue("NULL"),
]);
$this->createHistory($name, History::EVENT_UNSET_EMAIL, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setEntrymsg($name, $nick, $entrymsg, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'entrymsg' => $entrymsg,
]);
$this->createHistory($name, History::EVENT_SET_ENTRYMSG, $ip, [
'entrymsg' => $entrymsg,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function unsetEntrymsg($name, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'entrymsg' => new \Phalcon\Db\RawValue("NULL"),
]);
$this->createHistory($name, History::EVENT_UNSET_ENTRYMSG, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setOption($name, $nick, $option, $value, $ip, $check_operator = true)
{
$dbTx = (new PhalconTxManager())->get();
try {
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, $option == 'openai' ? 'SET' : 499, $nick)) {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} else {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
}
}
if ($check_operator === true && in_array($option, ['noakick', 'noexpire', 'noads', 'expirewarn', 'forum', 'underage'])) {
if ($oper === true) {
if (in_array($option, ['noexpire', 'noads', 'expirewarn', 'forum', 'underage', 'openai'])) {
$nick_manager->checkOperator($nick, 'devel');
}
} else {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$options = $o->getOptions();
$v = mb_strtolower($value) == 'on' ? true : false;
if (isset($options[$option]) && $v === $options[$option]) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_OPTION_NOT_CHANGED);
}
// We only allow to activate openai option if channel is IG
if ($option == 'openai' && $v === true && $o->getIg() != 1 && $oper === false) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
$options[$option] = $v;
$o = $this->update($o, [
'options' => $options,
]);
$this->createHistory($name, $options[$option] ? History::EVENT_SET_OPTION : History::EVENT_UNSET_OPTION, $ip, [
'option' => $option,
'who' => $nick,
]);
$dbTx->commit();
} catch (\Exception $e) {
$dbTx->rollback();
throw new \Exception($e->getMessage(), $e->getCode());
}
return $o;
}
public function setLastModes($name, $modes)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$o = $this->update($o, [
'last_modes' => $modes,
]);
return $o;
}
public function setTopic($name, $nick, $topic, $ts, $ip, $check_credentials = true)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
if (true === $check_credentials) {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'TOPIC', $nick)) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'last_topic' => $topic,
'last_topic_by' => mb_strtolower($nick),
'last_topic_time' => $ts,
]);
$this->createHistory($name, History::EVENT_SET_TOPIC, $ip, [
'topic' => $topic,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function setLevel($name, $nick, $level, $value, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
if (!$this->levelExists($level)) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_LEVEL_DOES_NOT_EXIST);
}
if (!is_numeric($value) || $value < -1 || $value > 500) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_LEVEL_OUT_OF_BOUNDS);
}
$levels = $this->normalizeLevels(json_decode($o->getLevels(), true));
$levels[strtoupper($level)] = $value;
$levels = $this->normalizeLevels($levels);
$o = $this->update($o, [
'levels' => json_encode($levels),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->createHistory($name, History::EVENT_SET_LEVEL, $ip, [
'level' => strtoupper($level),
'value' => $value,
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function disableLevel($name, $nick, $level, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
if (!$this->levelExists($level)) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_LEVEL_DOES_NOT_EXIST);
}
$levels = $this->normalizeLevels(json_decode($o->getLevels(), true));
$levels[strtoupper($level)] = 'DIS';
$levels = $this->normalizeLevels($levels);
$o = $this->update($o, [
'levels' => json_encode($levels),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->createHistory($name, History::EVENT_DISABLE_LEVEL, $ip, [
'level' => strtoupper($level),
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function resetLevels($name, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 500, $nick)) {
try {
$nick_manager->checkOperator($nick, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = $this->update($o, [
'levels' => json_encode($this->default_levels),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->createHistory($name, History::EVENT_RESET_LEVELS, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function updateLastUse($channel)
{
$o = $this->get($channel, true);
$o = $this->update($o, [
'time_last_use' => time(),
]);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
try {
$o = $this->setOption($o->getName(), 'ChatHispano', 'expirewarn', 'off', '127.0.0.1', false);
} catch (\Exception $e) {
}
return $o;
}
protected function checkAkickMask($mask, $exception = false, $oper = false)
{
$restrictedPrefixes = [
"U:",
"G:",
"X:",
];
if (false === $oper && in_array(substr($mask, 0, 2), $restrictedPrefixes)) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
// only nick, we add !*@* to the end
if (preg_match("/^[^\s:!@]+$/", $mask)) {
$mask .= '!*@*';
}
$patterns = [
"/^r:[^\\s]+$/", // realname
"/^a:[^\\s!@\\+]+![^\\s!@\\+]+@[^\\s!@\\+]+\\+[^\\s]+$/", // mask+realname
"/^G:([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // geolocation
"/^G:([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // geolocation with continent
"/^g:([a-z]:)?[^\\s!@\\+]+![^\\s!@\\+]+@[^\\s!@\\+]+\\+([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // mask + geolocation
"/^U:[a-z0-9]{16}$/", // unique user id (android)
"/^U:[a-z0-9]{32}$/", // unique user id (webchat)
"/^X:[a-z0-9]{16}!([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // unique user id (android) + geolocation
"/^X:[a-z0-9]{32}!([A-Z]{2}|\\*)!([A-Z]{2}|\\*)!([A-Z]{2,3}|\\*)!([A-Za-z0-9\\*]+|\\*)!([A-Za-z0-9\\*]+|\\*)$/", // unique user id (webchat) + geolocation
"/^([a-z]:)?[^\\s!@\\+]+![^\\s!@\\+]+@[^\\s!@\\+]+$/", // rest of
];
$valid = false;
foreach ($patterns as $p) {
if (preg_match($p, $mask)) {
$valid = true;
break;
}
}
if ($valid === false) {
throw new Exception(null, $exception ? ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_CREATE : ErrorCodes::ERR_CHANNEL_AKICK_CREATE, [
'message' => 'Invalid mask',
]);
}
// Convert to lowercase nick part in regular masks + a:, g: extbans
if (substr($mask, 1, 1) != ':' || substr($mask, 0, 2) == 'a:' || substr($mask, 0, 2) == 'g:') {
$parts = explode('!', $mask);
$mask = strtolower($parts[0]) . '!' . join('!', array_slice($parts, 1));
}
return $mask;
}
public function akickAdd($channel, $mask, $reason, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($channel, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
} else {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
}
}
if ($oper === false) {
$redis = $this->getDI()->get('redis_cluster');
$v = $redis->get('chathispano_inspircd_akick_delete_' . str_replace('#', '', $channel) . '_' . $mask);
if ($v && $v == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_WAIT);
}
}
$mask = $this->checkAkickMask($mask, false, $oper);
$o = new Akick();
$o->assign([
'channel' => mb_strtolower($channel),
'mask' => $mask,
'reason' => $reason,
'author' => mb_strtolower($op),
'created_on' => new \Phalcon\Db\RawValue("NOW()"),
'last_hit' => new \Phalcon\Db\RawValue("NULL"),
'hits' => 0,
]);
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_ADD, $ip, [
$mask,
mb_strtolower($op),
$reason,
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_ADD, $ip, [
mb_strtolower($channel),
$mask,
$reason,
]);
$dbTx->commit();
return $o;
}
public function akickSet($channel, $mask, $reason, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($channel, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = Akick::findFirst([
'channel = :channel: AND mask = :mask:',
'bind' => [
'channel' => mb_strtolower($channel),
'mask' => $mask,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_NOT_FOUND);
}
$o->assign([
'reason' => $reason,
'author' => mb_strtolower($op),
]);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_SET, $ip, [
$mask,
mb_strtolower($op),
$reason,
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_SET, $ip, [
mb_strtolower($channel),
$mask,
$reason,
]);
$dbTx->commit();
return $o;
}
public function akickDel($name, $mask, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = Akick::findFirst([
'channel = :channel: AND mask = :mask:',
'bind' => [
'channel' => mb_strtolower($name),
'mask' => $mask,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_NOT_FOUND);
}
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
$redis = $this->getDI()->get('redis_cluster');
$redis->set('chathispano_inspircd_akick_delete_' . str_replace('#', '', $name) . '_' . $mask, 1, 3600 * 24);
$this->createHistory(mb_strtolower($name), History::EVENT_AKICK_DEL, $ip, [
$mask,
mb_strtolower($op),
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_DEL, $ip, [
mb_strtolower($name),
$mask,
]);
$dbTx->commit();
return $o;
}
public function akickClear($name, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper', '', true);
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$list = $o->getAkick();
$masks = [];
foreach ($list as $a) {
$masks[] = $a->getMask();
if (false === $a->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_DELETE, [
'message' => join('. ', $a->getMessages()),
]);
}
}
foreach ($masks as $mask) {
$redis = $this->getDI()->get('redis_cluster');
$redis->set('chathispano_inspircd_akick_delete_' . str_replace('#', '', $name) . '_' . $mask, 1, 3600 * 24);
$this->createHistory(mb_strtolower($name), History::EVENT_AKICK_DEL, $ip, [
$mask,
mb_strtolower($op),
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_DEL, $ip, [
mb_strtolower($name),
$mask,
]);
}
$dbTx->commit();
return $o;
}
public function akickList($name, $op, $ip, $order = 'mask ASC')
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
return Akick::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => $order,
]);
}
public function akickEnforce($name, $users, $op, $ip)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$exceptions = AkickException::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => 'hits DESC',
]);
$list = Akick::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => 'hits DESC',
]);
$result = [];
foreach ($users as $u) {
$exception = false;
foreach ($exceptions as $o) {
if ($nick_manager->checkMask($u, $o->getMask())) {
$exception = true;
break;
}
}
if (false === $exception) {
foreach ($list as $o) {
if (isset($u['modes']) && preg_match("/[Bok]/", $u['modes'])) {
continue;
}
if ($nick_manager->checkMask($u, $o->getMask())) {
$result[] = array_merge($u, [
'mask' => $o->getMask(),
'reason' => $o->getReason(),
'author' => $o->getAuthor(),
]);
$o->setLastHit(new \Phalcon\Db\RawValue("NOW()"));
$o->setHits($o->getHits() + 1);
$o->save();
break;
}
}
}
}
return $result;
}
public function akickAffectsUser(Channel $c, array $user)
{
if ($c->getIsSuspended() == 1) {
return false;
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$list = AkickException::find([
'channel = :channel:',
'bind' => [
'channel' => $c->getName(),
],
'order' => 'hits DESC',
]);
foreach ($list as $o) {
if ($nick_manager->checkMask($user, $o->getMask())) {
return false;
}
}
$list = Akick::find([
'channel = :channel:',
'bind' => [
'channel' => $c->getName(),
],
'order' => 'hits DESC',
]);
foreach ($list as $o) {
if ($nick_manager->checkMask($user, $o->getMask())) {
return true;
}
}
return false;
}
public function akickCheck($name, $user, $op, $ip)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (mb_strtolower($user['nick']) != mb_strtolower($op)) {
if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
}
$list = AkickException::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => 'hits DESC',
]);
foreach ($list as $o) {
if ($nick_manager->checkMask($user, $o->getMask())) {
return [];
}
}
$list = Akick::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => 'hits DESC',
]);
$result = [];
foreach ($list as $o) {
if ($nick_manager->checkMask($user, $o->getMask())) {
$result[] = [
'mask' => $o->getMask(),
'reason' => $o->getReason(),
'author' => $o->getAuthor(),
];
break;
}
}
return $result;
}
public function akickCount($name, $op)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
return Akick::count([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
]);
}
public function akickHitCount($channel, $mask, $victim)
{
$parameters = [];
if ($channel != '') {
$parameters['channel'] = mb_strtolower($channel);
}
if ($mask != '') {
$parameters['mask'] = mb_strtolower($mask);
}
if ($victim != '') {
$parameters['victim'] = mb_strtolower($victim);
}
return Hit::count([
$parameters,
]);
}
public function akickHitList($channel, $mask, $victim, $page = 1)
{
$parameters = [];
if ($channel != '') {
$parameters['channel'] = mb_strtolower($channel);
}
if ($mask != '') {
$parameters['mask'] = mb_strtolower($mask);
}
if ($victim != '') {
$parameters['victim'] = mb_strtolower($victim);
}
return Hit::find([
$parameters,
'limit' => self::PAGE_SIZE,
'skip' => ($page - 1) * self::PAGE_SIZE,
]);
}
public function akickHit($name, $mask, $nick, $ts = 0)
{
$dbTx = (new PhalconTxManager())->get();
$o = Akick::findFirst([
'channel = :name: AND mask = :mask:',
'bind' => [
'name' => mb_strtolower($name),
'mask' => $mask,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_NOT_FOUND);
}
if ($ts == 0) {
$o->setLastHit(new \Phalcon\Db\RawValue("NOW()"));
} else {
$o->setLastHit(date('Y-m-d H:i:s', $ts));
}
$o->setHits($o->getHits() + 1);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_UPDATE, [
'message' => join(". ", $o->getMessages()),
]);
}
$h = new Hit();
$h->date = new \MongoDB\BSON\UTCDateTime(time() * 1000);
$h->channel = $o->getChannel();
$h->mask = $mask;
$h->victim = mb_strtolower($nick);
$h->reason = $o->getReason();
if (false === $h->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_UPDATE, [
'message' => join(". ", $h->getMessages()),
]);
}
$dbTx->commit();
return $o;
}
public function akickFind()
{
return Akick::find();
}
public function akickExceptionAdd($channel, $mask, $reason, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($channel, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
} else {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
}
}
$mask = $this->checkAkickMask($mask, true, $oper);
$o = new AkickException();
$o->assign([
'channel' => mb_strtolower($channel),
'mask' => $mask,
'reason' => $reason,
'author' => mb_strtolower($op),
'created_on' => new \Phalcon\Db\RawValue("NOW()"),
'last_hit' => new \Phalcon\Db\RawValue("NULL"),
'hits' => 0,
]);
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_EXCEPTION_ADD, $ip, [
$mask,
mb_strtolower($op),
$reason,
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_EXCEPTION_ADD, $ip, [
mb_strtolower($channel),
$mask,
$reason,
]);
$dbTx->commit();
return $o;
}
public function akickExceptionSet($channel, $mask, $reason, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($channel, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = AkickException::findFirst([
'channel = :channel: AND mask = :mask:',
'bind' => [
'channel' => mb_strtolower($channel),
'mask' => $mask,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_NOT_FOUND);
}
$o->assign([
'reason' => $reason,
'author' => mb_strtolower($op),
]);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->createHistory(mb_strtolower($channel), History::EVENT_AKICK_EXCEPTION_SET, $ip, [
$mask,
mb_strtolower($op),
$reason,
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_EXCEPTION_SET, $ip, [
mb_strtolower($channel),
$mask,
$reason,
]);
$dbTx->commit();
return $o;
}
public function akickExceptionDel($name, $mask, $op, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-CHANGE', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
$o = AkickException::findFirst([
'channel = :channel: AND mask = :mask:',
'bind' => [
'channel' => mb_strtolower($name),
'mask' => $mask,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_NOT_FOUND);
}
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->createHistory(mb_strtolower($name), History::EVENT_AKICK_EXCEPTION_DEL, $ip, [
$mask,
mb_strtolower($op),
]);
$nick_manager->createHistory(mb_strtolower($op), NickHistory::EVENT_AKICK_EXCEPTION_DEL, $ip, [
mb_strtolower($name),
$mask,
]);
$dbTx->commit();
return $o;
}
public function akickExceptionList($name, $op, $ip, $order = 'mask ASC')
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
return AkickException::find([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
'order' => $order,
]);
}
public function akickExceptionCount($name, $op)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$oper = false;
if (false === $this->checkLevel($o, 'AKICK-LIST', $op)) {
try {
$nick_manager->checkOperator($op, 'preoper');
$oper = true;
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
return AkickException::count([
'channel = :channel:',
'bind' => [
'channel' => mb_strtolower($name),
],
]);
}
public function akickExceptionHitCount($channel, $mask, $victim)
{
$parameters = [];
if ($channel != '') {
$parameters['channel'] = mb_strtolower($channel);
}
if ($mask != '') {
$parameters['mask'] = mb_strtolower($mask);
}
if ($victim != '') {
$parameters['victim'] = mb_strtolower($victim);
}
return ExceptionHit::count([
$parameters,
]);
}
public function akickExceptionHitList($channel, $mask, $victim, $page = 1)
{
$parameters = [];
if ($channel != '') {
$parameters['channel'] = mb_strtolower($channel);
}
if ($mask != '') {
$parameters['mask'] = mb_strtolower($mask);
}
if ($victim != '') {
$parameters['victim'] = mb_strtolower($victim);
}
return ExceptionHit::find([
$parameters,
'limit' => self::PAGE_SIZE,
'skip' => ($page - 1) * self::PAGE_SIZE,
]);
}
public function akickExceptionHit($name, $mask, $nick, $ts = 0)
{
$dbTx = (new PhalconTxManager())->get();
$o = AkickException::findFirst([
'channel = :name: AND mask = :mask:',
'bind' => [
'name' => mb_strtolower($name),
'mask' => $mask,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_NOT_FOUND);
}
if ($ts == 0) {
$o->setLastHit(new \Phalcon\Db\RawValue("NOW()"));
} else {
$o->setLastHit(date('Y-m-d H:i:s', $ts));
}
$o->setHits($o->getHits() + 1);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_UPDATE, [
'message' => join(". ", $o->getMessages()),
]);
}
$h = new Hit();
$h->date = new \MongoDB\BSON\UTCDateTime(time() * 1000);
$h->channel = $o->getChannel();
$h->mask = $mask;
$h->victim = mb_strtolower($nick);
$h->reason = $o->getReason();
if (false === $h->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_AKICK_EXCEPTION_UPDATE, [
'message' => join(". ", $h->getMessages()),
]);
}
$dbTx->commit();
return $o;
}
public function akickExceptionFind()
{
return AkickException::find();
}
public function drop($name, $oper, $reason, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'preoper', '');
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->enqueueDelete($o);
$this->setStatus($name, Status::STATUS_DROPPED, $ip, $oper, $reason);
$this->createHistory($name, History::EVENT_DROPPED, $ip, [
'who' => $oper,
'reason' => $reason,
]);
$dbTx->commit();
return $o;
}
public function delSuccessor($name, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
if (strlen($o->getSuccessor()) <= 0) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_NO_SUCCESSOR);
}
if (mb_strtolower($o->getSuccessor()) != mb_strtolower($nick)) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUCCESSOR_MISMATCH);
}
$o = $this->update($o, [
'successor' => new \Phalcon\Db\RawValue("NULL"),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->createHistory($name, History::EVENT_UNSET_SUCCESSOR, $ip, [
'who' => $nick,
]);
$dbTx->commit();
return $o;
}
public function listForbidAll($cached = false)
{
if ($cached === true) {
return Forbid::find([
'cache' => [
'key' => 'channel-forbids-all',
'lifetime' => 3600,
],
]);
} else {
return Forbid::find();
}
}
public function countForbid()
{
return Forbid::count();
}
public function getChannelsByPattern($pattern)
{
$matched = [];
$list = $this->listAll();
foreach ($list as $o) {
$name = str_replace('#', '', $o->getName());
if (preg_match('#' . $pattern . '#i', $name)) {
$matched[] = $o;
}
}
return $matched;
}
public function listForbid($page = 1)
{
return Forbid::find([
'limit' => self::PAGE_SIZE,
'offset' => ($page - 1) * self::PAGE_SIZE,
]);
}
public function getForbid($id)
{
$o = Forbid::findFirst([
'id = :id:',
'bind' => [
'id' => $id,
],
]);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_NOT_FOUND);
}
return $o;
}
public function checkForbid($name, $cached = false)
{
$list = $this->listForbidAll($cached);
foreach ($list as $o) {
if (preg_match("#" . $o->getPattern() . "#i", str_replace('#', '', $name))) {
return true;
}
}
return false;
}
public function checkForbiddenRegisteredChannels(Forbid $f, $oper, $force, $ip)
{
$list = Channel::find();
foreach ($list as $o) {
if (preg_match("#" . $f->getPattern() . "#i", str_replace('#', '', $o->getName()))) {
if ($force === true) {
/**
* We have to drop the nick as it is not allowed to use it anymore
*/
$this->drop($o->getName(), $oper, 'El canal ya no puede usarse (FORBID)', $ip);
} else {
/**
* We drop an exception as we warn that pattern will drop registered nicks
* and it is not forced
*/
throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_REGISTERED_AFFECTED);
}
}
}
}
public function newForbid(array $data, $oper, $force, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel');
$date = date('Y-m-d H:i:s');
$defaults = [
'created_by' => $oper,
'created_at' => $date,
'updated_by' => $oper,
'updated_at' => $date,
];
$data = array_merge($defaults, $data);
$o = new Forbid();
$o->assign($data);
$this->checkForbiddenRegisteredChannels($o, $oper, $force, $ip);
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_CREATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$dbTx->commit();
return $o;
}
public function updateForbid($id, array $data, $oper, $force, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel');
$o = $this->getForbid($id);
$defaults = [
'updated_by' => $oper,
'updated_at' => date('Y-m-d H:i:s'),
];
$data = array_merge($defaults, $data);
$o->assign($data);
$this->checkForbiddenRegisteredChannels($o, $oper, $force, $ip);
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
$dbTx->commit();
return $o;
}
public function deleteForbid($id, $oper)
{
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($oper, 'devel');
$o = $this->getForbid($id);
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_FORBID_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
public function getChannelAccess($channel, $nick)
{
$o = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => mb_strtolower($channel),
'nick' => mb_strtolower($nick),
],
]);
return $o;
}
public function getLevel(/*Channel|string*/ $channel, $nick)
{
$nick = strtolower($nick);
if (is_object($channel)) {
$c = $channel;
} else {
$c = $this->get($channel, true);
}
// Channel owner
if (mb_strtolower($c->getFounder()) == $nick) {
return 500;
}
// Identified
$redis = $this->getDI()->get('redis_cluster');
$json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, $c->getName());
if ($json) {
$identified = json_decode($json, true);
} else {
$identified = [];
}
if (in_array($nick, $identified)) {
return 500;
}
// Sucessor
if (mb_strtolower($c->getSuccessor()) == $nick) {
return self::SUCCESSOR_LEVEL;
}
// Register
$a = $this->getChannelAccess($c->getName(), $nick);
if ($a) {
return $a->getLevel();
}
return 0;
}
public function checkLevel(/*Channel|string*/ $channel, $level, $nick)
{
$nick = strtolower($nick);
if (is_object($channel)) {
$c = $channel;
} else {
$c = $this->get($channel, true);
}
$userlevel = 0;
$is_founder = false;
if (mb_strtolower($c->getFounder()) == $nick) {
$userlevel = 500;
$is_founder = true;
} else {
$redis = $this->getDI()->get('redis_cluster');
$json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, $c->getName());
if ($json) {
$identified = json_decode($json, true);
} else {
$identified = [];
}
if (in_array($nick, $identified)) {
$userlevel = 500;
$is_founder = true;
} elseif ($c->getSuccessor() && mb_strtolower($c->getSuccessor()) == $nick) {
$userlevel = self::SUCCESSOR_LEVEL;
} else {
$a = $this->getChannelAccess($c->getName(), $nick);
if ($a) {
$userlevel = $a->getLevel();
}
}
}
if (!is_numeric($level)) {
$levels = $this->normalizeLevels(json_decode($c->getLevels(), true));
if ($levels[$level] === 'DIS' || $levels[$level] === 'DISABLED') {
if ($level === 'AUTOOP' && $is_founder === true) {
return true;
}
return false;
}
if ($level === 'NOJOIN' || $level === 'AUTODEOP' || $level === 'AUTODEVOICE') {
return $userlevel <= $levels[$level];
}
if ($levels[$level] === 0 && ($level === 'AUTOOP' || $level === 'AUTOVOICE')) {
return false;
}
return $userlevel >= $levels[$level];
}
return $userlevel >= $level;
}
public function checkInvite($channel, $nick)
{
return $this->checkLevel($channel, 'INVITE', $nick);
}
public function checkVoice($channel, $nick)
{
return $this->checkLevel($channel, 'VOICEDEVOICE', $nick);
}
public function checkDevoice($channel, $nick)
{
return $this->checkLevel($channel, 'VOICEDEVOICE', $nick);
}
public function checkOp($channel, $nick)
{
return $this->checkLevel($channel, 'OPDEOP', $nick);
}
public function checkDeop($channel, $nick)
{
return $this->checkLevel($channel, 'OPDEOP', $nick);
}
public function checkUnban($channel, $nick)
{
return $this->checkLevel($channel, 'UNBAN', $nick);
}
public function checkTopic($channel, $nick)
{
return $this->checkLevel($channel, 'TOPIC', $nick);
}
public function checkBlogger($channel, $nick)
{
return $this->checkLevel($channel, 'BLOGGER', $nick);
}
public function checkForum($channel, $nick)
{
return $this->checkLevel($channel, 'FORUM', $nick);
}
public function delaccess($channel, $nick, $ip)
{
$dbTx = (new PhalconTxManager())->get();
$nick = mb_strtolower($nick);
$c = $this->get($channel, true);
if ($c->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$a = $this->getChannelAccess($channel, $nick);
if ($a) {
if ($a->getLevel() < 0) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NEGATIVE_REGISTER);
} else {
if (false === $a->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_DELETE, [
'message' => join('. ', $a->getMessages()),
]);
}
}
} else {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ACCESS_NOT_FOUND);
}
$this->createHistory($c->getName(), History::EVENT_DELACCESS, $ip, [
'nick' => $nick,
]);
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->createHistory($nick, History::EVENT_DELACCESS, $ip, [
'channel' => $channel,
]);
$this->enqueue($c);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($channel);
$dbTx->commit();
return $a;
}
public function getStatusAll()
{
return Status::find();
}
public function getStatusList($status, $page = 1)
{
return Status::find([
[
'status' => (int) $status,
],
'limit' => self::PAGE_SIZE,
'skip' => ($page - 1) * self::PAGE_SIZE,
]);
}
public function getStatus($channel)
{
return Status::findFirst([
[
'channel' => mb_strtolower($channel),
],
]);
}
public function setStatus($channel, $status, $ip, $nick, $reason = '', $password = '', $description = '', $email = '')
{
$o = $this->getStatus($channel);
if (!$o) {
$o = new Status();
$o->channel = mb_strtolower($channel);
}
$o->ip = $ip;
$o->nick = mb_strtolower($nick);
$o->status = $status;
if ($o->status == Status::STATUS_REQUESTED) {
$o->founder = $o->nick;
}
$o->ts = time();
$o->reason = $reason;
$o->password = $password;
$o->description = $description;
$o->email = $email;
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_UPDATE, [
'message' => join('. ', $o->getMessages()),
]);
}
return $o;
}
public function comment($channel, $nick, $ip, $comment)
{
return $this->createHistory($channel, History::EVENT_COMMENT, $ip, [
'who' => $nick,
'comment' => $comment,
]);
}
public function getIdentified($channel)
{
$redis = $this->getDI()->get('redis_cluster');
$json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel));
if ($json) {
$nicks = json_decode($json, true);
} else {
$nicks = [];
}
return $nicks;
}
public function isIdentified($channel, $nick)
{
$redis = $this->getDI()->get('redis_cluster');
$json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel));
if ($json) {
$nicks = json_decode($json, true);
} else {
$nicks = [];
}
return in_array(mb_strtolower($nick), $nicks);
}
public function identify($channel, $password, $nick, $ip)
{
$nick = mb_strtolower($nick);
$o = $this->get($channel, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
if ($o->getFounder() == mb_strtolower($nick)) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_ALREADY_FOUNDER);
}
if (false === $this->checkLevel($o, 'IDENTIFY', $nick)) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
if (!$this->getDI()->get('security')->checkHash($password, $o->getPassword())) {
$config = $this->getDI()->get('config');
$redis = $this->getDI()->get('redis_cluster');
$debug_channel = $config->irc->bots->chan->debug_channel;
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$irc_manager->privmsgOrderEnqueue('AAAAAA', $debug_channel, "\x02\x034[BADPASS]\x03 Chan =\x02 " . $channel . "\x02 Nick =\x02 " . $nick);
if ($redis->hExists('chathispano_badpass_chan', $ip)) {
$badpass = json_decode($redis->hGet('chathispano_badpass_chan', $ip), true);
if (time() - $badpass['ts'] > 300) {
$badpass = ['ts' => time(), 'cnt' => 1];
} else {
$badpass = ['ts' => time(), 'cnt' => $badpass['cnt'] + 1];
}
} else {
$badpass = ['ts' => time(), 'cnt' => 1];
}
if ($badpass['cnt'] >= 5) {
try {
$gline_manager = $this->getDI()->get('inspircd_gline_manager');
$geo = $irc_manager->get_geoip($ip);
$g = $gline_manager->new(-1, Gline::TYPE_BADPASS, '-', '-', '-', 'urquhart.chathispano.com', $ip, '3600', [], $geo ? $geo : []);
$irc_manager->glineOrderEnqueue('*@' . $ip, '3600', '[' . $g->id . '] You have missed the password multiple times. This has been detected as an abuse.');
$debug_channel = $config->irc->bots->chan->debug_channel;
$irc_manager->privmsgOrderEnqueue('AAAAAA', $debug_channel, "\x02\x034[BADPASS] [GLINE] [" . $g->id . "]\x03");
$redis->hDel('chathispano_badpass_chan', $ip);
} catch (\Exception $e) {
}
} else {
$redis->hSet('chathispano_badpass_chan', $ip, json_encode($badpass));
}
throw new Exception(null, ErrorCodes::ERR_CHANNEL_BAD_PASSWORD);
}
$this->setIdentify($channel, $nick, true);
$redis->hDel('chathispano_badpass_chan', $ip);
$this->enqueueIdentify($o, $nick, "1");
$this->createHistory($o->getName(), History::EVENT_IDENTIFY, $ip, [
'who' => $nick,
]);
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->createHistory($nick, History::EVENT_IDENTIFY, $ip, [
'name' => $o->getName(),
]);
}
public function setIdentify($channel, $nick, $triggerException = false)
{
$redis = $this->getDI()->get('redis_cluster');
$json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel));
if ($json) {
$nicks = json_decode($json, true);
if (in_array($nick, $nicks)) {
if ($triggerException == true) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_NICK_ALREADY_IDENTIFIED);
} else {
return;
}
}
} else {
$nicks = [];
}
$nicks[] = $nick;
$redis->hSet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel), json_encode($nicks));
}
public function unidentify($channel, $nick)
{
$nick = mb_strtolower($nick);
$o = $this->get($channel, true);
$redis = $this->getDI()->get('redis_cluster');
$json = $redis->hGet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel));
if ($json) {
$nicks = json_decode($json, true);
if (!in_array($nick, $nicks)) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_NICK_NOT_IDENTIFIED);
}
$nicks = array_diff($nicks, [$nick]);
$redis->hSet(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel), json_encode($nicks));
}
$this->enqueueIdentify($o, $nick, "0");
}
public function unidentifyChannel($channel)
{
$o = $this->get($channel, true);
// NOTE: We get the identified list before delete to send to Socket later
$list = $this->getIdentified($channel);
$redis = $this->getDI()->get('redis_cluster');
$redis->hDel(self::REDIS_HASH_CHANNEL_IDENTIFY, mb_strtolower($channel));
// NOTE: We send to socket the unidentified list
foreach ($list as $nick) {
$this->enqueueIdentify($o, $nick, "0");
}
}
public function unidentifyAll()
{
$redis = $this->getDI()->get('redis_cluster');
$redis->del(self::REDIS_HASH_CHANNEL_IDENTIFY);
// NOTE: We do not send to Socket because this is only a services burst reset
}
public function info($bot, $channel, $nick, $ip, $oper = false)
{
if ($oper === true) {
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
$nick_manager->checkOperator($nick, 'preoper');
}
$s = $this->getStatus($channel);
if (!$s) {
$s = new Status();
$s->channel = mb_strtolower($channel);
$s->status = Status::STATUS_NOT_REGISTERED;
}
$messages = [
$bot->buildMessage("Information from channel %channel%:", [
'channel' => $channel,
]),
" " . $bot->buildMessage("Status") . ": " . $bot->buildMessage($s->getStatusName()),
];
try {
$o = $this->get($channel, true);
if ($o->getIsSuspended() == 1) {
$messages[] = " " . $bot->buildMessage("Suspend reason") . ": " . $o->getSuspendReason();
if ($oper === true) {
$messages[] = " " . $bot->buildMessage("Suspended by") . ": " . $o->getSuspendBy();
}
$messages[] = " " . $bot->buildMessage("Suspended until") . ": " . date('Y-m-d H:i:s', $o->getSuspendTs() + $o->getSuspendDuration());
}
$messages[] = " " . $bot->buildMessage("Section") . ": " . (strlen($o->getSection()) <= 0 ? "-" : $o->getSection());
if ($o->getIg() == 1) {
$messages[] = " " . $bot->buildMessage("It is a general interest channel.", []);
}
$messages[] = " " . $bot->buildMessage("Founder") . ": " . ($o->getFounder() ? $o->getFounder() : $bot->buildMessage("Without founder"));
if ($o->getSuccessor()) {
$messages[] = " " . $bot->buildMessage("Successor") . ": " . $o->getSuccessor();
}
$messages[] = " " . $bot->buildMessage("Description") . ": " . $o->getDescription();
$messages[] = " " . $bot->buildMessage("Registered") . ": " . date('Y-m-d H:i:s', $o->getTimeRegistered());
$messages[] = " " . $bot->buildMessage("Last use") . ": " . date('Y-m-d H:i:s', $o->getTimeLastUse());
$options = $o->getOptions(!$oper);
if (($options['noexpire'] === false || $options['noexpire'] === 0) && $o->getIg() != 1) {
if ($o->getTimeLastUse()) {
$messages[] = " " . $bot->buildMessage("Expires at") . ": " . date('Y-m-d H:i:s', $o->getTimeLastUse() + self::CHANNEL_EXPIRE_DAYS * 24 * 3600);
} else {
$messages[] = " " . $bot->buildMessage("Expires at") . ": " . date('Y-m-d H:i:s', $o->getTimeRegistered() + self::CHANNEL_EXPIRE_DAYS * 24 * 3600);
}
}
$levels = $this->normalizeLevels(json_decode($o->getLevels(), true));
// We only show topic and entrymsg information if user is an operator or is not blocked by NOJOIN level
if ($oper === true || false === $this->checkLevel($channel, 'NOJOIN', $nick)) {
if (strlen($o->getLastTopic()) > 0) {
$messages[] = " " . $bot->buildMessage("Last topic") . ": " . $o->getLastTopic();
$messages[] = " " . $bot->buildMessage("Topic set by") . ": " . $o->getLastTopicBy();
$messages[] = " " . $bot->buildMessage("Topic set on") . ": " . date('Y-m-d H:i:s', $o->getLastTopicTime());
} else {
$messages[] = " " . $bot->buildMessage("No topic set");
}
if (strlen($o->getEntrymsg())) {
$messages[] = " " . $bot->buildMessage("Entry message") . ": " . $o->getEntrymsg();
} else {
$messages[] = " " . $bot->buildMessage("No entry message set");
}
}
if ($o->getUrl()) {
$messages[] = " URL: " . $o->getUrl();
}
try {
$blog_manager = $this->getDI()->get('blog_manager');
if ($blog_manager->countPosts($o->getName()) > 0) {
$config = $this->getDI()->get('config');
$messages[] = " " . $bot->buildMessage("Blog") . ": " . $config->application->baseUri . 'canal/' . $o->getNamePretty() . '/blog';
}
} catch (\Exception $e) {
}
$allopts = $o->getOptions(false);
if ($allopts['forum'] === true) {
$config = $this->getDI()->get('config');
$s = $o->getSectionObj();
if ($s) {
$messages[] = " " . $bot->buildMessage("Forum") . ": " . $config->discourse->baseUri . '/c/' . $s->getSlug() . '/' . $o->getNamePretty();
}
}
if ($o->getEmail()) {
$messages[] = " " . $bot->buildMessage("Email") . ": " . $o->getEmail();
}
$messages[] = " " . $bot->buildMessage("Options") . ":";
foreach ($options as $opt => $v) {
$messages[] = " " . mb_strtoupper($opt) . ": " . $bot->buildMessage($v ? "Activated" : "Deactivated", []);
}
$messages[] = " " . $bot->buildMessage("Modes lock") . ": " . $o->getMlock();
} catch (\Exception $e) {
}
$messages[] = $bot->buildMessage("End of information from channel %channel%.", [
'channel' => $channel,
]);
return $messages;
}
public function checkAccess($channel, $identity)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$c = $irc_manager->getChannel($channel);
if ($c && isset($c['modes']) && preg_match('/(s|p)/', $c['modes'])) {
$o = $this->get($channel, true);
if ($o && mb_strtolower($o->getFounder()) == mb_strtolower($identity['selected_nick'])) {
return;
}
$a = Access::findFirst([
'channel = :channel: AND nick = :nick:',
'bind' => [
'channel' => mb_strtolower($channel),
'nick' => (isset($identity['selected_nick']) ? mb_strtolower($identity['selected_nick']) : ''),
],
]);
if ($a && $a->getLevel() > 0) {
return;
}
throw new Exception(null, ErrorCodes::ERR_CHANNEL_IS_PRIVATE);
}
}
public function getChannelsBySection($section, $limit = -1, $exclude = '')
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$minimum_nicks = $this->getDI()->get('config')->channels->important->minimum_nicks;
$list = Channel::find([
'section = :section:',
'bind' => [
'section' => $section,
],
]);
$temp = [];
foreach ($list as $o) {
if ($o->getIsSuspended() != 1) {
$obj = $irc_manager->getChannel($o->getName());
$sheet = $o->getDatasheet();
if ($sheet || $obj && isset($obj['modes']) && !preg_match('/(i|R|s|p|k)/', $obj['modes'])) {
if (mb_strtolower($o->getName()) != mb_strtolower($exclude)) {
$c = $obj && isset($obj['cnt_members']) ? $obj['cnt_members'] : 0;
if (!isset($temp[$c])) {
$temp[$c] = [];
}
$temp[$c][] = $o;
}
}
}
}
ksort($temp, SORT_NUMERIC);
$temp = array_reverse($temp, true);
$channels = [];
foreach ($temp as $i => $list) {
foreach ($list as $o) {
if ($i >= $minimum_nicks || $o->getDatasheet()) {
$channels[] = [
'obj' => $o,
'users' => $i,
];
}
}
}
if ($limit > 0) {
$channels = array_slice($channels, 0, $limit);
}
return $channels;
}
public function getRandomDatasheet()
{
$list = Datasheet::find([
'order' => 'RAND() DESC',
'limit' => 10,
]);
foreach ($list as $o) {
$c = $o->getChannelObj();
if ($c && $c->getSection() != 'ADU' && $c->getSection() != 'GAY' && $c->getSection() != 'LES') {
return $o;
}
}
return false;
}
public function createChannelSection($request)
{
$default = [
'parent' => new \Phalcon\Db\RawValue(''),
];
$dbTx = (new PhalconTxManager())->get();
$o = new ChannelSection();
if (is_array($request)) {
$o->assign(array_merge($default, $request));
} else {
$o->assign(array_merge($default, $request->getPost()));
}
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [
'message' => implode('. ', $o->getMessages()),
]);
}
if (!is_array($request)) {
$this->updateChannelSectionImages($request, true);
}
$dbTx->commit();
return $o;
}
public function saveChannelSection($request)
{
$default = [
'parent' => new \Phalcon\Db\RawValue(''),
];
$dbTx = (new PhalconTxManager())->get();
if (is_array($request)) {
$o = $this->getSection($request['code'] ?? '');
$o->assign(array_merge($default, $request));
} else {
$o = $this->getSection($request->getPost('code', 'string', ''));
$o->assign(array_merge($default, $request->getPost()));
}
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_UPDATE, [
'message' => implode('. ', $o->getMessages()),
]);
}
if (!is_array($request)) {
$this->updateChannelSectionImages($request, false);
}
$dbTx->commit();
return $o;
}
protected function updateChannelSectionImages($request, $require_files = false)
{
if (count($request->getUploadedFiles()) < 1) {
if (true === $require_files) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SECTION_CREATE, [
'message' => 'You missed to upload images.',
]);
} else {
return;
}
}
$cdn_config = $this->getDI()->get('config')->cdn->toArray();
$env = trim(file_get_contents(__DIR__ . '/../../../../config/environment.txt'));
foreach ($request->getUploadedFiles() as $file) {
if ($file->getName() == '') {
continue;
}
if ($file->getKey() == 'image_off' || $file->getKey() == 'image_on') {
if ($file->getKey() == 'image_off') {
$fname = $cdn_config['path'] . '/channels/sections/' . $request->getPost('code', 'string', '') . '-off.png';
} else {
$fname = $cdn_config['path'] . '/channels/sections/' . $request->getPost('code', 'string', '') . '-on.png';
}
Graphics::resizeW($file->getTempName(), $file->getTempName(), 1024);
Graphics::crop($file->getTempName(), $file->getTempName(), 0, 0, 1024, 520);
$file->moveTo($fname);
}
}
if ($env == 'prod') {
foreach ($request->getUploadedFiles() as $file) {
if ($file->getName() == '') {
continue;
}
if ($file->getKey() == 'image_off' || $file->getKey() == 'image_on') {
if ($file->getKey() == 'image_off') {
$fname = $cdn_config['path'] . '/channels/sections/' . $request->getPost('code', 'string', '') . '-off.png';
$name = $request->getPost('section', 'string', '') . '-off.png';
} else {
$fname = $cdn_config['path'] . '/channels/sections/' . $request->getPost('code', 'string', '') . '-on.png';
$name = $request->getPost('section', 'string', '') . '-on.png';
}
foreach ($cdn_config['nodes'] as $node) {
if ($this->request->getServerAddress() != $node['host']) {
try {
$cdn = new Cdn($node['host'], $node['user'], $node['passwd'], 'channels/sections');
$cdn->connect();
$cdn->upload([
$fname => $file->getName(),
]);
$cdn->disconnect();
} catch (\Exception $e) {
$this->getDI()->get('redis_cluster')->rPush('chathispano_ftp_pending', json_encode([
'server' => $node['host'],
'user' => $node['user'],
'passwd' => $node['passwd'],
'path' => $fname,
'folder' => 'channels/sections',
'name' => $name,
]));
}
}
}
}
}
}
}
public function getDatasheets()
{
return Datasheet::find([
'order' => 'channel ASC',
]);
}
public function getDatasheet($channel)
{
$o = Datasheet::findFirstByChannel($channel);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_NOT_FOUND, [
'name' => $channel,
]);
}
return $o;
}
public function getDatasheetBySlug($slug)
{
$o = Datasheet::findFirstBySlug($slug);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_NOT_FOUND, [
'name' => $slug,
]);
}
return $o;
}
public function getRandomDatasheets($amount = 10)
{
return Datasheet::find([
"section <> 'ADU' AND section <> 'GAY' AND section <> 'LES'",
'order' => 'RAND() DESC',
'limit' => $amount,
]);
}
public function createChannelDatasheet($request)
{
if (is_array($request)) {
$c = Channel::findFirstByName($request['channel'] ?? '');
} else {
$c = Channel::findFirstByName($request->getPost('channel', 'string', ''));
}
if (!$c) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_REQUIRE_REGISTERED_CHANNEL);
}
$dbTx = (new PhalconTxManager())->get();
$o = new Datasheet();
if (is_array($request)) {
$o->assign($request);
} else {
$o->assign($request->getPost());
}
$o->setSection($c->getSection());
if (false === $o->create()) {
$dbTx->rollback();
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_CREATE, [
'message' => implode('. ', $o->getMessages()),
]);
}
$dbTx->commit();
if (!is_array($request)) {
$this->updateChannelDatasheetImage($request, true);
}
return $o;
}
public function saveChannelDatasheet($request)
{
if (!is_array($request)) {
$dbTx = (new PhalconTxManager())->get();
}
if (is_array($request)) {
$o = $this->getDatasheetBySlug($request['slug'] ?? '');
$o->assign($request);
} else {
$o = $this->getDatasheetBySlug($request->getPost('slug', 'string', ''));
$o->assign($request->getPost());
}
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_UPDATE, [
'message' => implode('. ', $o->getMessages()),
]);
}
if (!is_array($request)) {
$this->updateChannelDatasheetImage($request, false);
$dbTx->commit();
}
return $o;
}
public function dropChannelDatasheet($slug)
{
$o = $this->getDatasheetBySlug($slug);
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_DELETE, [
'message' => implode('. ', $o->getMessages()),
]);
}
return $o;
}
protected function updateChannelDatasheetImage($request, $require_files = false)
{
if (count($request->getUploadedFiles()) < 1) {
if (true === $require_files) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_CREATE, [
'message' => 'You missed to upload images.',
]);
} else {
return;
}
}
$cdn_config = $this->getDI()->get('config')->cdn->toArray();
$path = $cdn_config['path'] . '/channels/datasheet/';
$env = trim(file_get_contents(__DIR__ . '/../../../../config/environment.txt'));
foreach ($request->getUploadedFiles() as $file) {
if ($file->getName() == '') {
continue;
}
if ($file->getKey() == 'image') {
Graphics::resizeW($file->getTempName(), $file->getTempName(), 1024);
$fname = mb_strtolower($request->getPost('slug', 'string', '')) . '.png';
$file->moveTo($path . $fname);
}
}
if ($env == 'prod') {
foreach ($request->getUploadedFiles() as $file) {
if ($file->getName() == '') {
continue;
}
if ($file->getKey() == 'image') {
$fname = mb_strtolower($request->getPost('slug', 'string', '')) . '.png';
foreach ($cdn_config['nodes'] as $node) {
if ($request->getServerAddress() != $node['host']) {
try {
$cdn = new Cdn($node['host'], $node['user'], $node['passwd'], 'channels/datasheet');
$cdn->connect();
$cdn->upload([
$path . $fname => $fname,
]);
$cdn->disconnect();
} catch (\Exception $e) {
$this->getDI()->get('redis_cluster')->rPush('chathispano_ftp_pending', json_encode([
'server' => $node['server'],
'user' => $node['user'],
'passwd' => $node['passwd'],
'path' => $path . $fname,
'folder' => 'channels/datasheet',
'name' => $fname,
]));
}
}
}
}
}
}
}
public function getOverrides()
{
return Override::find([
'order' => 'channel ASC',
]);
}
public function getOverride($channel)
{
$o = Override::findFirstByChannel($channel);
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_NOT_FOUND, [
'name' => $channel,
]);
}
return $o;
}
public function createChannelOverride($request)
{
if (is_array($request)) {
$o = Channel::findFirstByName($request['channel'] ?? '');
} else {
$o = Channel::findFirstByName($request->getPost('channel', 'string', ''));
}
if (!$o) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_REQUIRE_REGISTERED_CHANNEL);
}
$o = new Override();
if (is_array($request)) {
$o->assign($request);
} else {
$o->assign($request->getPost());
}
if (false === $o->create()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_CREATE, [
'message' => implode('. ', $o->getMessages()),
]);
}
return $o;
}
public function saveChannelOverride($request)
{
if (is_array($request)) {
$o = $this->getOverride($request['channel'] ?? '');
$o->assign($request);
} else {
$o = $this->getOverride($request->getPost('channel', 'string', ''));
$o->assign($request->getPost());
}
if (false === $o->save()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_UPDATE, [
'message' => implode('. ', $o->getMessages()),
]);
}
return $o;
}
public function dropChannelOverride($channel)
{
$o = $this->getOverride($channel);
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DATASHEET_DELETE, [
'message' => implode('. ', $o->getMessages()),
]);
}
return $o;
}
public function getBlogsData(User $o)
{
$data = [];
$blog_manager = $this->getDI()->get('blog_manager');
$nicks = $o->getNicks();
foreach ($nicks as $n) {
$channels = $n->getFounderChannels();
foreach ($channels as $c) {
// We skip if we have already granted access
if (isset($data[$c->getName()])) {
continue;
}
// It does not have access to post
if (!$this->checkBlogger($c, $n->getNick())) {
continue;
}
$last_post = $blog_manager->getLastChannelPost($c->getName(), true);
$data[$c->getNamePretty()] = [
'name' => $c->getName(),
'pretty_name' => $c->getNamePretty(),
'total_posts' => $blog_manager->countPosts($c->getName(), true),
'published_posts' => $blog_manager->countPosts($c->getName(), false),
'last_post_date' => $last_post ? $last_post->getUpdatedAt() : '-',
];
}
$channels = $n->getSuccessorChannels();
foreach ($channels as $c) {
// We skip if we have already granted access
if (isset($data[$c->getName()])) {
continue;
}
// It does not have access to post
if (!$this->checkBlogger($c, $n->getNick())) {
continue;
}
$last_post = $blog_manager->getLastChannelPost($c->getName(), true);
$data[$c->getNamePretty()] = [
'name' => $c->getName(),
'pretty_name' => $c->getNamePretty(),
'total_posts' => $blog_manager->countPosts($c->getName(), true),
'published_posts' => $blog_manager->countPosts($c->getName(), false),
'last_post_date' => $last_post ? $last_post->getUpdatedAt() : '-',
];
}
$channels = $n->getChannelRegisters();
foreach ($channels as $r) {
// We skip if we have already granted access
if (isset($data[$r->getChannel()])) {
continue;
}
// It does not have access to post
if (!$this->checkBlogger($r->getChannel(), $n->getNick())) {
continue;
}
$last_post = $blog_manager->getLastChannelPost($r->getChannel(), true);
$data[$r->getChannelPretty()] = [
'name' => $r->getChannel(),
'pretty_name' => $r->getChannelPretty(),
'total_posts' => $blog_manager->countPosts($r->getChannel(), true),
'published_posts' => $blog_manager->countPosts($r->getChannel(), false),
'last_post_date' => $last_post ? $last_post->getUpdatedAt() : '-',
];
}
}
return $data;
}
public function getForumsData(User $o)
{
$data = [];
$nicks = $o->getNicks();
foreach ($nicks as $n) {
$channels = $n->getFounderChannels();
foreach ($channels as $c) {
// We skip if we have already granted access
if (isset($data[$c->getName()])) {
continue;
}
// It does not have access to post
if (!$this->checkForum($c, $n->getNick())) {
continue;
}
$options = $c->getOptions();
$data[$c->getNamePretty()] = [
'name' => $c->getName(),
'pretty_name' => $c->getNamePretty(),
'activated' => $options && is_array($options) && isset($options['forum']) ? $options['forum'] : false,
'section_slug' => $c->getSectionObj() ? $c->getSectionObj()->getSlug() : '',
];
}
$channels = $n->getSuccessorChannels();
foreach ($channels as $c) {
// We skip if we have already granted access
if (isset($data[$c->getName()])) {
continue;
}
// It does not have access to post
if (!$this->checkForum($c, $n->getNick())) {
continue;
}
$options = $c->getOptions();
$data[$c->getNamePretty()] = [
'name' => $c->getName(),
'pretty_name' => $c->getNamePretty(),
'activated' => $options && is_array($options) && isset($options['forum']) ? $options['forum'] : false,
'section_slug' => $c->getSectionObj() ? $c->getSectionObj()->getSlug() : '',
];
}
$channels = $n->getChannelRegisters();
foreach ($channels as $r) {
// We skip if we have already granted access
if (isset($data[$r->getChannel()])) {
continue;
}
// It does not have access to post
if (!$this->checkForum($r->getChannel(), $n->getNick())) {
continue;
}
$c = $r->getChannelObj();
$options = $c->getOptions();
$data[$r->getChannelPretty()] = [
'name' => $r->getChannel(),
'pretty_name' => $r->getChannelPretty(),
'activated' => $options && is_array($options) && isset($options['forum']) ? $options['forum'] : false,
'section_slug' => $c->getSectionObj() ? $c->getSectionObj()->getSlug() : '',
];
}
}
return $data;
}
public function activateForum($name, $nick, $ip)
{
$o = $this->get($name, true);
if ($o->getIsSuspended() == 1) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_SUSPENDED);
}
$nick_manager = $this->getDI()->get('inspircd_nick_manager');
if (false === $this->checkLevel($o, 'FORUM', $nick)) {
try {
$nick_manager->checkOperator($nick, 'devel');
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_ACCESS_DENIED);
}
}
try {
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->createChannel($o);
$this->setOption($name, 'ChatHispano', 'forum', 'on', '127.0.0.1', false);
} catch (\Exception $e) {
throw new Exception(null, ErrorCodes::ERR_SERVICES_UNKNOWN, [
'code' => $e->getMessage(),
]);
}
return $o;
}
protected function expireAkickList($list, $type, &$updatedChannels)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$redis = $this->getDI()->get('redis_cluster');
foreach ($list as $o) {
try {
if (false === $o->delete()) {
$msg = "\x02\x034[ERROR] [AKICK] [EXPIRE]\x03 Channel=\x02 " . $o->getChannel() . "\x02 Mask=\x02 " . $o->getMask() . "\x02 Message=\x02 " . join(". ", $o->getMessages());
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg);
} else {
$redis->set('chathispano_inspircd_akick_delete_' . str_replace('#', '', $o->getChannel()) . '_' . $o->getMask(), 1, 3600 * 24);
if (!in_array($o->getChannel(), $updatedChannels)) {
$updatedChannels[] = $o->getChannel();
}
$msg = "\x02[AKICK] [EXPIRE] Channel=\x02 " . $o->getChannel() . "\x02 Mask=\x02 " . $o->getMask() . "\x02 Date=\x02 " . $o->getCreatedOn() . "\x02 Hits=\x02 " . $o->getHits() . "\x02 LastHit=\x02 " . $o->getLastHit() . "\x02 Type=\x02 " . $type;
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#chan', $msg);
$irc_manager->noticeOrderEnqueue('AAAAAA', '@' . $o->getChannel(), "El akick " . $o->getMask() . " ha expirado");
$this->createHistory($o->getChannel(), History::EVENT_AKICK_EXPIRE, '127.0.0.1', [
$o->getMask(),
]);
}
} catch (\Exception $e) {
$msg = "\x02\x034[ERROR] [AKICK] [EXPIRE]\x03 Channel=\x02 " . $o->getChannel() . "\x02 Mask=\x02 " . $o->getMask() . "\x02 Message=\x02 " . $e->getMessage();
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg);
}
}
}
protected function expireNegativeRegisters($list, $type, &$updatedChannels)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$redis = $this->getDI()->get('redis_cluster');
foreach ($list as $o) {
try {
if (false === $o->delete()) {
$msg = "\x02\x034[ERROR] [ACCESS] [EXPIRE]\x03 Channel=\x02 " . $o->getChannel() . "\x02 Nick=\x02 " . $o->getNick() . "\x02 Message=\x02 " . join(". ", $o->getMessages());
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg);
} else {
$redis->set('chathispano_inspircd_negative_registers_delete_' . str_replace('#', '', $o->getChannel()) . '_' . $o->getNick(), 1, 3600 * 24);
if (!in_array($o->getChannel(), $updatedChannels)) {
$updatedChannels[] = $o->getChannel();
}
$msg = "\x02[ACCESS] [EXPIRE] Channel=\x02 " . $o->getChannel() . "\x02 Nick=\x02 " . $o->getNick() . "\x02 Date=\x02 " . date('Y-m-d H:i:s', $o->getSetOn()) . "\x02 LastHit=\x02 " . date('Y-m-d H:i:s', $o->getLastUse()) . "\x02 Type=\x02 " . $type;
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#chan', $msg);
$irc_manager->noticeOrderEnqueue('AAAAAA', '@' . $o->getChannel(), "El registro -1 " . $o->getNick() . " ha expirado");
$this->createHistory($o->getChannel(), History::EVENT_ACCESS_EXPIRE, '127.0.0.1', [
$o->getNick(),
]);
}
} catch (\Exception $e) {
$msg = "\x02\x034[ERROR] [ACCESS] [EXPIRE]\x03 Channel=\x02 " . $o->getChannel() . "\x02 Nick=\x02 " . $o->getNick() . "\x02 Message=\x02 " . $e->getMessage();
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg);
}
}
}
public function expireAkicks()
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$updatedChannels = [];
// Expire akicks with no use and 7 days age
$list = Akick::find([
"hits = 0 AND created_on < :date:",
"bind" => [
"date" => date('Y-m-d H:i:s', strtotime("now -7 days")),
],
"order" => "channel ASC",
]);
$this->expireAkickList($list, 'NOHITS', $updatedChannels);
// Expire akicks with no hits in the last 30 days
$list = Akick::find([
"hits > 0 AND last_hit < :date:",
"bind" => [
"date" => date('Y-m-d H:i:s', strtotime("now -30 days")),
],
"order" => "channel ASC",
]);
$this->expireAkickList($list, 'NOHITS30D', $updatedChannels);
// Expire akicks with 90 days age
$list = Akick::find([
"created_on < :date:",
"bind" => [
"date" => date('Y-m-d H:i:s', strtotime("now -90 days")),
],
"order" => "channel ASC",
]);
$this->expireAkickList($list, '90DOLD', $updatedChannels);
$list = Access::find([
'level = -1 AND set_on < :date: AND last_use IS NULL',
'bind' => [
"date" => strtotime("now -7 days"),
],
'order' => 'channel ASC',
]);
$this->expireNegativeRegisters($list, 'NOHITS', $updatedChannels);
$list = Access::find([
'level = -1 AND last_use IS NOT NULL AND last_use < :date:',
'bind' => [
"date" => strtotime("now -30 days"),
],
'order' => 'channel ASC',
]);
$this->expireNegativeRegisters($list, 'NOHITS30D', $updatedChannels);
$list = Access::find([
'level = -1 AND set_on < :date:',
'bind' => [
"date" => strtotime("now -90 days"),
],
'order' => 'channel ASC',
]);
$this->expireNegativeRegisters($list, '90OLD', $updatedChannels);
// Send updated channels to servers
foreach ($updatedChannels as $channel) {
$o = Channel::findFirst([
"name = :name:",
"bind" => [
"name" => $channel,
],
]);
if (!$o) {
$msg = "\x02\x034[ERROR] [AKICK] [EXPIRE]\x03 Channel=\x02 " . $channel . "\x02 Message=\x02 Channel not found";
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg);
} else {
$this->enqueue($o);
}
}
}
protected function expireSuspend(Channel $o)
{
$dbTx = (new PhalconTxManager())->get();
try {
$this->update($o, [
'is_suspended' => 0,
'suspend_by' => new \Phalcon\Db\RawValue("NULL"),
'suspend_reason' => new \Phalcon\Db\RawValue("NULL"),
'suspend_ts' => new \Phalcon\Db\RawValue("NULL"),
'suspend_duration' => new \Phalcon\Db\RawValue("NULL"),
]);
$discourse_manager = $this->getDI()->get('discourse_manager');
$discourse_manager->updateChannel($o->getName());
$this->setStatus($o->getName(), Status::STATUS_REGISTERED, '127.0.0.1', $o->getFounder());
$c = $this->get($o->getName(), true);
$this->createHistory($o->getName(), History::EVENT_EXPIRE_SUSPEND, '127.0.0.1', []);
$this->enqueue($c);
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$msg = "\x02[SUSPEND] [EXPIRE] Channel=\x02 " . $o->getName();
$irc_manager->privmsgOrderEnqueue('AAAAAA', $this->getDI()->get('config')->irc->bots->chan->debug_channel, $msg);
$dbTx->commit();
} catch (\Exception $e) {
$dbTx->rollback();
}
}
public function expireSuspends($console)
{
$list = $this->listSuspendExpired();
$cnt = 0;
foreach ($list as $o) {
try {
$this->expireSuspend($o);
$cnt++;
} catch (\Exception $e) {
$dbTx = (new PhalconTxManager())->get();
$dbTx->rollback();
}
}
$console->consoleLog(">>> Expired " . $cnt . " channel suspends", 'yellow');
}
protected function expireChannel(Channel $o)
{
$dbTx = (new PhalconTxManager())->get();
try {
$founder = $o->getFounderObj();
if (false === $o->delete()) {
throw new Exception(null, ErrorCodes::ERR_CHANNEL_DELETE, [
'message' => join('. ', $o->getMessages()),
]);
}
$this->setStatus($o->getName(), Status::STATUS_NOT_REGISTERED, '127.0.0.1', 'CHaN');
$this->createHistory($o->getName(), History::EVENT_EXPIRED, '127.0.0.1', []);
$this->enqueueDelete($o);
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$msg = "\x02\x034[EXPIRED]\x03 Name=\x02 " . $o->getName() . "\x02 Last use=\x02 " . date('Y-m-d H:i:s', $o->getTimeLastUse());
$irc_manager->privmsgOrderEnqueue('AAAAAA', $this->getDI()->get('config')->irc->bots->chan->debug_channel, $msg);
if ($founder) {
$mailer = $this->getDI()->get('mail');
$mailer->addTo($founder->getEmail());
$mailer->setLanguage('es');
$mailer->send(
'Chat Hispano',
'[ChatHispano] El canal ' . $o->getName() . ' ha expirado',
'channel_expired',
null,
[
'name' => $o->getName(),
'nick' => $founder->getEmail(),
'last_use' => date('Y-m-d H:i:s', $o->getTimeLastUse()),
'expire_days' => self::CHANNEL_EXPIRE_DAYS,
'images' => [
'logo' => 'public/assets/backoffice/img/logo-medium.jpg',
],
]
);
}
$dbTx->commit();
} catch (\Exception $e) {
$dbTx->rollback();
}
}
protected function expireWarnChannel(Channel $o)
{
$this->setOption($o->getName(), 'ChatHispano', 'expirewarn', 'on', '127.0.0.1', false);
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$msg = "\x02\x038[EXPIRE WARN]\x03 Name=\x02 " . $o->getName() . "\x02 Last use=\x02 " . date('Y-m-d H:i:s', $o->getTimeLastUse());
$irc_manager->privmsgOrderEnqueue('AAAAAA', $this->getDI()->get('config')->irc->bots->chan->debug_channel, $msg);
$founder = $o->getFounderObj();
if ($founder) {
$mailer = $this->getDI()->get('mail');
$mailer->addTo($founder->getEmail());
$mailer->setLanguage('es');
$mailer->send(
'Chat Hispano',
'[ChatHispano] Aviso de expiración del canal ' . $o->getName(),
'channel_expire_warn',
null,
[
'name' => $o->getName(),
'nick' => $founder->getEmail(),
'last_use' => date('Y-m-d H:i:s', $o->getTimeLastUse()),
'expire_days' => self::CHANNEL_EXPIRE_DAYS,
'images' => [
'logo' => 'public/assets/backoffice/img/logo-medium.jpg',
],
]
);
}
}
public function expire($console)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$expire_ts = time() - (self::CHANNEL_EXPIRE_DAYS * 24 * 3600);
$expire_warn = time() - (self::CHANNEL_WARN_EXPIRE_DAYS * 24 * 3600);
$list = Channel::find([
'time_last_use < :time_last_use:',
'bind' => [
'time_last_use' => $expire_warn,
],
]);
$cnt = 0;
$warn = 0;
$suspended = 0;
$noexpire = 0;
foreach ($list as $o) {
try {
$options = $o->getOptions();
if ($o->getIsSuspended() == 1) {
/**
* We do not expire suspended channels
*/
$suspended++;
continue;
}
if ($o->getIg() == 1 || $options['noexpire'] === true) {
/**
* We do not expire IG channels or with NOEXPIRE
*/
$noexpire++;
continue;
}
if ($o->getTimeLastUse() == null || $o->getTimeLastUse() < $expire_ts) {
$this->expireChannel($o);
$cnt++;
} else {
if ($options['expirewarn'] === true) {
/**
* Channel is already warned
*/
continue;
}
$this->expireWarnChannel($o);
$warn++;
}
} catch (\Exception $e) {
$console->consoleLog(">>> Error: " . $e->getMessage() . " " . $e->getCode(), 'red');
$msg = "\x02\x038[ERROR]\x03 Message=\x02 " . $e->getMessage();
$irc_manager->privmsgOrderEnqueue('AAAAAA', '#debug', $msg);
}
}
$console->consoleLog(">>> Not expiring " . $suspended . " SUSPENDED channels", 'green');
$console->consoleLog(">>> Not expiring " . $noexpire . " channels with NOEXPIRE", 'green');
$console->consoleLog(">>> Total " . $warn . " channels warned", 'yellow');
$console->consoleLog(">>> Total " . $cnt . " channels expired", 'red');
}
protected function enqueueDelete(Channel $o)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$data = [
'DATATYPE' => 'DELETE',
'obj' => [
'obj' => 'CHANNEL',
'key' => $o->getName(),
],
];
$irc_manager->dataEnqueue($data);
}
public function enqueue(Channel $o)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$data = $o->socketExport();
$data['DATATYPE'] = 'CHANNEL';
$irc_manager->dataEnqueue($data);
}
protected function enqueueIdentify(Channel $o, $nick, $status)
{
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$n = $irc_manager->getNick($nick);
if ($n) {
$irc_manager->dataEnqueue([
'DATATYPE' => 'IDENTIFY',
'channel' => $o->getName(),
'nick' => $nick,
'status' => $status,
], $n['server_name']);
}
}
}
|
| #14 | ChatHispanoEngine\Core\Managers\InspIRCd\ChannelManager->getRandomDatasheets /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Controllers/BaseController.php (259) <?php
namespace ChatHispanoEngine\Web\Controllers;
use ChatHispanoEngine\Core\Controllers\BaseController as CoreController;
use ChatHispanoEngine\Core\Library\Util;
use ChatHispanoEngine\Core\Library\Irc\IP;
use ChatHispanoEngine\Core\Models\InspIRCd\Channel;
class BaseController extends CoreController
{
protected $private_controllers = [
'profile',
];
protected $private_actions = [
'paywall' => [
'checkoutSuccessPaypal',
],
];
protected $time_start;
protected $enable_moment = false;
protected $enable_editor = false;
protected $enable_charts = false;
protected $head_title;
protected $head_suffix;
protected $meta_description;
protected $meta_site_name;
protected $meta_show_image;
protected $meta_image;
protected $meta_twitter_profile;
protected $meta_facebook_id;
protected $meta_noindex;
protected $meta_nofollow;
protected $meta_article;
protected $meta_article_tags;
protected $meta_article_section;
protected $meta_article_created;
protected $meta_article_updated;
protected $rel_canonical;
protected function getDefaultMetaTags()
{
$config = $this->getDI()->get('config');
$this->head_title = $config->seo->head_title;
$this->head_suffix = $config->seo->head_suffix;
$this->meta_description = $config->seo->meta_description;
$this->meta_site_name = $config->seo->meta_site_name;
$this->meta_show_image = true;
$this->meta_image = $config->seo->meta_image;
$this->meta_twitter_profile = $config->seo->meta_twitter_profile;
$this->meta_facebook_id = $config->seo->meta_facebook_id;
$this->meta_noindex = $this->env == 'prod' ? false : true;
$this->meta_nofollow = false;
$this->article = false;
$this->rel_canonical = 'https://'
. $this->request->getServer('SERVER_NAME')
. ($this->request->getServer('REQUEST_URI') == '/' ? '' : $this->request->getServer('REQUEST_URI'));
$controller = $this->dispatcher->getControllerName();
$action = $this->dispatcher->getActionName();
$seo = $config->seo->controllers->toArray();
if (isset($seo[$controller]) && isset($seo[$controller][$action])) {
$this->head_title = $seo[$controller][$action]['title'];
$this->meta_description = $seo[$controller][$action]['description'];
if (isset($seo[$controller][$action]['nofollow']) && true === $seo[$controller][$action]['nofollow']) {
$this->setMetaNofollow(true);
}
}
}
protected function setArticleMeta(array $meta_article_tags, $meta_article_section, $meta_article_created, $meta_article_updated)
{
$this->meta_article = true;
$this->meta_article_tags = $meta_article_tags;
$this->meta_article_section = $meta_article_section;
$this->meta_article_created = $meta_article_created;
$this->meta_article_updated = $meta_article_updated;
}
protected function setHeadTitle($head_title)
{
$this->head_title = $head_title;
}
protected function setMetaDescription($meta_description)
{
$this->meta_description = $meta_description;
}
protected function setMetaSiteName($meta_site_name)
{
$this->meta_site_name = $meta_site_name;
}
protected function setMetaImage($meta_image)
{
$this->meta_image = $meta_image;
}
protected function setMetaNofollow($meta_nofollow)
{
$this->meta_nofollow = $meta_nofollow;
}
protected function setMetaNoindex($meta_noindex)
{
$this->meta_noindex = $meta_noindex;
}
protected function setRelCanonical($rel_canonical)
{
$this->rel_canonical = $rel_canonical;
}
protected function setMetaTags()
{
$this->view->head_title = $this->head_title;
$this->view->head_suffix = $this->head_suffix;
$this->view->meta_description = $this->meta_description;
$this->view->meta_site_name = $this->meta_site_name;
$this->view->meta_show_image = $this->meta_show_image;
$this->view->meta_image = $this->meta_image;
$this->view->meta_facebook_id = $this->meta_facebook_id;
$this->view->meta_twitter_profile = $this->meta_twitter_profile;
$this->view->meta_noindex = $this->meta_noindex;
$this->view->meta_nofollow = $this->meta_nofollow;
$this->view->meta_article = $this->meta_article;
if ($this->meta_article) {
$this->view->meta_article_tags = $this->meta_article_tags;
$this->view->meta_article_section = $this->meta_article_section;
$this->view->meta_article_created = $this->meta_article_created;
$this->view->meta_article_updated = $this->meta_article_updated;
}
$this->view->rel_canonical = $this->rel_canonical;
}
public function beforeExecuteRoute($dispatcher)
{
$this->view->cdn_uri = $this->config->cdn->baseUri;
$this->translate->setDefaultDomain('web');
$controller = $this->dispatcher->getControllerName();
$action = $this->dispatcher->getActionName();
if ($controller == 'auth'
&& $action != 'session'
&& $action != 'logout'
&& $action != 'setNick'
&& $action != 'registerCompleted'
&& true === $this->auth->isUserSignedIn()) {
$this->response->redirect('');
return false;
}
$this->view->section_sex = 0;
$this->view->section_gay = 0;
$this->view->section_lesbianas = 0;
if (false === $this->auth->isUserSignedIn()
&& (in_array($controller, $this->private_controllers)
|| (isset($this->private_actions[$controller]) && in_array($action, $this->private_actions[$controller])))) {
$this->flashSession->warning($this->_t('You have to login to access to this module.'));
$this->response->redirect('auth/login');
$this->session->set('web_redirect_after_login', $this->request->getQuery('_url'));
$dispatcher->forward([
'controller' => 'auth',
'action' => 'login',
]);
return false;
}
if ($controller == 'auth') {
$redir = $this->request->getQuery('redir', 'string', '');
if ($redir != '') {
if ($action == 'login') {
$this->session->set('web_redirect_after_login', $redir);
$this->session->remove('web_redirect_after_register');
} elseif ($action == 'register') {
$this->session->remove('web_redirect_after_login');
$this->session->set('web_redirect_after_register', $redir);
}
}
}
/*
* Getting environment and common template variables
*/
$this->getEnvironment();
/*
* Building assets
*/
if ($controller == 'webchat') {
$this->buildWebchatAssets();
} else {
$this->buildAssets();
}
if ($this->auth->isUserSignedIn() || $this->auth->checkAuthCookie()) {
$this->view->loggedIn = true;
$this->view->identity = $this->auth->syncIdentity();
$identity = $this->auth->getIdentity();
$this->view->loggedInUser = $this->getDI()->get('user_manager')->getByEmail($identity['email']);
$this->view->hasPremium = $this->view->loggedInUser->hasSubscriptionType('premium');
if ($this->view->hasPremium) {
$s = $this->view->loggedInUser->getSubscriptionType('premium');
if ($s->getSettings()['status'] == 'enabled') {
$this->view->premiumSubscription = $s->getPlan()->getSlug();
} else {
$this->view->hasPremium = false;
$this->view->premiumSubscription = false;
}
} else {
$this->view->premiumSubscription = false;
}
} else {
$this->view->loggedIn = false;
$this->view->hasPremium = false;
}
$this->getDefaultMetaTags();
$this->view->rating_avg = 4.9;
$this->view->rating_best = 5;
$this->view->rating_total = 5982;
$this->view->client_ip = $this->request->getClientAddress();
$this->view->client_real_ip = $this->request->getClientAddress(true);
try {
$this->view->gline = $this->getDI()->get('inspircd_gline_manager')->findActiveByIp($this->view->client_real_ip);
} catch (\Exception $e) {
}
$this->view->controller = $controller;
$this->view->action = $action;
$this->view->backLink = $this->request->getServer('HTTP_REFERER');
$this->view->baseUri = $this->config->application->baseUri;
$queryString = $_SERVER['QUERY_STRING'] ?? '/';
$this->view->fullUri = $this->config->application->baseUri . substr($queryString, 1);
$this->view->supportUri = $this->config->application->supportUri;
$this->view->locale = $this->translate->getLanguage();
$this->view->chatmovilUri = $this->config->application->chatmovilUri;
$this->view->kiwiUri = $this->config->application->kiwiUri;
$this->view->current_year = date('Y');
$this->view->facebook_app_id = $this->config->facebook->app_id;
/**
* Random channel datasheets
*/
$this->view->random_channels = $this->getDI()->get('inspircd_channel_manager')->getRandomDatasheets(3);
// Special content type in utils controller
if ($this->view->controller == 'utils') {
if ($this->view->action == 'sitemap') {
$this->response->setHeader('Content-Type', 'text/xml; charset=utf-8');
} else {
$this->response->setHeader('Content-Type', 'text/plain; charset=utf-8');
}
} else {
$this->response->setHeader('Content-Type', 'text/html; charset=utf-8');
}
$this->view->cdnUri = $this->config->cdn->baseUri;
// Ads config
$this->view->ads_revive_enabled = false;
if ($this->view->controller == 'stats' || ($this->view->controller == 'channel' && $this->view->action == 'stats') || $this->view->controller == 'stories') {
$this->view->ads_revive_enabled = true;
}
$this->view->ads_onnetwork_enabled = true;
// Always disabled
$this->view->ads_optimanetwork_enabled = false;
$this->view->refinery89_enabled = false;
// Vivelavita ads
$this->view->vivelavita = $this->getDI()->get('vivelavita_manager');
// Detect crawlers
if ($this->env == 'prod') {
$crawler_detector = new \Jaybizzle\CrawlerDetect\CrawlerDetect();
if ($crawler_detector->isCrawler()) {
$this->view->ads_onnetwork_enabled = false;
$this->view->ads_revive_enabled = true;
} else {
// Detect HOSTING / VPN
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$geo = $irc_manager->get_geoip($this->request->getClientAddress(true));
$continents = ['OC', 'AS', 'AF'];
if ($geo && is_array($geo) && ($geo['proxy'] || $geo['hosting'] || in_array($geo['continent_code'], $continents))) {
$this->view->ads_onnetwork_enabled = false;
$this->view->ads_revive_enabled = true;
} elseif (!$geo || !is_array($geo)) {
$this->view->ads_onnetwork_enabled = false;
$this->view->ads_revive_enabled = true;
}
}
}
// We add this to make revive work
if (true === $this->view->ads_revive_enabled) {
$this->response->setHeader('Access-Control-Allow-Origin', $this->request->getHTTPReferer());
}
// Wechat version
$this->view->enable_element = $this->config->webchat->enable_element;
// Underage wall
$underage_wall_exceptions = [
'/condiciones',
'/lopd',
'/normas/politica-de-cookies',
'/contactar',
'/quejas',
'/ayuda',
];
foreach ($underage_wall_exceptions as $uri) {
if (str_starts_with($_SERVER['REQUEST_URI'], $uri)) {
$this->view->disable_underage_wall = 1;
break;
}
}
// Paywall promo
$promo_enabled = $this->config->paywall->promo->enabled;
$promo_start_time = $this->config->paywall->promo->start_time;
$promo_end_time = $this->config->paywall->promo->end_time;
$this->view->paywall_promo_enabled = $promo_enabled && time() >= strtotime($promo_start_time) && time() <= strtotime($promo_end_time);
$this->view->paywall_promo_image = $this->config->paywall->promo->image;
$this->view->paywall_promo_button_link = $this->config->paywall->promo->button_link;
$this->view->paywall_promo_keyword_header = $this->_t($this->config->paywall->promo->keyword_header);
$this->view->paywall_promo_keyword_description = $this->_t($this->config->paywall->promo->keyword_description);
}
public function afterExecuteRoute($dispatcher)
{
$this->view->enable_moment = $this->enable_moment;
$this->view->enable_charts = $this->enable_charts;
$this->view->enable_editor = $this->enable_editor;
/*
* Default META tags
*/
$this->setMetaTags();
}
public function goToLastPage()
{
$this->response->redirect($this->request->getServer('HTTP_REFERER'));
}
/**
* Translator.
*
* @param string $message
*/
protected function _t($message, $vars = null)
{
return $this->translate->translate($message, $vars, 'web');
}
protected function buildResponse()
{
$response = (new \Phalcon\Http\Response())
->setStatusCode(200, 'OK')
->setHeader('Access-Control-Allow-Headers', 'X-Requested-With');
return $response;
}
protected function checkSection($section)
{
$sex = 0;
$gay = 0;
$lesbianas = 0;
switch ($section) {
case 'ADU':
$sex = 1;
break;
case 'LES':
$lesbianas = 1;
break;
case 'GAY':
$gay = 1;
break;
default:
break;
}
$this->view->section_sex = $sex;
$this->view->section_gay = $gay;
$this->view->section_lesbianas = $lesbianas;
}
protected function checkChannelSection(Channel $channel)
{
/**
* Getting section to know if it is a sex/gay/lesb channel or not
* to put different ad zones (#1471)
*/
$lesbianas = 0;
$gay = 0;
$sex = 0;
if ($channel) {
$options = $channel->getOptions();
if ($options['noads'] == 1 || $options['noads'] == '1') {
/**
* If ads are manually disabled, we mark as adults to avoid showing ads
*/
$sex = 1;
} else {
try {
$section = $channel->getSectionObj();
if ($section) {
switch ($section->getCode()) {
case 'ADU':
$sex = 1;
break;
case 'LES':
$lesbianas = 1;
break;
case 'GAY':
$gay = 1;
break;
default:
break;
}
} else {
$debug_channel = $this->config->irc->opers_channel;
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$irc_manager->privmsgOrderEnqueue('AAAAAA', $debug_channel, "El canal\x02 " . $channel->getName() . "\x02 no tiene sección en la BBDD");
$sex = 1;
}
} catch (\Exception $e) {
/**
* If we catch an error getting section, we avoid ads
*/
$sex = 1;
}
}
} else {
/**
* If there is no channel, we avoid ads
*/
$sex = 1;
}
$this->view->section_sex = $sex;
$this->view->section_gay = $gay;
$this->view->section_lesbianas = $lesbianas;
}
protected function buildWebchatAssets()
{
$this->assets->collection('webchatCss')
->addInlineCss(file_get_contents(__DIR__ . '/../../../public/assets/compiled/webchatCss.min.css'));
$this->assets->collection('webchatJs')
->addInlineJs(file_get_contents(__DIR__ . '/../../../public/assets/compiled/webchatJs.min.js'));
$this->assets->collection('wpluginJs')
->addInlineJs(file_get_contents(__DIR__ . '/../../../public/assets/compiled/wpluginJs.min.js'));
}
protected function buildAssets()
{
$this->assets->collection('headerCss')
->addInlineCss(file_get_contents(__DIR__ . '/../../../public/assets/compiled/headerCss.min.css'));
$this->assets->collection('mainJs')
->addInlineJs(file_get_contents(__DIR__ . '/../../../public/assets/compiled/mainJs.min.js'));
$this->assets->collection('pluginJs')
->addInlineJs(file_get_contents(__DIR__ . '/../../../public/assets/compiled/pluginJs.min.js'));
if ($this->enable_moment === true) {
$this->assets->collection('momentJs')
->addInlineJs(file_get_contents(__DIR__ . '/../../../public/assets/compiled/momentJs.min.js'));
}
if ($this->enable_charts === true) {
$this->assets->collection('chartJs')
->addInlineJs(file_get_contents(__DIR__ . '/../../../public/assets/compiled/chartJs.min.js'));
}
if ($this->enable_editor === true) {
$baseUri = $this->config->application->baseUri;
$this->assets->collection('ckeditorJs')
->addJs('assets/web/plugins/ckeditor/ckeditor.js')
->addJs('assets/web/plugins/ckeditor/lang/en.js')
->addJs('assets/web/plugins/ckeditor/lang/es.js')
->addJs('assets/web/plugins/ckeditor/lang/ca.js')
->addJs('assets/web/js/ckeditor/youtube/plugin.js')
->addJs('assets/web/js/ckeditor/youtube/lang/en.js')
->addJs('assets/web/js/ckeditor/youtube/lang/es.js');
}
}
}
|
| #15 | ChatHispanoEngine\Web\Controllers\BaseController->beforeExecuteRoute |
| #16 | Phalcon\Dispatcher\AbstractDispatcher->dispatch |
| #17 | Phalcon\Mvc\Application->handle /srv/ChatHispanoEngine/releases/20250927141530/apps/Application.php (150) <?php
// namespace ChatHispanoEngine;
/**
* Application driver class to initialize Phalcon and
* other resources.
*/
class Application extends \Phalcon\Mvc\Application
{
private static $mode = 'dev';
private static $DEFAULT_MODULE = 'api';
public const MODE_PRODUCTION = 'prod';
public const MODE_STAGING = 'staging';
public const MODE_TEST = 'test';
public const MODE_DEVELOPMENT = 'dev';
/**
* Set application mode and error reporting level.
*/
public function __construct($defaultModule, $env = 'dev')
{
$this->modules = array(
'core' => array(
'className' => 'ChatHispanoEngine\Core\Module',
'path' => __DIR__.'/Core/Module.php',
),
'api' => array(
'className' => 'ChatHispanoEngine\Api\Module',
'path' => __DIR__.'/Api/Module.php',
),
'login' => array(
'className' => 'ChatHispanoEngine\Login\Module',
'path' => __DIR__.'/Login/Module.php',
),
'oidc' => array(
'className' => 'ChatHispanoEngine\Oidc\Module',
'path' => __DIR__.'/Oidc/Module.php',
),
'web' => array(
'className' => 'ChatHispanoEngine\Web\Module',
'path' => __DIR__.'/Web/Module.php',
),
'backoffice' => array(
'className' => 'ChatHispanoEngine\Backoffice\Module',
'path' => __DIR__.'/Backoffice/Module.php',
),
'movil' => array(
'className' => 'ChatHispanoEngine\Movil\Module',
'path' => __DIR__.'/Movil/Module.php',
),
'regwebexternal' => array(
'className' => 'ChatHispanoEngine\RegWebExternal\Module',
'path' => __DIR__.'/Regwebexternal/Module.php',
),
'cdn' => array(
'className' => 'ChatHispanoEngine\Cdn\Module',
'path' => __DIR__.'/Cdn/Module.php',
),
'shorten' => array(
'className' => 'ChatHispanoEngine\Shorten\Module',
'path' => __DIR__.'/Shorten/Module.php',
),
);
static::$DEFAULT_MODULE = $defaultModule;
self::$mode = $env;
self::$mode = trim(file_get_contents(__DIR__.'/../config/environment.txt'));
define('ENVIRONMENT', self::$mode);
if (!defined('PHALCON_MODE')) {
$mode = getenv('PHALCON_MODE');
$mode = $mode ? $mode : self::$mode;
define('PHALCON_MODE', $mode);
}
switch (self::getMode()) {
case self::MODE_PRODUCTION:
case self::MODE_STAGING:
error_reporting(0);
break;
case self::MODE_TEST:
case self::MODE_DEVELOPMENT:
ini_set('display_errors', 'On');
error_reporting(E_ALL);
break;
}
}
/**
* Register the services here to make them general or register in
* the ModuleDefinition to make them module-specific.
*/
protected function _registerServices()
{
$defaultModule = self::$DEFAULT_MODULE;
$modules = $this->modules;
$config = include __DIR__.'/../config/config.php';
$env_config = include __DIR__.'/../config/config_'.ENVIRONMENT.'.php';
$config->merge($env_config);
$di = new \Phalcon\DI\FactoryDefault();
include __DIR__.'/../config/loader.php';
include __DIR__.'/../config/services.php';
include __DIR__.'/../config/routing.php';
$this->setDI($di);
}
/**
* Run the application.
*/
public function main()
{
if (static::MODE_PRODUCTION === static::getMode()) {
$this->mainProd();
} else {
$this->mainDev();
}
}
private function getRequestUri()
{
if (!isset($_SERVER)) {
return "/";
}
if (!is_array($_SERVER)) {
return "/";
}
if (!isset($_SERVER['REQUEST_URI'])) {
return "/";
}
return $_SERVER['REQUEST_URI'];
}
/**
* Run the development environment.
*/
private function mainDev()
{
(new \Phalcon\Support\Debug())->listen();
$this->_registerServices();
$this->registerModules($this->modules);
$response = $this->handle($this->getRequestUri());
$response->send();
}
/**
* Run the production environment.
*/
private function mainProd()
{
try {
$this->registerModules($this->modules);
$this->_registerServices();
$response = $this->handle($this->getRequestUri());
$response->send();
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Stream(__DIR__.'/../logs/'.date('Y-m-d').'.log');
$msg = "[".$_SERVER['SERVER_NAME']."] [".$_SERVER['REQUEST_URI']."] [".$e->getCode()."] ".$e->getMessage()." at ".$e->getFile()." (".$e->getLine().")";
$msg .= "\n".$e->getTraceAsString();
$logger->process(new \Phalcon\Logger\Item($msg, "error", 100));
$logger->close();
// remove view contents from buffer
ob_clean();
$errorCode = 500;
$errorView = __DIR__.'/../public/errors/error.html';
if (401 === $e->getCode()) {
// 401 UNAUTHORIZED
$errorCode = 401;
} elseif (403 === $e->getCode()) {
// 403 FORBIDDEN
$errorCode = 403;
} elseif (404 === $e->getCode()
|| $e instanceof Phalcon\Mvc\View\Exception
|| $e instanceof Phalcon\Mvc\Dispatcher\Exception) {
// 404 NOT FOUND
$errorCode = 404;
}
// Get error view contents. Since we are including the view
// file here you can use PHP and local vars inside the error view.
ob_start();
include_once $errorView;
$contents = ob_get_contents();
ob_end_clean();
// send view to header
$response = $this->getDI()->getShared('response');
$response->resetHeaders()
->setStatusCode($errorCode, null)
->setContent($contents)
->send()
;
/**
* We try to register in MongoDB the error to be able to
* track it in backoffice and/or receive emails
*/
try {
$system_log_manager = $this->getDI()->get('system_log_manager');
if ($errorCode == 500) {
$system_log_manager->createError([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
} else {
$system_log_manager->createWarning([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
} catch (\Exception $e) {
}
}
}
public function slowLog($t)
{
$config = $this->getDI()->get('config');
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$server = gethostname() ? gethostname() : 'unknown';
$uri = "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
if (substr($_SERVER['REQUEST_URI'], 0, 10) == '/historias') {
return;
}
$msg = "\x02[SLOWLOG] [".str_pad($server, 6, " ", STR_PAD_LEFT)."] [".str_pad(round($t, 1), 5, " ", STR_PAD_LEFT)."s] PATH=\x02 ".$_SERVER['REQUEST_URI']
."\x02 TYPE=\x02 ".$_SERVER['REQUEST_METHOD']."\x02 URI=\x02 ".$uri;
$irc_manager->privmsgOrderEnqueue('AAAAAI', $config->irc->debug_channel, $msg);
}
/**
* Get the current mode.
*
* @return string
*/
public static function getMode()
{
return self::$mode;
}
}
|
| #18 | Application->mainDev /srv/ChatHispanoEngine/releases/20250927141530/apps/Application.php (122) <?php
// namespace ChatHispanoEngine;
/**
* Application driver class to initialize Phalcon and
* other resources.
*/
class Application extends \Phalcon\Mvc\Application
{
private static $mode = 'dev';
private static $DEFAULT_MODULE = 'api';
public const MODE_PRODUCTION = 'prod';
public const MODE_STAGING = 'staging';
public const MODE_TEST = 'test';
public const MODE_DEVELOPMENT = 'dev';
/**
* Set application mode and error reporting level.
*/
public function __construct($defaultModule, $env = 'dev')
{
$this->modules = array(
'core' => array(
'className' => 'ChatHispanoEngine\Core\Module',
'path' => __DIR__.'/Core/Module.php',
),
'api' => array(
'className' => 'ChatHispanoEngine\Api\Module',
'path' => __DIR__.'/Api/Module.php',
),
'login' => array(
'className' => 'ChatHispanoEngine\Login\Module',
'path' => __DIR__.'/Login/Module.php',
),
'oidc' => array(
'className' => 'ChatHispanoEngine\Oidc\Module',
'path' => __DIR__.'/Oidc/Module.php',
),
'web' => array(
'className' => 'ChatHispanoEngine\Web\Module',
'path' => __DIR__.'/Web/Module.php',
),
'backoffice' => array(
'className' => 'ChatHispanoEngine\Backoffice\Module',
'path' => __DIR__.'/Backoffice/Module.php',
),
'movil' => array(
'className' => 'ChatHispanoEngine\Movil\Module',
'path' => __DIR__.'/Movil/Module.php',
),
'regwebexternal' => array(
'className' => 'ChatHispanoEngine\RegWebExternal\Module',
'path' => __DIR__.'/Regwebexternal/Module.php',
),
'cdn' => array(
'className' => 'ChatHispanoEngine\Cdn\Module',
'path' => __DIR__.'/Cdn/Module.php',
),
'shorten' => array(
'className' => 'ChatHispanoEngine\Shorten\Module',
'path' => __DIR__.'/Shorten/Module.php',
),
);
static::$DEFAULT_MODULE = $defaultModule;
self::$mode = $env;
self::$mode = trim(file_get_contents(__DIR__.'/../config/environment.txt'));
define('ENVIRONMENT', self::$mode);
if (!defined('PHALCON_MODE')) {
$mode = getenv('PHALCON_MODE');
$mode = $mode ? $mode : self::$mode;
define('PHALCON_MODE', $mode);
}
switch (self::getMode()) {
case self::MODE_PRODUCTION:
case self::MODE_STAGING:
error_reporting(0);
break;
case self::MODE_TEST:
case self::MODE_DEVELOPMENT:
ini_set('display_errors', 'On');
error_reporting(E_ALL);
break;
}
}
/**
* Register the services here to make them general or register in
* the ModuleDefinition to make them module-specific.
*/
protected function _registerServices()
{
$defaultModule = self::$DEFAULT_MODULE;
$modules = $this->modules;
$config = include __DIR__.'/../config/config.php';
$env_config = include __DIR__.'/../config/config_'.ENVIRONMENT.'.php';
$config->merge($env_config);
$di = new \Phalcon\DI\FactoryDefault();
include __DIR__.'/../config/loader.php';
include __DIR__.'/../config/services.php';
include __DIR__.'/../config/routing.php';
$this->setDI($di);
}
/**
* Run the application.
*/
public function main()
{
if (static::MODE_PRODUCTION === static::getMode()) {
$this->mainProd();
} else {
$this->mainDev();
}
}
private function getRequestUri()
{
if (!isset($_SERVER)) {
return "/";
}
if (!is_array($_SERVER)) {
return "/";
}
if (!isset($_SERVER['REQUEST_URI'])) {
return "/";
}
return $_SERVER['REQUEST_URI'];
}
/**
* Run the development environment.
*/
private function mainDev()
{
(new \Phalcon\Support\Debug())->listen();
$this->_registerServices();
$this->registerModules($this->modules);
$response = $this->handle($this->getRequestUri());
$response->send();
}
/**
* Run the production environment.
*/
private function mainProd()
{
try {
$this->registerModules($this->modules);
$this->_registerServices();
$response = $this->handle($this->getRequestUri());
$response->send();
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Stream(__DIR__.'/../logs/'.date('Y-m-d').'.log');
$msg = "[".$_SERVER['SERVER_NAME']."] [".$_SERVER['REQUEST_URI']."] [".$e->getCode()."] ".$e->getMessage()." at ".$e->getFile()." (".$e->getLine().")";
$msg .= "\n".$e->getTraceAsString();
$logger->process(new \Phalcon\Logger\Item($msg, "error", 100));
$logger->close();
// remove view contents from buffer
ob_clean();
$errorCode = 500;
$errorView = __DIR__.'/../public/errors/error.html';
if (401 === $e->getCode()) {
// 401 UNAUTHORIZED
$errorCode = 401;
} elseif (403 === $e->getCode()) {
// 403 FORBIDDEN
$errorCode = 403;
} elseif (404 === $e->getCode()
|| $e instanceof Phalcon\Mvc\View\Exception
|| $e instanceof Phalcon\Mvc\Dispatcher\Exception) {
// 404 NOT FOUND
$errorCode = 404;
}
// Get error view contents. Since we are including the view
// file here you can use PHP and local vars inside the error view.
ob_start();
include_once $errorView;
$contents = ob_get_contents();
ob_end_clean();
// send view to header
$response = $this->getDI()->getShared('response');
$response->resetHeaders()
->setStatusCode($errorCode, null)
->setContent($contents)
->send()
;
/**
* We try to register in MongoDB the error to be able to
* track it in backoffice and/or receive emails
*/
try {
$system_log_manager = $this->getDI()->get('system_log_manager');
if ($errorCode == 500) {
$system_log_manager->createError([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
} else {
$system_log_manager->createWarning([
'ip' => $_SERVER['SERVER_ADDR'],
'host' => $_SERVER['SERVER_NAME'],
'process' => 'php-fpm',
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
} catch (\Exception $e) {
}
}
}
public function slowLog($t)
{
$config = $this->getDI()->get('config');
$irc_manager = $this->getDI()->get('inspircd_irc_manager');
$server = gethostname() ? gethostname() : 'unknown';
$uri = "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
if (substr($_SERVER['REQUEST_URI'], 0, 10) == '/historias') {
return;
}
$msg = "\x02[SLOWLOG] [".str_pad($server, 6, " ", STR_PAD_LEFT)."] [".str_pad(round($t, 1), 5, " ", STR_PAD_LEFT)."s] PATH=\x02 ".$_SERVER['REQUEST_URI']
."\x02 TYPE=\x02 ".$_SERVER['REQUEST_METHOD']."\x02 URI=\x02 ".$uri;
$irc_manager->privmsgOrderEnqueue('AAAAAI', $config->irc->debug_channel, $msg);
}
/**
* Get the current mode.
*
* @return string
*/
public static function getMode()
{
return self::$mode;
}
}
|
| #19 | Application->main /srv/ChatHispanoEngine/releases/20250927141530/public/index.php (13) <?php
date_default_timezone_set('Europe/Madrid');
require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/../apps/Application.php';
if (isset($_SERVER['PHALCON_APP'])) {
$app = new Application($_SERVER['PHALCON_APP']);
} else {
$app = new Application('web');
}
$app->main();
try {
$t = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
if ($t > 6) {
$app->slowLog($t);
}
} catch (\Exception $e) {
}
|
| Key | Value |
|---|---|
| _url | /historias/zaragoza/2023-11-10/654edbb8720eebd99702aea6/dislike |
| Key | Value |
|---|---|
| USER | www-data |
| HOME | /var/www |
| HTTP_CONNECTION | close |
| HTTP_X_FORWARDED_FOR | 216.73.216.159 |
| HTTP_X_FORWARDED_PROTO | http |
| HTTP_COOKIE | PHPSESSID=91eda427d8236c53f42973249d65935e |
| HTTP_ACCEPT_ENCODING | gzip, br, zstd, deflate |
| HTTP_USER_AGENT | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) |
| HTTP_ACCEPT | */* |
| DISABLE_ANTEVENIO | 0 |
| DISABLE_MOBUSI | 0 |
| DISABLE_MASSARIUS | 0 |
| DISABLE_RELATEDCONTENT | 0 |
| DISABLE_ADSENSE | 0 |
| ADS_DEFER | 0 |
| PHALCON_APP | web |
| CHATHISPANOENGINE_REVISION | development |
| CHATHISPANOENGINE_INSTANCE | virtualbox |
| SCRIPT_FILENAME | /srv/ChatHispanoEngine/releases/20250927141530/public/index.php |
| PATH_TRANSLATED | /srv/ChatHispanoEngine/current/public |
| PATH_INFO | |
| HTTP_HOST | test.chathispano.com |
| REDIRECT_STATUS | 200 |
| SERVER_NAME | test.chathispano.com |
| SERVER_PORT | 80 |
| SERVER_ADDR | 10.234.61.101 |
| REMOTE_USER | |
| REMOTE_PORT | 46472 |
| REMOTE_ADDR | 10.234.61.151 |
| SERVER_SOFTWARE | nginx/1.26.3 |
| GATEWAY_INTERFACE | CGI/1.1 |
| REQUEST_SCHEME | http |
| SERVER_PROTOCOL | HTTP/1.1 |
| DOCUMENT_ROOT | /srv/ChatHispanoEngine/releases/20250927141530/public |
| DOCUMENT_URI | /index.php |
| REQUEST_URI | /historias/zaragoza/2023-11-10/654edbb8720eebd99702aea6/dislike |
| SCRIPT_NAME | /index.php |
| CONTENT_LENGTH | |
| CONTENT_TYPE | |
| REQUEST_METHOD | GET |
| QUERY_STRING | _url=/historias/zaragoza/2023-11-10/654edbb8720eebd99702aea6/dislike |
| FCGI_ROLE | RESPONDER |
| PHP_SELF | /index.php |
| REQUEST_TIME_FLOAT | 1781638191.4415 |
| REQUEST_TIME | 1781638191 |
| # | Path |
|---|---|
| 0 | /srv/ChatHispanoEngine/releases/20250927141530/public/index.php |
| 1 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/autoload.php |
| 2 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/autoload_real.php |
| 3 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/platform_check.php |
| 4 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/ClassLoader.php |
| 5 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/include_paths.php |
| 6 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/autoload_static.php |
| 7 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-mbstring/bootstrap.php |
| 8 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-mbstring/bootstrap80.php |
| 9 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/deprecation-contracts/function.php |
| 10 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/amp/lib/functions.php |
| 11 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/amp/lib/Internal/functions.php |
| 12 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/react/promise/src/functions_include.php |
| 13 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/react/promise/src/functions.php |
| 14 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-ctype/bootstrap.php |
| 15 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-ctype/bootstrap80.php |
| 16 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-normalizer/bootstrap.php |
| 17 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php |
| 18 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php85/bootstrap.php |
| 19 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php85/bootstrap80.php |
| 20 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php84/bootstrap.php |
| 21 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-grapheme/bootstrap.php |
| 22 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php |
| 23 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/byte-stream/lib/functions.php |
| 24 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/collections/functions.php |
| 25 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/collections/helpers.php |
| 26 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/string/Resources/functions.php |
| 27 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php |
| 28 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/ralouphie/getallheaders/src/getallheaders.php |
| 29 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php |
| 30 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/clock/Resources/now.php |
| 31 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-intl-idn/bootstrap.php |
| 32 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/translation/Resources/functions.php |
| 33 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/var-dumper/Resources/functions/dump.php |
| 34 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/guzzlehttp/guzzle/src/functions_include.php |
| 35 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/guzzlehttp/guzzle/src/functions.php |
| 36 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php80/bootstrap.php |
| 37 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/process/lib/functions.php |
| 38 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/serialization/src/functions.php |
| 39 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/sync/src/functions.php |
| 40 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/sync/src/ConcurrentIterator/functions.php |
| 41 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/reflection/helpers.php |
| 42 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/psy/psysh/src/functions.php |
| 43 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/daverandom/libdns/src/functions.php |
| 44 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/support/functions.php |
| 45 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/illuminate/support/helpers.php |
| 46 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/symfony/polyfill-php81/bootstrap.php |
| 47 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/amphp/dns/lib/functions.php |
| 48 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/codeception/codeception/functions.php |
| 49 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/functions.php |
| 50 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Application.php |
| 51 | /srv/ChatHispanoEngine/releases/20250927141530/config/config.php |
| 52 | /srv/ChatHispanoEngine/releases/20250927141530/config/config_dev.php |
| 53 | /srv/ChatHispanoEngine/releases/20250927141530/config/loader.php |
| 54 | /srv/ChatHispanoEngine/releases/20250927141530/config/services.php |
| 55 | /srv/ChatHispanoEngine/releases/20250927141530/config/managers.php |
| 56 | /srv/ChatHispanoEngine/releases/20250927141530/config/routing.php |
| 57 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/routing.php |
| 58 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Module.php |
| 59 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/config.php |
| 60 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/services.php |
| 61 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/config/managers.php |
| 62 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Controllers/StoriesController.php |
| 63 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Controllers/BaseController.php |
| 64 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Controllers/BaseController.php |
| 65 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/iwalkalone/translator/src/Translator.php |
| 66 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Web/Auth/Auth.php |
| 67 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/GlineManager.php |
| 68 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/InspIRCd/Gline.php |
| 69 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/BaseCollection.php |
| 70 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Client.php |
| 71 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/InstalledVersions.php |
| 72 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/composer/installed.php |
| 73 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/BuilderEncoder.php |
| 74 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Codec/EncodeIfSupported.php |
| 75 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Codec/Encoder.php |
| 76 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/PipelineEncoder.php |
| 77 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/RecursiveEncode.php |
| 78 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/VariableEncoder.php |
| 79 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/DictionaryEncoder.php |
| 80 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/FieldPathEncoder.php |
| 81 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/CombinedFieldQueryEncoder.php |
| 82 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/QueryEncoder.php |
| 83 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/OutputWindowEncoder.php |
| 84 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/OperatorEncoder.php |
| 85 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Builder/Encoder/DateTimeEncoder.php |
| 86 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Database.php |
| 87 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Collection.php |
| 88 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/FindOne.php |
| 89 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/Explainable.php |
| 90 | /srv/ChatHispanoEngine/releases/20250927141530/vendor/mongodb/mongodb/src/Operation/Find.php |
| 91 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Managers/InspIRCd/ChannelManager.php |
| 92 | /srv/ChatHispanoEngine/releases/20250927141530/apps/Core/Models/Channel/Datasheet.php |
| Memory | |
|---|---|
| Usage | 4194304 |