Compare commits

...

52 Commits

Author SHA1 Message Date
mercury ca37736cd5 fix menu rulesset with empty rules 2024-10-26 23:14:03 +04:00
mercury 1c4fff50d1 fix menu warp after update 2024-10-26 22:47:43 +04:00
mercury 6ffb4d0a79 update version 2024-10-26 22:41:07 +04:00
mercury 394062cbe0 fix warp off after update 2024-10-26 22:29:07 +04:00
mercury dd8897575f fix warp off after update 2024-10-26 22:18:36 +04:00
mercury 9ab05de320 fix update menu 2024-10-26 21:58:10 +04:00
legiz-ru 71f7db5bac update singbox 1.10.1 windows x64 (#26) 2024-10-26 19:47:15 +04:00
mercury 237da68f14 duplicate the rulesset list in the message 2024-10-26 14:44:06 +04:00
mercury 961ebf3423 xray->routes->proxy <=> Pac 2024-10-25 21:02:58 +04:00
mercury ddcaea751f update version 2024-10-25 18:43:32 +04:00
mercury ce8cdac7c7 Fix for auto-backup not triggering on the first tick 2024-10-25 18:36:54 +04:00
mercury 00aae6c2f7 adguard: list of allowed clients 2024-10-25 18:12:05 +04:00
mercury 89c0139ef6 show safe search status 2024-10-25 17:38:50 +04:00
mercury c57053c8a0 copyable warp key 2024-10-25 17:14:52 +04:00
mercury 3cc16469ff warp registration delete before off 2024-10-25 17:11:46 +04:00
mercury e06544b00f update version 2024-10-24 23:45:25 +04:00
mercury c5b7e1ffdc warp registration fix 2024-10-24 23:15:44 +04:00
mercury 7d21937f04 ability to override i18n 2024-10-24 22:32:16 +04:00
mercury 16138648ca fix openconnect link 2024-10-24 21:54:37 +04:00
mercury ced10f22fa update version 2024-10-24 00:01:51 +04:00
mercury 18a4ee39fb improve selfupdate 2024-10-23 23:59:32 +04:00
mercury 4f4777b5ef improve selfupdate 2024-10-23 23:56:50 +04:00
mercury dee90b1f4f improve selfupdate 2024-10-23 23:53:58 +04:00
mercury 01571f50e6 improve selfupdate 2024-10-23 23:29:56 +04:00
mercury 4998893234 fix autobackup 2024-10-23 21:35:17 +04:00
mercury 95f92791b1 update version 2024-10-23 10:08:32 +04:00
mercury cedfb66ca0 fix autoupdate wireguard crash 2024-10-23 10:05:06 +04:00
mercury 6215836926 fix empty route rules for singbox 2024-10-23 03:01:10 +04:00
mercury 842d76261a update version 2024-10-23 02:45:17 +04:00
mercury 4c63ae669a improve selfupdate 2024-10-23 02:32:19 +04:00
mercury bba1ec9e17 improve selfupdate 2024-10-23 02:25:00 +04:00
mercury a798df0fd3 improve selfupdate 2024-10-23 02:20:16 +04:00
mercury d225e7c039 fix double import after update 2024-10-23 02:06:35 +04:00
mercury 3b9b930b48 - autobackup check formate
- cron status
- fix with sending a backup when there are special characters in the bot name
2024-10-23 01:24:36 +04:00
mercury bd17e5cd14 improve ip detect on start 2024-10-22 23:55:05 +04:00
mercury c3975549db openconnect: isolate-workers = false 2024-10-22 22:42:20 +04:00
mercury 3087bee82d openconnect: expose-iroutes on/off 2024-10-21 22:19:13 +04:00
mercury 96fbf5a3c3 openconnect: limit cpu and memory 2024-10-21 21:09:50 +04:00
mercury b32bd960fa xray: tags for templates 2024-10-21 02:29:19 +04:00
mercury ba0895ea4c fix start menu 2024-10-21 01:28:15 +04:00
mercury 68e6e5919d fixes for first launch 2024-10-21 01:07:05 +04:00
mercury 28c5b9d506 xray route: учет регистра в process_name, package_name 2024-10-14 09:47:19 +04:00
mercury 9cc42fd34a xray route: добавлен список process_name 2024-10-14 01:11:21 +04:00
mercury 5eef9581c7 singbox template: package_name -> ruleset 2024-10-14 00:38:58 +04:00
mercury 1d9d992361 sslip.io -> nip.io 2024-10-14 00:00:25 +04:00
mercury e1f14d85e0 порядок правил маршрутизации для singbox 2024-10-13 23:58:02 +04:00
mercury dc65e65e20 fix create windows service box 2 2024-10-10 00:19:59 +04:00
mercury 486a2c5959 fix create windows service box 2024-10-09 21:03:15 +04:00
mercury 39643bf681 add html fake from settings menu 2024-10-06 23:19:05 +04:00
mercury 5f1fc6d912 override html mock 2024-10-06 21:04:13 +04:00
mercury 0538d04397 sing-box template: block rule first 2024-10-06 20:49:24 +04:00
mercury af9933676d karing import url 2024-09-30 17:13:32 +04:00
19 changed files with 570 additions and 336 deletions
+3 -1
View File
@@ -19,4 +19,6 @@ mirror/.env
update/* update/*
!update/update.sh !update/update.sh
override.env override.env
override.html
override.php
+400 -173
View File
@@ -142,9 +142,15 @@ class Bot
case preg_match('~^/autoupdate$~', $this->input['message'], $m): case preg_match('~^/autoupdate$~', $this->input['message'], $m):
$this->autoupdate(); $this->autoupdate();
break; break;
case preg_match('~^/adgFillAllowedClients(?: (\d+))?$~', $this->input['callback'], $m):
$this->adgFillAllowedClients($m[1] ?: false);
break;
case preg_match('~^/appOutbound$~', $this->input['callback'], $m): case preg_match('~^/appOutbound$~', $this->input['callback'], $m):
$this->appOutbound(); $this->appOutbound();
break; break;
case preg_match('~^/processOutbound$~', $this->input['callback'], $m):
$this->processOutbound();
break;
case preg_match('~^/offWarp$~', $this->input['callback'], $m): case preg_match('~^/offWarp$~', $this->input['callback'], $m):
$this->offWarp(); $this->offWarp();
break; break;
@@ -268,6 +274,9 @@ class Bot
case preg_match('~^/addOcUser$~', $this->input['callback'], $m): case preg_match('~^/addOcUser$~', $this->input['callback'], $m):
$this->addOcUser(); $this->addOcUser();
break; break;
case preg_match('~^/changeOcExpose$~', $this->input['callback'], $m):
$this->changeOcExpose();
break;
case preg_match('~^/addXrUser$~', $this->input['callback'], $m): case preg_match('~^/addXrUser$~', $this->input['callback'], $m):
$this->addXrUser(); $this->addXrUser();
break; break;
@@ -428,9 +437,15 @@ class Bot
case preg_match('~^/xtlswarp(?: (\d+))?$~', $this->input['callback'], $m): case preg_match('~^/xtlswarp(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlswarp($m[1] ?: 0); $this->xtlswarp($m[1] ?: 0);
break; break;
case preg_match('~^/xtlsproxy(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsproxy($m[1] ?: 0);
break;
case preg_match('~^/xtlsapp(?: (\d+))?$~', $this->input['callback'], $m): case preg_match('~^/xtlsapp(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsapp($m[1] ?: 0); $this->xtlsapp($m[1] ?: 0);
break; break;
case preg_match('~^/xtlsprocess(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsprocess($m[1] ?: 0);
break;
case preg_match('~^/xtlsrulesset(?: (\d+))?$~', $this->input['callback'], $m): case preg_match('~^/xtlsrulesset(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsrulesset($m[1] ?: 0); $this->xtlsrulesset($m[1] ?: 0);
break; break;
@@ -482,8 +497,8 @@ class Bot
case preg_match('~^/proxy$~', $this->input['callback'], $m): case preg_match('~^/proxy$~', $this->input['callback'], $m):
$this->proxy(); $this->proxy();
break; break;
case preg_match('~^/showpac$~', $this->input['callback'], $m): case preg_match('~^/addOverrideHtml$~', $this->input['callback'], $m):
$this->showpac(); $this->addOverrideHtml();
break; break;
case preg_match('~^/export$~', $this->input['callback'], $m): case preg_match('~^/export$~', $this->input['callback'], $m):
$this->exportManual(); $this->exportManual();
@@ -809,6 +824,30 @@ class Bot
]; ];
} }
public function addOverrideHtml()
{
$r = $this->send(
$this->input['chat'],
"@{$this->input['username']} attach html",
$this->input['message_id'],
reply: 'attach html',
);
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'start_callback' => $this->input['callback_id'],
'callback' => 'setOverrideHtml',
'args' => [],
];
}
public function setOverrideHtml()
{
$r = $this->request('getFile', ['file_id' => $this->input['file_id']]);
if (!empty($f = file_get_contents($this->file . $r['result']['file_path']))) {
file_put_contents('/app/webapp/override.html', $f);
}
}
public function restartOcserv($conf) public function restartOcserv($conf)
{ {
file_put_contents('/config/ocserv.conf', $conf); file_put_contents('/config/ocserv.conf', $conf);
@@ -1030,25 +1069,32 @@ class Bot
public function cron() public function cron()
{ {
$period = 10;
while (true) { while (true) {
$this->shutdownClient(); $this->shutdownClient();
$this->shutdownClientXr(); $this->shutdownClientXr();
$this->checkVersion(); $this->checkVersion();
$this->checkBackup(); $this->checkBackup($period);
$this->checkCert(); $this->checkCert();
sleep(10); sleep($period);
} }
} }
public function checkBackup() public function checkBackup($delta)
{ {
$c = $this->getPacConf(); $c = $this->getPacConf();
$now = strtotime(date('Y-m-d H:i'));
if (!empty($c['backup'])) { if (!empty($c['backup'])) {
$now = strtotime(date('Y-m-d H:i:s'));
[$start, $period] = explode('/', $c['backup']); [$start, $period] = explode('/', $c['backup']);
$start = strtotime($start); $start = strtotime(trim($start));
$period = strtotime($period, 0); $period = strtotime(trim($period), 0);
if ($now - $start >= $period && ($now - $start) % $period == 0) { if (
!empty($start)
&& !empty($period)
&& empty($this->backup)
&& $now - $start >= 0
&& (($now - $start) % $period < $delta)
) {
if (!empty($c['pinbackup'])) { if (!empty($c['pinbackup'])) {
$this->pinAdmin($c['pinbackup'], 1); $this->pinAdmin($c['pinbackup'], 1);
} }
@@ -1057,6 +1103,12 @@ class Bot
} }
} }
public function cleanQueue(): void
{
$r = $this->request('deleteWebhook', []);
$r = $this->request('getUpdates', ['offset' => -1]);
}
public function pinAdmin($pin, $unpin = false) public function pinAdmin($pin, $unpin = false)
{ {
require __DIR__ . '/config.php'; require __DIR__ . '/config.php';
@@ -1071,9 +1123,8 @@ class Bot
{ {
require __DIR__ . '/config.php'; require __DIR__ . '/config.php';
$conf = $this->getPacConf(); $conf = $this->getPacConf();
$bot = $this->request('getMyName', [])['result']['name']; $bot = preg_replace('~[\W]~iu', '_', $this->request('getMyName', [])['result']['name']);
$conf['pinbackup'] = $this->upload("{$bot}_export_" . date('d_m_Y_H_i') . '.json', $this->export(), $c['admin'][0])['result']['message_id']; $conf['pinbackup'] = $this->upload("{$bot}_export_" . date('d_m_Y_H_i') . '.json', $this->export(), $c['admin'][0])['result']['message_id'];
$conf['backup'] = implode(' / ', [date('Y-m-d H:i'), trim(explode('/', $conf['backup'])[1])]);
$this->setPacConf($conf); $this->setPacConf($conf);
$this->pinAdmin($conf['pinbackup']); $this->pinAdmin($conf['pinbackup']);
} }
@@ -1263,7 +1314,7 @@ class Bot
if (!empty($file)) { if (!empty($file)) {
file_put_contents($file, $json); file_put_contents($file, $json);
} }
$bot = $this->request('getMyName', [])['result']['name']; $bot = preg_replace('~[\W]~iu', '_', $this->request('getMyName', [])['result']['name']);
return $this->upload("{$bot}_export_" . date('d_m_Y_H_i') . '.json', $json); return $this->upload("{$bot}_export_" . date('d_m_Y_H_i') . '.json', $json);
} }
@@ -1415,8 +1466,8 @@ class Bot
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out)); $this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
$this->language = $this->getPacConf()['language'] ?: 'en'; $this->language = $this->getPacConf()['language'] ?: 'en';
$this->limit = $this->getPacConf()['limitpage'] ?: 5; $this->limit = $this->getPacConf()['limitpage'] ?: 5;
sleep(3);
if (empty($file)) { if (empty($file)) {
sleep(3);
$this->menu(); $this->menu();
} }
} }
@@ -1730,10 +1781,14 @@ class Bot
$this->adguardProtect(); $this->adguardProtect();
$u = $this->ssh("nginx -t 2>&1", 'ng'); $u = $this->ssh("nginx -t 2>&1", 'ng');
$out[] = $u; $out[] = $u;
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out)); if (empty($nomenu)) {
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
}
if (preg_match('~test is successful~', $u)) { if (preg_match('~test is successful~', $u)) {
$out[] = $this->ssh("nginx -s reload 2>&1", 'ng'); $out[] = $this->ssh("nginx -s reload 2>&1", 'ng');
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out)); if (empty($nomenu)) {
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
}
$this->setPacConf($conf); $this->setPacConf($conf);
$this->chocdomain($domain); $this->chocdomain($domain);
$this->setUpstreamDomainOcserv($domain); $this->setUpstreamDomainOcserv($domain);
@@ -1750,13 +1805,19 @@ class Bot
public function sslip() public function sslip()
{ {
$c = $this->getPacConf(); require __DIR__ . '/config.php';
if (empty($c['domain'])) { $p = $this->getPacConf();
$this->addDomain(str_replace('.', '-', $this->ip) . '.sslip.io', 1); $ip = getenv('IP');
$r = $this->send($c['admin'][0], "start $ip");
$this->input['chat'] = $c['admin'][0];
$this->input['message_id'] = $r['result']['message_id'];
$this->input['callback_id'] = false;
if (empty($p['domain'])) {
$this->addDomain(str_replace('.', '-', $this->ip) . '.nip.io', 1);
$this->setSSL('letsencrypt'); $this->setSSL('letsencrypt');
} else {
$this->menu();
} }
$this->menu();
} }
public function comment($text, $tag) public function comment($text, $tag)
@@ -2398,7 +2459,7 @@ DNS-over-HTTPS with IP:
if (!empty($domains)) { if (!empty($domains)) {
$conf = $this->getPacConf(); $conf = $this->getPacConf();
foreach ($domains as $k => $v) { foreach ($domains as $k => $v) {
$conf[$type][$type == 'rulessetlist' ? trim($v) : idn_to_ascii(trim($v))] = true; $conf[$type][in_array($type, ['rulessetlist', 'packagelist', 'processlist']) ? trim($v) : idn_to_ascii(trim($v))] = true;
} }
ksort($conf[$type]); ksort($conf[$type]);
$this->setPacConf($conf); $this->setPacConf($conf);
@@ -2412,7 +2473,10 @@ DNS-over-HTTPS with IP:
{ {
switch ($type) { switch ($type) {
case 'includelist': case 'includelist':
$this->pacUpdate(); $this->pacUpdate($_SESSION['proxylistentry']);
if (!empty($_SESSION['proxylistentry'])) {
$this->xtlsproxy();
}
break; break;
case 'blocklist': case 'blocklist':
$this->xrayUpdateRules(); $this->xrayUpdateRules();
@@ -2422,6 +2486,10 @@ DNS-over-HTTPS with IP:
$this->xrayUpdateRules(); $this->xrayUpdateRules();
$this->xtlswarp(); $this->xtlswarp();
break; break;
case 'processlist':
$this->xrayUpdateRules();
$this->xtlsprocess();
break;
case 'packagelist': case 'packagelist':
$this->xrayUpdateRules(); $this->xrayUpdateRules();
$this->xtlsapp(); $this->xtlsapp();
@@ -3288,6 +3356,7 @@ DNS-over-HTTPS with IP:
public function pacMenu($page = 0) public function pacMenu($page = 0)
{ {
unset($_SESSION['proxylistentry']);
$rmpac = stat(__DIR__ . '/zapretlists/rmpac'); $rmpac = stat(__DIR__ . '/zapretlists/rmpac');
$rpac = stat(__DIR__ . '/zapretlists/rpac'); $rpac = stat(__DIR__ . '/zapretlists/rpac');
$mpac = stat(__DIR__ . '/zapretlists/mpac'); $mpac = stat(__DIR__ . '/zapretlists/mpac');
@@ -3368,7 +3437,7 @@ DNS-over-HTTPS with IP:
'callback_data' => "/addCommunityFilter", 'callback_data' => "/addCommunityFilter",
], ],
]; ];
$data = array_merge($data, $this->listPac('includelist', $page, 'pacMenu')); $data = array_merge($data, $this->listPac('includelist', $page, 'pacMenu')[0]);
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
@@ -3401,6 +3470,9 @@ DNS-over-HTTPS with IP:
case 'packagelist': case 'packagelist':
$this->xtlsapp(); $this->xtlsapp();
break; break;
case 'processlist':
$this->xtlsprocess();
break;
case 'rulessetlist': case 'rulessetlist':
$this->xtlsrulesset(); $this->xtlsrulesset();
break; break;
@@ -3504,7 +3576,7 @@ DNS-over-HTTPS with IP:
{ {
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> block list'; $text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> block list';
$data = $this->listPac('blocklist', $page, 'xtlsblock'); [$data] = $this->listPac('blocklist', $page, 'xtlsblock');
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
@@ -3523,7 +3595,26 @@ DNS-over-HTTPS with IP:
{ {
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> warp list'; $text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> warp list';
$data = $this->listPac('warplist', $page, 'xtlswarp'); [$data] = $this->listPac('warplist', $page, 'xtlswarp');
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/routes",
],
];
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
$data ?: false,
);
}
public function xtlsproxy($page = 0)
{
$_SESSION['proxylistentry'] = 1;
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> proxy list';
[$data] = $this->listPac('includelist', $page, 'xtlsproxy');
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
@@ -3546,11 +3637,19 @@ DNS-over-HTTPS with IP:
$this->xtlsapp(); $this->xtlsapp();
} }
public function processOutbound()
{
$p = $this->getPacConf();
$p['process_outbound'] = !$p['process_outbound'];
$p = $this->setPacConf($p);
$this->xtlsprocess();
}
public function xtlsapp($page = 0) public function xtlsapp($page = 0)
{ {
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> package list'; $text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> package list';
$data = $this->listPac('packagelist', $page, 'xtlsapp'); [$data] = $this->listPac('packagelist', $page, 'xtlsapp');
$p = $this->getPacConf(); $p = $this->getPacConf();
$data[] = [ $data[] = [
[ [
@@ -3572,11 +3671,38 @@ DNS-over-HTTPS with IP:
); );
} }
public function xtlsprocess($page = 0)
{
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> process list';
[$data] = $this->listPac('processlist', $page, 'xtlsprocess');
$p = $this->getPacConf();
$data[] = [
[
'text' => 'set to ' . ($p['process_outbound'] ? 'proxy' : 'direct'),
'callback_data' => "/processOutbound",
],
];
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/routes",
],
];
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
$data ?: false,
);
}
public function xtlsrulesset($page = 0) public function xtlsrulesset($page = 0)
{ {
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> rulesset list'; $text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> rulesset list';
$data = $this->listPac('rulessetlist', $page, 'xtlsrulesset', 1); [$data, $tmp] = $this->listPac('rulessetlist', $page, 'xtlsrulesset', 1);
$text = array_merge($text, $tmp ?: []);
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
@@ -3607,9 +3733,12 @@ DNS-over-HTTPS with IP:
$domains = array_slice($domains, $page * $this->limit, $this->limit, true); $domains = array_slice($domains, $page * $this->limit, $this->limit, true);
$i = 0; $i = 0;
foreach ($domains as $k => $v) { foreach ($domains as $k => $v) {
if ($type == 'rulessetlist') {
$text[] = "<blockquote><code>$k</code></blockquote>";
}
$data[] = [ $data[] = [
[ [
'text' => $this->i18n($v ? 'on' : 'off') . ' ' . ($basename ? basename($k) . ' ' : '') . idn_to_utf8($k), 'text' => $this->i18n($v ? 'on' : 'off') . ' ' . ($basename ? basename($k) . ' ' : '') . (in_array($type, ['rulessetlist', 'packagelist', 'processlist']) ? $k : idn_to_utf8($k)),
'callback_data' => "/change$type " . ($i + $page * $this->limit), 'callback_data' => "/change$type " . ($i + $page * $this->limit),
], ],
[ [
@@ -3653,7 +3782,7 @@ DNS-over-HTTPS with IP:
], ],
]; ];
} }
return $data; return [$data, $text];
} }
public function listPacChange($type, $action, $key) public function listPacChange($type, $action, $key)
@@ -3769,9 +3898,10 @@ DNS-over-HTTPS with IP:
public function menu($type = false, $arg = false, $return = false) public function menu($type = false, $arg = false, $return = false)
{ {
$domain = $this->getPacConf()['domain'] ?: $this->ip; $domain = $this->getPacConf()['domain'] ?: $this->ip;
$cron = exec('pgrep -f cron.php');
$menu = [ $menu = [
'main' => [ 'main' => [
'text' => 'v' . getenv('VER'), 'text' => 'v' . getenv('VER') . ($this->dontshowcron ? '' : "\ncron: " . $this->i18n($cron ? 'on' : 'off') . ($cron ? '' : ' show <code>logs/php_error</code>')),
'data' => [ 'data' => [
[ [
[ [
@@ -4058,10 +4188,12 @@ DNS-over-HTTPS with IP:
preg_match('~^camouflage_secret[^\n]+?"([^"]+)*"~sm', $ocserv, $m); preg_match('~^camouflage_secret[^\n]+?"([^"]+)*"~sm', $ocserv, $m);
$cs = $m[1]; $cs = $m[1];
preg_match('~^dns = ([^\n]+)~sm', $ocserv, $m); preg_match('~^dns = ([^\n]+)~sm', $ocserv, $m);
$dns = $m[1]; $dns = $m[1];
preg_match('~^expose-iroutes = (true)~sm', $ocserv, $m);
$expose = $m[1];
$pass = htmlspecialchars($pac['ocserv']); $pass = htmlspecialchars($pac['ocserv']);
$text[] = "Menu -> OpenConnect"; $text[] = "Menu -> OpenConnect";
if (!empty($m[1])) { if (!empty($cs)) {
$text[] = "<code>https://oc.$domain/?$cs</code>"; $text[] = "<code>https://oc.$domain/?$cs</code>";
} }
$text[] = "password: <span class='tg-spoiler'>$pass</span>"; $text[] = "password: <span class='tg-spoiler'>$pass</span>";
@@ -4079,6 +4211,12 @@ DNS-over-HTTPS with IP:
'callback_data' => "/changeOcDns", 'callback_data' => "/changeOcDns",
], ],
]; ];
$data[] = [
[
'text' => $this->i18n('expose-iroutes') . ' ' . $this->i18n($expose ? 'on' : 'off'),
'callback_data' => "/changeOcExpose",
],
];
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('add peer'), 'text' => $this->i18n('add peer'),
@@ -4106,6 +4244,15 @@ DNS-over-HTTPS with IP:
]; ];
} }
public function changeOcExpose()
{
$c = file_get_contents('/config/ocserv.conf');
preg_match('~^expose-iroutes = ([^\n]+)~sm', $c, $m);
$t = preg_replace('~^expose-iroutes[^\n]+~sm', "expose-iroutes = " . ($m[1] == 'true' ? 'false' : 'true'), $c);
$this->restartOcserv($t);
$this->menu('oc');
}
public function deloc($i) public function deloc($i)
{ {
$clients = $this->getClientsOc(); $clients = $this->getClientsOc();
@@ -4472,6 +4619,14 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n('warp'), 'text' => $this->i18n('warp'),
'callback_data' => "/xtlswarp", 'callback_data' => "/xtlswarp",
]], ]],
[[
'text' => $this->i18n('proxy'),
'callback_data' => "/xtlsproxy",
]],
[[
'text' => $this->i18n('process'),
'callback_data' => "/xtlsprocess",
]],
[[ [[
'text' => $this->i18n('package'), 'text' => $this->i18n('package'),
'callback_data' => "/xtlsapp", 'callback_data' => "/xtlsapp",
@@ -4535,25 +4690,34 @@ DNS-over-HTTPS with IP:
return 'off'; return 'off';
} }
public function offWarp() public function offWarp($inversion = true)
{ {
$p = $this->getPacConf(); $p = $this->getPacConf();
if (empty($p['warpoff'])) { if ($inversion && !empty($p['warpoff'])) {
$this->ssh('pkill warp-svc', 'wp');
$p['warpoff'] = 1;
} else {
$this->ssh('warp-svc > /dev/null 2>&1 &', 'wp'); $this->ssh('warp-svc > /dev/null 2>&1 &', 'wp');
sleep(3); sleep(3);
$this->send($this->input['chat'], 'Registration: ' . $this->ssh('warp-cli --accept-tos registration new 2>&1', 'wp')); if (empty($this->ssh('[ -f "/var/lib/cloudflare-warp/conf.json" ] && echo 1', 'wp'))) {
if (!empty($p['warp'])) { $this->send($this->input['chat'], 'Registration: ' . $this->ssh('warp-cli --accept-tos registration new 2>&1', 'wp'));
$this->send($this->input['chat'], 'License: ' . $this->ssh("warp-cli --accept-tos registration license {$p['warp']} 2>&1", 'wp')); if (!empty($p['warp'])) {
$this->send($this->input['chat'], 'License: ' . $this->ssh("warp-cli --accept-tos registration license {$p['warp']} 2>&1", 'wp'));
}
} }
$this->send($this->input['chat'], 'Proxy mode: ' . $this->ssh('warp-cli --accept-tos mode proxy 2>&1', 'wp')); $this->send($this->input['chat'], 'Proxy mode: ' . $this->ssh('warp-cli --accept-tos mode proxy 2>&1', 'wp'));
$this->send($this->input['chat'], 'Connect: ' . $this->ssh('warp-cli --accept-tos connect 2>&1', 'wp')); $this->send($this->input['chat'], 'Connect: ' . $this->ssh('warp-cli --accept-tos connect 2>&1', 'wp'));
unset($p['warpoff']); unset($p['warpoff']);
} else {
if (empty($inversion)) {
$this->ssh('warp-cli --accept-tos registration delete 2>&1', 'wp');
} else {
$this->send($this->input['chat'], 'Registration delete: ' . $this->ssh('warp-cli --accept-tos registration delete 2>&1', 'wp'));
}
$this->ssh('pkill warp-svc', 'wp');
$p['warpoff'] = 1;
} }
$this->setPacConf($p); $this->setPacConf($p);
$this->warp(); if (!empty($inversion)) {
$this->warp();
}
} }
public function warp() public function warp()
@@ -4561,7 +4725,7 @@ DNS-over-HTTPS with IP:
$p = $this->getPacConf(); $p = $this->getPacConf();
$text[] = "Menu -> " . $this->i18n('warp'); $text[] = "Menu -> " . $this->i18n('warp');
$text[] = "status: " . $this->warpStatus(); $text[] = "status: " . $this->warpStatus();
$text[] = "key: " . $this->getPacConf()['warp']; $text[] = "key: <code>{$this->getPacConf()['warp']}</code>";
$data[] = [ $data[] = [
[ [
'text' => $this->i18n($p['warpoff'] ? 'off' : 'on'), 'text' => $this->i18n($p['warpoff'] ? 'off' : 'on'),
@@ -4657,14 +4821,27 @@ DNS-over-HTTPS with IP:
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=si&s={$c['id']}#{$c['email']}'>sing-box</a>"; $text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=si&s={$c['id']}#{$c['email']}'>sing-box</a>";
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=st&s={$c['id']}#{$c['email']}'>streisand</a>"; $text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=st&s={$c['id']}#{$c['email']}'>streisand</a>";
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=h&s={$c['id']}#{$c['email']}'>hiddify</a>"; $text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=h&s={$c['id']}#{$c['email']}'>hiddify</a>";
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=k&s={$c['id']}#{$c['email']}'>karing</a>";
$si = "$scheme://{$domain}/pac/" . base64_encode(serialize([
'h' => $hash,
't' => 'si',
's' => $c['id'],
]));
$xr = "$scheme://{$domain}/pac/" . base64_encode(serialize([
'h' => $hash,
't' => 's',
's' => $c['id'],
]));
$text[] = "\nxray config: <pre><code>$xr</code></pre>";
$text[] = "sing-box config: <pre><code>$si</code></pre>";
$text[] = "\nv2ray config: <pre><code>$scheme://{$domain}/pac?h=$hash&t=s&s={$c['id']}</code></pre>";
$text[] = "sing-box config: <pre><code>$scheme://{$domain}/pac?h=$hash&t=si&s={$c['id']}</code></pre>";
$text[] = "sing-box windows: <a href='$scheme://{$domain}/pac?h=$hash&t=si&r=w&s={$c['id']}'>windows service</a>"; $text[] = "sing-box windows: <a href='$scheme://{$domain}/pac?h=$hash&t=si&r=w&s={$c['id']}'>windows service</a>";
$data[] = [ $data[] = [
[ [
'text' => 'v2ray', 'text' => 'xray',
'web_app' => ['url' => "https://{$domain}/pac?h=$hash&t=s&s={$c['id']}"], 'web_app' => ['url' => "https://{$domain}/pac?h=$hash&t=s&s={$c['id']}"],
], ],
[ [
@@ -4741,45 +4918,6 @@ DNS-over-HTTPS with IP:
return $c['domain'] ?: $this->ip; return $c['domain'] ?: $this->ip;
} }
public function v2raySubscription($key, $fs = 0)
{
$pac = $this->getPacConf();
$domain = $this->getDomain();
$xr = $this->getXray();
$flag = true;
foreach ($xr['inbounds'][0]['settings']['clients'] as $k => $v) {
if ($v['id'] == $key) {
if (!empty($fs)) {
return $this->userXr($k);
}
if (empty($v['off'])) {
$flag = false;
}
break;
}
}
if ($flag) {
return;
}
$c = json_decode(file_get_contents('/config/v2ray.json'), true);
$c['outbounds'][0]['settings']['vnext'][0]['address'] = $domain;
$c['outbounds'][0]['settings']['vnext'][0]['users'][0]['id'] = $key;
$c['outbounds'][0]['streamSettings']['realitySettings']['serverName'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0];
$c['outbounds'][0]['streamSettings']['realitySettings']['publicKey'] = $pac['xray'];
$c['outbounds'][0]['streamSettings']['realitySettings']['shortId'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0];
$c['routing']['rules'][0]['domain'] = array_keys(array_filter($pac['includelist']));
if (empty($c['routing']['rules'][0]['domain'])) {
unset($c['routing']['rules'][0]);
$c['routing']['rules'] = array_values($c['routing']['rules']);
}
echo json_encode($c);
}
public function subscription() public function subscription()
{ {
$type = $_GET['t'] == 's' ? 'v2ray' : 'sing'; $type = $_GET['t'] == 's' ? 'v2ray' : 'sing';
@@ -4826,17 +4964,19 @@ DNS-over-HTTPS with IP:
case 'v': case 'v':
header("Location: v2rayng://install-config?url=$v2"); header("Location: v2rayng://install-config?url=$v2");
exit; exit;
case 'k':
header("Location: karing://install-config?url=$si");
exit;
case 'h': case 'h':
header("Location: hiddify://install-config/?url=$si"); header("Location: hiddify://install-config/?url=$si");
exit; exit;
case 'w': case 'w':
$link = htmlspecialchars($si, ENT_XML1, 'UTF-8'); $link = htmlspecialchars($si, ENT_XML1, 'UTF-8');
file_put_contents('/singbox/winsw3.xml', preg_replace('#~url~#', $link, file_get_contents('/singbox/winsw3.xml'))); $n = "singbox_$uid.zip";
$n = "singbox_$uid.zip";
copy('/singbox/singbox.zip', $n); copy('/singbox/singbox.zip', $n);
$zip = new ZipArchive(); $zip = new ZipArchive();
$zip->open($n, ZipArchive::CREATE); $zip->open($n, ZipArchive::CREATE);
$zip->addFile('/singbox/winsw3.xml', 'winsw3.xml'); $zip->addFromString('winsw3.xml', preg_replace('#~url~#', $link, file_get_contents('/singbox/winsw3.xml')));
$zip->close(); $zip->close();
header('Content-Disposition: attachment; filename="singbox.zip"'); header('Content-Disposition: attachment; filename="singbox.zip"');
echo file_get_contents($n); echo file_get_contents($n);
@@ -4862,9 +5002,9 @@ DNS-over-HTTPS with IP:
switch ($_GET['t']) { switch ($_GET['t']) {
case 's': case 's':
$c['outbounds'][0]['settings']['vnext'][0]['address'] = $domain; $c['outbounds'][0]['settings']['vnext'][0]['address'] = '~domain~';
$c['outbounds'][0]['settings']['vnext'][0]['users'][0] = [ $c['outbounds'][0]['settings']['vnext'][0]['users'][0] = [
'id' => $uid, 'id' => '~uid~',
'encryption' => 'none', 'encryption' => 'none',
]; ];
if ($pac['transport'] == 'Websocket') { if ($pac['transport'] == 'Websocket') {
@@ -4876,7 +5016,7 @@ DNS-over-HTTPS with IP:
], ],
"tlsSettings" => [ "tlsSettings" => [
"allowInsecure" => false, "allowInsecure" => false,
"serverName" => $domain, "serverName" => '~domain~',
"fingerprint" => "chrome" "fingerprint" => "chrome"
] ]
]; ];
@@ -4887,10 +5027,10 @@ DNS-over-HTTPS with IP:
"network" => "tcp", "network" => "tcp",
"security" => "reality", "security" => "reality",
"realitySettings" => [ "realitySettings" => [
"serverName" => $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0], "serverName" => '~server_name~',
"fingerprint" => "chrome", "fingerprint" => "chrome",
"publicKey" => $pac['xray'], "publicKey" => '~public_key~',
"shortId" => $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0], "shortId" => '~short_id~',
] ]
]; ];
$c['outbounds'][0]['mux'] = [ $c['outbounds'][0]['mux'] = [
@@ -4898,24 +5038,10 @@ DNS-over-HTTPS with IP:
"concurrency" => -1 "concurrency" => -1
]; ];
} }
foreach ($c['routing']['rules'] as $k => $v) {
if (array_key_exists('domain', $v) && $v['domain'] == '~pac~') {
$c['routing']['rules'][$k]['domain'] = array_keys(array_filter($pac['includelist'] ?: []));
if (empty($c['routing']['rules'][$k]['domain'])) {
unset($c['routing']['rules'][$k]);
}
}
}
$c['routing']['rules'] = array_values($c['routing']['rules']);
break; break;
case 'si': case 'si':
if ($c['dns']['servers'][0]['address'] == '~dns~') { $c['outbounds'][0]['server'] = '~domain~';
$c['dns']['servers'][0]['address'] = "https://$domain/dns-query/$uid"; $c['outbounds'][0]['uuid'] = '~uid~';
}
$c['outbounds'][0]['server'] = $domain;
$c['outbounds'][0]['uuid'] = $uid;
if ($pac['transport'] == 'Websocket') { if ($pac['transport'] == 'Websocket') {
unset($c['outbounds'][0]['tls']['reality']); unset($c['outbounds'][0]['tls']['reality']);
unset($c['outbounds'][0]['flow']); unset($c['outbounds'][0]['flow']);
@@ -4923,56 +5049,60 @@ DNS-over-HTTPS with IP:
"type" => "ws", "type" => "ws",
"path" => "/ws" "path" => "/ws"
]; ];
$c['outbounds'][0]['tls']['server_name'] = $domain; $c['outbounds'][0]['tls']['server_name'] = '~domain~';
} else { } else {
unset($c['outbounds'][0]["transport"]); unset($c['outbounds'][0]["transport"]);
$c['outbounds'][0]['flow'] = 'xtls-rprx-vision'; $c['outbounds'][0]['flow'] = 'xtls-rprx-vision';
$c['outbounds'][0]['tls']['reality']['public_key'] = $pac['xray']; $c['outbounds'][0]['tls']['reality']['public_key'] = '~public_key~';
$c['outbounds'][0]['tls']['server_name'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0]; $c['outbounds'][0]['tls']['server_name'] = '~server_name~';
$c['outbounds'][0]['tls']['reality']['short_id'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0]; $c['outbounds'][0]['tls']['reality']['short_id'] = '~short_id~';
} }
foreach ($c['route']['rules'] as $k => $v) { $c['route'] = $this->addRuleSet($c['route']);
if (array_key_exists('domain_suffix', $v) && $v['domain_suffix'] == '~pac~') { $c['route'] = $this->createRuleSet($c['route'], $uid, $domain);
$c['route']['rules'][$k]['domain_suffix'] = array_keys(array_filter($pac['includelist'] ?: []));
if (empty($c['route']['rules'][$k]['domain_suffix'])) {
unset($c['route']['rules'][$k]);
}
}
}
$c['route']['rules'] = array_values($c['route']['rules']);
$c['route'] = $this->addRuleSet($c['route']);
$c['route'] = $this->addPackageRule($c['route']);
$c['route'] = $this->createRuleSet($c['route'], $uid, $domain);
$c['route'] = $this->clearEmptyRules($c['route']);
break; break;
} }
$json = $this->replaceTags(json_encode($c), [
'"~pac~"' => json_encode(array_keys(array_filter($pac['includelist'] ?: []))),
'~dns~' => "https://$domain/dns-query/$uid",
'~uid~' => $uid,
'~domain~' => $domain,
'~short_id~' => $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0],
'~public_key~' => $pac['xray'],
'~server_name~' => $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0],
]);
$json = $this->clearEmptyRules($json);
header('Content-type: application/json'); header('Content-type: application/json');
echo json_encode($c); echo $json;
} }
public function clearEmptyRules($route) public function replaceTags($subject, $tags)
{ {
foreach ($route['rules'] as $k => $v) { return str_replace(array_keys($tags), array_values($tags), $subject);
if (count($v) == 1) { }
unset($route['rules'][$k]);
public function clearEmptyRules($json)
{
$json = json_decode($json, 1);
if (!empty($json['routing']['rules'])) {
foreach ($json['routing']['rules'] as $k => $v) {
if (array_key_exists('domain', $v) && empty($v['domain'])) {
unset($json['routing']['rules'][$k]);
}
} }
$json['routing']['rules'] = array_values($json['routing']['rules']);
} }
$route['rules'] = array_values($route['rules']); if (!empty($json['route']['rules'])) {
return $route; foreach ($json['route']['rules'] as $k => $v) {
} if (count($v) < 2) {
unset($json['route']['rules'][$k]);
public function addPackageRule($route) }
{ }
$p = $this->getPacConf(); $json['route']['rules'] = array_values($json['route']['rules']);
if (!empty($t = array_filter($p['packagelist'] ?: []))) {
$route['rules'][] = [
'package_name' => array_keys($t),
'outbound' => $p['app_outbound'] ? 'direct' : 'proxy',
];
} }
return $route; return json_encode($json);
} }
public function addRuleSet($route) public function addRuleSet($route)
@@ -5008,25 +5138,38 @@ DNS-over-HTTPS with IP:
foreach ($route['rules'] as $k => $v) { foreach ($route['rules'] as $k => $v) {
if (!empty($v['createruleset'])) { if (!empty($v['createruleset'])) {
foreach ($v['createruleset'] as $i => $r) { foreach ($v['createruleset'] as $r) {
foreach ($r['rules'] as $l => $n) { foreach ($r['rules'] as $l => $n) {
if (array_key_exists('domain_suffix', $n) && $n['domain_suffix'] == '~pac~') { switch (true) {
$r['rules'][$l]['domain_suffix'] = array_keys(array_filter($pac['includelist'] ?: [])); case array_key_exists('domain_suffix', $n):
if (empty($r['rules'][$l]['domain_suffix'])) { switch ($n['domain_suffix']) {
unset($r['rules'][$l]); case '~pac~':
} $t = 'includelist';
} break;
if (array_key_exists('domain_suffix', $n) && $n['domain_suffix'] == '~warp~') { case '~warp~':
$r['rules'][$l]['domain_suffix'] = array_keys(array_filter($pac['warplist'] ?: [])); $t = 'warplist';
if (empty($r['rules'][$l]['domain_suffix'])) { break;
unset($r['rules'][$l]); case '~block~':
} $t = 'blocklist';
} break;
if (array_key_exists('domain_suffix', $n) && $n['domain_suffix'] == '~block~') { }
$r['rules'][$l]['domain_suffix'] = array_keys(array_filter($pac['blocklist'] ?: [])); $r['rules'][$l]['domain_suffix'] = array_keys(array_filter($pac[$t] ?: []));
if (empty($r['rules'][$l]['domain_suffix'])) { if (empty($r['rules'][$l]['domain_suffix'])) {
unset($r['rules'][$l]); unset($r['rules'][$l]);
} }
break;
case array_key_exists('package_name', $n):
$r['rules'][$l]['package_name'] = array_keys(array_filter($pac['packagelist'] ?: []));
if (empty($r['rules'][$l]['package_name'])) {
unset($r['rules'][$l]);
}
break;
case array_key_exists('process_name', $n):
$r['rules'][$l]['process_name'] = array_keys(array_filter($pac['processlist'] ?: []));
if (empty($r['rules'][$l]['process_name'])) {
unset($r['rules'][$l]);
}
break;
} }
} }
if (!empty($_GET['r']) && $r['name'] == $_GET['r']) { if (!empty($_GET['r']) && $r['name'] == $_GET['r']) {
@@ -5045,18 +5188,23 @@ DNS-over-HTTPS with IP:
} }
$ruleset[] = [ $ruleset[] = [
"tag" => $r['name'], "tag" => $r['name'],
"url" => "$scheme://{$domain}/pac?" . http_build_query([ "url" => "$scheme://{$domain}/pac/" . base64_encode(serialize([
'h' => $hash, 'h' => $hash,
't' => 'si', 't' => 'si',
's' => $uid, 's' => $uid,
'r' => $r['name'], 'r' => $r['name'],
]), ])),
"update_interval" => $r['interval'], "update_interval" => $r['interval'],
"type" => "remote", "type" => "remote",
"format" => "binary", "format" => "binary",
"download_detour" => "direct", "download_detour" => "direct",
]; ];
$route['rules'][$k]['rule_set'][] = $r['name']; $route['rules'][$k]['rule_set'][] = $r['name'];
switch (true) {
case preg_match('#~(.+)~#', $route['rules'][$k]['outbound'], $m):
$route['rules'][$k]['outbound'] = $pac[$m[1]] ? 'direct' : 'proxy';
break;
}
} }
unset($route['rules'][$k]['createruleset']); unset($route['rules'][$k]['createruleset']);
if (empty($route['rules'][$k]['rule_set'])) { if (empty($route['rules'][$k]['rule_set'])) {
@@ -5226,6 +5374,11 @@ DNS-over-HTTPS with IP:
$text .= "DNS over HTTPS:\n<code>$ip</code>\n<code>$scheme://$domain/dns-query" . ($conf['adguardkey'] ? "/{$conf['adguardkey']}" : '') . "</code>\n\n"; $text .= "DNS over HTTPS:\n<code>$ip</code>\n<code>$scheme://$domain/dns-query" . ($conf['adguardkey'] ? "/{$conf['adguardkey']}" : '') . "</code>\n\n";
$text .= "DNS over TLS:\n<code>tls://" . ($conf['adguardkey'] ? "{$conf['adguardkey']}." : '') . "$domain</code>"; $text .= "DNS over TLS:\n<code>tls://" . ($conf['adguardkey'] ? "{$conf['adguardkey']}." : '') . "$domain</code>";
} }
$safesearch = yaml_parse_file($this->adguard)['filtering']['safe_search']['enabled'];
$text .= "\n\nsafesearch: " . $this->i18n($safesearch ? 'on' : 'off');
$allowedClients = yaml_parse_file($this->adguard)['dns']['allowed_clients'];
$text .= $allowedClients ? "\n\nallowed clients: \n - " . implode("\n - ", $allowedClients) : '';
$data = [ $data = [
[ [
[ [
@@ -5250,6 +5403,16 @@ DNS-over-HTTPS with IP:
], ],
], ],
]; ];
$data[] = [
[
'text' => $this->i18n('fill allowed clients'),
'callback_data' => "/adgFillAllowedClients 0",
],
[
'text' => $this->i18n('delete allowed clients'),
'callback_data' => "/adgFillAllowedClients 1",
],
];
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('add upstream'), 'text' => $this->i18n('add upstream'),
@@ -5287,6 +5450,34 @@ DNS-over-HTTPS with IP:
]; ];
} }
public function adgFillAllowedClients($delete = false)
{
$pac = $this->getPacConf();
$out[] = 'Restart Adguard Home';
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
$this->stopAd();
$c = yaml_parse_file($this->adguard);
if (!empty($delete)) {
unset($c['dns']['allowed_clients']);
} else {
$c['dns']['allowed_clients'] = [];
if (!empty($pac['adguardKey'])) {
$c['dns']['allowed_clients'][] = $pac['adguardKey'];
}
$c['dns']['allowed_clients'][] = getenv('WGADDRESS');
$c['dns']['allowed_clients'][] = getenv('WG1ADDRESS');
$c['dns']['allowed_clients'][] = '10.0.2.0/24'; // openconnect
if (!empty($xr = $this->getXray())) {
foreach ($xr['inbounds'][0]['settings']['clients'] as $v) {
$c['dns']['allowed_clients'][] = $v['id'];
}
}
}
yaml_emit_file($this->adguard, $c);
$this->startAd();
$this->menu('adguard');
}
public function menuLang() public function menuLang()
{ {
$data = []; $data = [];
@@ -5362,7 +5553,7 @@ DNS-over-HTTPS with IP:
]; ];
exec("git -C / branch -vv", $mm); exec("git -C / branch -vv", $mm);
return [ return [
'text' => '<pre><code class="language-shell">' . implode("\n", $mm) . '</code></pre>', 'text' => '<pre><code class="language-shell">' . htmlentities(implode("\n", $mm)) . '</code></pre>',
'data' => $data, 'data' => $data,
]; ];
} }
@@ -5494,7 +5685,11 @@ DNS-over-HTTPS with IP:
]; ];
$backup = array_filter(explode('/', $conf['backup'])); $backup = array_filter(explode('/', $conf['backup']));
if (!empty($backup)) { if (!empty($backup)) {
$backup = "{$backup[0]} start / {$backup[1]} period"; if (!empty(strtotime($backup[0])) && !empty(strtotime($backup[1]))) {
$backup = "{$backup[0]} start / {$backup[1]} period";
} else {
$backup = $this->i18n('off') . " {$conf['backup']} - wrong format";
}
} }
$data[] = [ $data[] = [
[ [
@@ -5502,6 +5697,12 @@ DNS-over-HTTPS with IP:
'callback_data' => "/backup", 'callback_data' => "/backup",
], ],
]; ];
$data[] = [
[
'text' => $this->i18n('fake html'),
'callback_data' => "/addOverrideHtml",
],
];
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('logs'), 'text' => $this->i18n('logs'),
@@ -5633,13 +5834,35 @@ DNS-over-HTTPS with IP:
$this->logs(); $this->logs();
} }
public function selfUpdate()
{
$ip = getenv('IP');
$rm = explode(':', trim(file_get_contents('/update/reload_message')));
$m = file_get_contents('/update/message');
$this->input['chat'] = $rm[0];
$this->input['message_id'] = $rm[1];
$this->input['callback_id'] = $rm[1];
if (file_exists($this->update)) {
if (!empty($m)) {
$this->send($this->input['chat'], "<pre>$m</pre>", $rm[1]);
}
$r = $this->send($this->input['chat'], "import settings");
$this->input['message_id'] = $r['result']['message_id'];
$this->input['callback_id'] = $r['result']['message_id'];
$this->importFile($this->update);
unlink($this->update);
}
file_put_contents('/update/message', '');
file_put_contents('/update/reload_message', '');
}
public function backup() public function backup()
{ {
$r = $this->send( $r = $this->send(
$this->input['chat'], $this->input['chat'],
"@{$this->input['username']} enter like start / period", "@{$this->input['username']} enter like: start / period",
$this->input['message_id'], $this->input['message_id'],
reply: 'enter like now / 12:00', reply: 'enter like: now / 12 hours',
); );
$_SESSION['reply'][$r['result']['message_id']] = [ $_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'], 'start_message' => $this->input['message_id'],
@@ -5765,7 +5988,11 @@ DNS-over-HTTPS with IP:
$c['backup'] = ''; $c['backup'] = '';
} else { } else {
[$start, $period] = explode('/', $text); [$start, $period] = explode('/', $text);
$c['backup'] = implode(' / ', [date('Y-m-d H:i', strtotime($start)), trim($period)]); if (!empty(strtotime($start)) && !empty(strtotime($period))) {
$c['backup'] = implode(' / ', [date('Y-m-d H:i', strtotime($start)), trim($period)]);
} else {
$this->send($this->input['from'], $this->input['message'] . ' - wrong format');
}
} }
if ($c['pinbackup']) { if ($c['pinbackup']) {
$this->pinAdmin($c['pinbackup'], 1); $this->pinAdmin($c['pinbackup'], 1);
@@ -5883,25 +6110,25 @@ DNS-over-HTTPS with IP:
public function createConfig($data) public function createConfig($data)
{ {
$pac = $this->getPacConf();
$conf[] = "[Interface]"; $conf[] = "[Interface]";
if (empty($data['interface']['ListenPort'])) { if (empty($data['interface']['ListenPort'])) {
if (empty($data['interface']['DNS'])) { if (empty($data['interface']['DNS'])) {
$data['interface']['DNS'] = $this->getPacConf()[$this->getInstanceWG(1) . 'dns'] ?: $this->dns; $data['interface']['DNS'] = $pac[$this->getInstanceWG(1) . 'dns'] ?: $this->dns;
} }
if (empty($data['interface']['MTU'])) { if (empty($data['interface']['MTU'])) {
$data['interface']['MTU'] = $this->getPacConf()[$this->getInstanceWG(1) . 'mtu'] ?: $this->mtu; $data['interface']['MTU'] = $pac[$this->getInstanceWG(1) . 'mtu'] ?: $this->mtu;
} }
} }
foreach ($data['interface'] as $k => $v) { foreach ($data['interface'] as $k => $v) {
$conf[] = "$k = $v"; $conf[] = "$k = $v";
} }
$pac = $this->getPacConf();
if (!empty($data['peers'])) { if (!empty($data['peers'])) {
foreach ($data['peers'] as $peer) { foreach ($data['peers'] as $peer) {
$conf[] = ''; $conf[] = '';
$conf[] = $peer['# PublicKey'] ? '# [Peer]' : '[Peer]'; $conf[] = $peer['# PublicKey'] ? '# [Peer]' : '[Peer]';
if (!empty($peer['Endpoint'])) { if (!empty($peer['Endpoint'])) {
$peer['Endpoint'] = ($this->getPacConf()[$this->getInstanceWG(1) . 'endpoint'] ? $this->ip : $this->getDomain()) . ":" . getenv($this->getInstanceWG(1) ? 'WG1PORT' : 'WGPORT'); $peer['Endpoint'] = ($pac[$this->getInstanceWG(1) . 'endpoint'] ? $this->ip : $this->getDomain()) . ":" . getenv($this->getInstanceWG(1) ? 'WG1PORT' : 'WGPORT');
} }
foreach ($peer as $k => $v) { foreach ($peer as $k => $v) {
$conf[] = "$k = $v"; $conf[] = "$k = $v";
+1 -2
View File
@@ -7,5 +7,4 @@ require __DIR__ . '/bot.php';
require __DIR__ . '/config.php'; require __DIR__ . '/config.php';
require __DIR__ . '/i18n.php'; require __DIR__ . '/i18n.php';
$bot = new Bot($c['key'], $i); (new Bot($c['key'], $i))->cron();
$bot->cron();
+8
View File
@@ -337,4 +337,12 @@ $i = [
'en' => '🟢 have updates', 'en' => '🟢 have updates',
'ru' => '🟢 есть обновления', 'ru' => '🟢 есть обновления',
], ],
'fake html' => [
'en' => 'fake html',
'ru' => 'фейк заглушка',
],
'expose-iroutes' => [
'en' => 'expose-iroutes',
'ru' => 'изоляция клиентов',
],
]; ];
+3
View File
@@ -11,6 +11,9 @@ if ('POST' == $_SERVER['REQUEST_METHOD'] && $_GET['k'] == $c['key']) {
require __DIR__ . '/calc.php'; require __DIR__ . '/calc.php';
require __DIR__ . '/bot.php'; require __DIR__ . '/bot.php';
require __DIR__ . '/i18n.php'; require __DIR__ . '/i18n.php';
if (file_exists(__DIR__ . '/override.php')) {
include __DIR__ . '/override.php';
}
$bot = new Bot($c['key'], $i); $bot = new Bot($c['key'], $i);
$bot->input(); $bot->input();
exit; exit;
+5 -4
View File
@@ -10,8 +10,9 @@ if ($c['debug']) {
} }
$bot = new Bot($c['key'], $i); $bot = new Bot($c['key'], $i);
$bot->adguardProtect(); $bot->cleanQueue();
$bot->adguardCheckPswd();
$bot->setcommands();
$bot->syncPortClients();
$bot->setwebhook(); $bot->setwebhook();
$bot->adguardCheckPswd();
$bot->adguardProtect();
$bot->syncPortClients();
$bot->setcommands();
+3 -26
View File
@@ -12,32 +12,9 @@ if ($c['debug']) {
$bot = new Bot($c['key'], $i); $bot = new Bot($c['key'], $i);
if (!empty($c['admin'])) { $bot->selfUpdate();
$ip = getenv('IP');
$rm = explode(':', trim(file_get_contents('/update/reload_message')));
$m = file_get_contents('/update/message');
foreach ($c['admin'] as $k => $v) {
$r = $bot->send($v, "start $ip");
$bot->input['chat'] = $v;
$bot->input['message_id'] = $r['result']['message_id'];
if (file_exists($bot->update)) {
if (!empty($m)) {
$bot->send($v, "<pre>$m</pre>", $v == $rm[0] ? $rm[1] : 0);
}
$r = $bot->send($v, "import settings");
$bot->input['chat'] = $v;
$bot->input['message_id'] = $r['result']['message_id'];
$bot->input['callback_id'] = $r['result']['message_id'];
if (empty($flag)) {
$bot->importFile($bot->update);
unlink($bot->update);
$flag = true;
}
}
}
}
file_put_contents('/update/message', '');
file_put_contents('/update/reload_message', '');
$bot->restartTG(); $bot->restartTG();
$bot->offWarp(0);
$bot->dontshowcron = 1;
$bot->sslip(); $bot->sslip();
$bot->cleanDocker(); $bot->cleanDocker();
+3
View File
@@ -16,5 +16,8 @@ dns:
tls: tls:
certificate_path: /certs/cert_public certificate_path: /certs/cert_public
private_key_path: /certs/cert_private private_key_path: /certs/cert_private
filtering:
safe_search:
enabled: false
log: log:
file: /logs/adguard file: /logs/adguard
+2 -2
View File
@@ -31,7 +31,7 @@ http {
location / { location / {
root /app; root /app;
index login.html; index override.html login.html;
try_files $uri $uri/ =404; try_files $uri $uri/ =404;
} }
location /adguard/ { location /adguard/ {
@@ -123,7 +123,7 @@ http {
# location / { # location / {
# root /app; # root /app;
# index login.html; # index override.html login.html;
# try_files $uri $uri/ =404; # try_files $uri $uri/ =404;
# } # }
# location /adguard/ { # location /adguard/ {
+2 -2
View File
@@ -31,7 +31,7 @@ http {
location / { location / {
root /app; root /app;
index login.html; index override.html login.html;
try_files $uri $uri/ =404; try_files $uri $uri/ =404;
} }
location /adguard/ { location /adguard/ {
@@ -123,7 +123,7 @@ http {
# location / { # location / {
# root /app; # root /app;
# index login.html; # index override.html login.html;
# try_files $uri $uri/ =404; # try_files $uri $uri/ =404;
# } # }
# location /adguard/ { # location /adguard/ {
+2 -2
View File
@@ -180,7 +180,7 @@ server-key = /certs/cert_private
# the isolation was tested at. If you get random failures on worker processes, try # the isolation was tested at. If you get random failures on worker processes, try
# disabling that option and report the failures you, along with system and debugging # disabling that option and report the failures you, along with system and debugging
# information at: https://gitlab.com/openconnect/ocserv/issues # information at: https://gitlab.com/openconnect/ocserv/issues
isolate-workers = true isolate-workers = false
# A banner to be displayed on clients after connection # A banner to be displayed on clients after connection
#banner = "Welcome" #banner = "Welcome"
@@ -584,7 +584,7 @@ route = default
# When set to true, all client's iroutes are made visible to all # When set to true, all client's iroutes are made visible to all
# connecting clients except for the ones offering them. This option # connecting clients except for the ones offering them. This option
# only makes sense if config-per-user is set. # only makes sense if config-per-user is set.
#expose-iroutes = true expose-iroutes = false
# Groups that a client is allowed to select from. # Groups that a client is allowed to select from.
# A client may belong in multiple groups, and in certain use-cases # A client may belong in multiple groups, and in certain use-cases
+1 -99
View File
@@ -1,99 +1 @@
{ {}
"zapret": false,
"excludelist": {
"(?:v|w)ul(?:c|k)an": true,
"^\\d": true,
"^a\\w-": true,
"^admiral": true,
"^avtomaty": true,
"^azart": true,
"^azimob": true,
"^baltplay": true,
"a(?:s|z)ino": true,
"adrenalin": true,
"alco": true,
"bet": true,
"prostitut": true,
"zenit": true,
"zerkalo": true,
"777": true
},
"includelist": {},
"reverselist": {},
"subzoneslist": {
"3dn": false,
"3nx": true,
"akadns": true,
"appspot": true,
"azurewebsites": true,
"beget": true,
"berlogovo": true,
"biz": true,
"brightcove": true,
"cc": true,
"cloudfront": true,
"co": true,
"com": true,
"cu": true,
"ddns": true,
"deviantart": true,
"dn": true,
"dp": true,
"dyndns": true,
"edgecastcdn": true,
"edu": true,
"eu": true,
"fastly": true,
"force": true,
"github": true,
"google": true,
"googleusercontent": true,
"gov": true,
"herokuapp": true,
"hldns": true,
"ho": true,
"hopto": true,
"hwcdn": true,
"i": true,
"iboards": true,
"in": true,
"info": true,
"int": true,
"itch": true,
"keenetic": true,
"kiev": true,
"kirov": true,
"linode": true,
"livejournal": true,
"maryno": true,
"mil": true,
"msk": true,
"my1": true,
"mybb2": true,
"ne": true,
"net": true,
"netdna-ssl": true,
"nnov": true,
"notion": true,
"nov": true,
"od": true,
"org": true,
"pp": true,
"pximg": true,
"pythonanywhere": true,
"ru": true,
"scaleway": true,
"sl": true,
"sl-reverse": true,
"spb": true,
"tilda": true,
"trafficmanager": true,
"tut": true,
"u-stream": true,
"ucoz": true,
"v": true,
"vercel": true,
"wix": true,
"wixmp": true
}
}
+42 -14
View File
@@ -110,6 +110,48 @@
"protocol": "dns", "protocol": "dns",
"outbound": "dns-out" "outbound": "dns-out"
}, },
{
"createruleset": [
{
"name": "package",
"interval": "15s",
"rules": [
{
"package_name": "~package~"
}
]
}
],
"outbound": "~app_outbound~"
},
{
"createruleset": [
{
"name": "process",
"interval": "15s",
"rules": [
{
"process_name": "~process~"
}
]
}
],
"outbound": "~process_outbound~"
},
{
"createruleset": [
{
"name": "block",
"interval": "15s",
"rules": [
{
"domain_suffix": "~block~"
}
]
}
],
"outbound": "block"
},
{ {
"createruleset": [ "createruleset": [
{ {
@@ -133,20 +175,6 @@
], ],
"outbound": "proxy" "outbound": "proxy"
}, },
{
"createruleset": [
{
"name": "block",
"interval": "15s",
"rules": [
{
"domain_suffix": "~block~"
}
]
}
],
"outbound": "block"
},
{ {
"outbound": "direct" "outbound": "direct"
} }
+5 -2
View File
@@ -16,6 +16,7 @@ networks:
- subnet: 10.10.1.0/24 - subnet: 10.10.1.0/24
volumes: volumes:
adguard: adguard:
warp:
services: services:
up: up:
@@ -33,7 +34,8 @@ services:
- ./config/sshd_config:/etc/ssh/sshd_config - ./config/sshd_config:/etc/ssh/sshd_config
- ./logs/:/logs/ - ./logs/:/logs/
ports: ports:
- 443:443 - 443:443/tcp
- 443:443/udp
hostname: upstream hostname: upstream
container_name: upstream-${VER} container_name: upstream-${VER}
depends_on: depends_on:
@@ -127,7 +129,7 @@ services:
required: false required: false
hostname: php hostname: php
container_name: php-${VER} container_name: php-${VER}
restart: unless-stopped # restart: unless-stopped
stop_grace_period: 1s stop_grace_period: 1s
command: ["/bin/sh", "/start_php.sh"] command: ["/bin/sh", "/start_php.sh"]
working_dir: /app working_dir: /app
@@ -509,6 +511,7 @@ services:
- ./config:/config - ./config:/config
- ./certs:/certs - ./certs:/certs
- ./scripts/start_wp.sh:/start_wp.sh - ./scripts/start_wp.sh:/start_wp.sh
- warp:/var/lib/cloudflare-warp
hostname: warp hostname: warp
container_name: warp-${VER} container_name: warp-${VER}
depends_on: depends_on:
+2 -1
View File
@@ -1,9 +1,10 @@
b: b:
docker compose build docker compose build
u: # запуск контейнеров u: # запуск контейнеров
$(eval IP := $(shell curl -s -t 1 2ip.io || curl -s -t 1 ipinfo.io/ip || curl -s -t 1 ifconfig.me))
bash ./update/update.sh & bash ./update/update.sh &
touch ./override.env touch ./override.env
IP=$(shell curl ipinfo.io/ip) VER=$(shell git describe --tags) docker compose --env-file ./.env --env-file ./override.env up -d --force-recreate IP=$(IP) VER=$(shell git describe --tags) docker compose --env-file ./.env --env-file ./override.env up -d --force-recreate
d: # остановка контейнеров d: # остановка контейнеров
-kill -9 $(shell cat ./update/update_pid) > /dev/null -kill -9 $(shell cat ./update/update_pid) > /dev/null
docker compose down --remove-orphans docker compose down --remove-orphans
+9 -5
View File
@@ -2,8 +2,12 @@ rm /ssh/key*
ssh-keygen -m PEM -t rsa -f /ssh/key -N '' ssh-keygen -m PEM -t rsa -f /ssh/key -N ''
openssl req -newkey rsa:2048 -sha256 -nodes -x509 -days 365 -keyout /certs/self_private -out /certs/self_public -subj "/C=NN/ST=N/L=N/O=N/CN=$IP" openssl req -newkey rsa:2048 -sha256 -nodes -x509 -days 365 -keyout /certs/self_private -out /certs/self_public -subj "/C=NN/ST=N/L=N/O=N/CN=$IP"
php init.php php init.php
php cron.php & if [[ -f "/start" && -f "/ssh/key.pub" && -s "/ssh/key.pub" ]]; then
unitd --log /logs/unit_error php cron.php &
curl -X PUT --data-binary @/config/unit.json --unix-socket /var/run/control.unit.sock http://localhost/config unitd --log /logs/unit_error
pkill unitd curl -X PUT --data-binary @/config/unit.json --unix-socket /var/run/control.unit.sock http://localhost/config
unitd --no-daemon --control 0.0.0.0:8080 --log /logs/unit_error pkill unitd
unitd --no-daemon --control 0.0.0.0:8080 --log /logs/unit_error
else
exit 1;
fi
+6 -3
View File
@@ -7,10 +7,13 @@ if [ "$off" == 'null' ]
then then
warp-svc > /dev/null & warp-svc > /dev/null &
sleep 3 sleep 3
warp-cli --accept-tos registration new if [ ! -f /var/lib/cloudflare-warp/conf.json ]
if [ ! -z "$key" ]
then then
warp-cli --accept-tos registration license $key warp-cli --accept-tos registration new
if [ ! -z "$key" ]
then
warp-cli --accept-tos registration license $key
fi
fi fi
warp-cli --accept-tos mode proxy warp-cli --accept-tos mode proxy
warp-cli --accept-tos connect warp-cli --accept-tos connect
Binary file not shown.
+73
View File
@@ -1,3 +1,76 @@
26.10.2024 v1.89
- xray rulesset: фикс меню при отсутствующих правилах
26.10.2024 v1.88
- xray rulesset: дублирование кнопок текстом
- singbox 1.10.1 для windows x64
- фикс с включенным warp после апдейта
- фикс с нерабочей кнопкой апдейта, обновится можно через /autoupdate если поймали не рабочую кнопку апдейта
25.10.2024 v1.87
- xray: в routes добавлен раздел proxy - зеркало раздела Pac
25.10.2024 v1.86
- фикс не срабатывания автобэкапа во время старта
- adguard: вывод списка разрешенных клиентов
- adguard: кнопка заполнения разрешенных клиентов - собирает все clientId со всех контейнеров
- adguard: вывод статуса безопасного поиска
- warp: при выключении удаляется регистрация deviceid
24.10.2024 v1.85
- фикс удаления состояния warp после рестарта
- возможность перезаписать фразы меню бота через app/override.php
24.10.2024 v1.84
- фикс показа ссылки для openconnect
24.10.2024 v1.83
- фикс ошибок доступа контейнеров при автообновлении
23.10.2024 v1.82
- фикс автобэкапа
23.10.2024 v1.81
- фикс краша wireguard после апдейта
23.10.2024 v1.80
- фикс пустых правил для singbox
23.10.2024 v1.79
- улучшение процесса обновления
23.10.2024 v1.78
- фикс двойного импорта при обновлении, когда админов больше одного
- рестарт бота сбрасывает очередь сообщений от телеграма
- при старте статус крона не показывается, т.к он еще не успел запуститься
23.10.2024 v1.77
- вывод статуса cron
- фикс с отправкой бэкапа при спецсимволах в названии бота
- проверка формата времени в автобэкапе
22.10.2024 v1.76
- улучшение определения ip бота при старте
22.10.2024 v1.75
- openconnect: isolate-workers = false
21.10.2024 v1.74
- openconnect: expose-iroutes on/off
21.10.2024 v1.73
- openconnect: ограничение контейнера по цпу и памяти
21.10.2024 v1.72
- xray: теги в кастомных шаблонах
21.10.2024 v1.71
- фикс установки nip.io при первом запуске
- фикс инициализации вебпанели adguardHome при первом запуске
14.10.2024 v1.70
- xray route: учет регистра в process_name, package_name
14.10.2024 v1.69
- xray route: добавлен список process_name
14.10.2024 v1.68
- singbox template: package_name -> ruleset
13.10.2024 v1.67
- sslip.io -> nip.io
13.10.2024 v1.66
- singbox template: изменен порядок правил маршрутизации для package_name
10.10.2024 v1.65.1
- фикс создания архива windows service singbox 2
09.10.2024 v1.65
- фикс создания архива windows service singbox
06.10.2024 v1.64.1
- добавление html заглушки через меню
06.10.2024 v1.64
- возможность установить свою html-заглушку
06.10.2024 v1.63
- приоритет правила block над остальными в стандартном шаблоне sing-box
30.09.2024 v1.62
- импорт профиля xray в karing
30.09.2024 v1.61.1 30.09.2024 v1.61.1
- фикс удаления ключа варпа через ноль - фикс удаления ключа варпа через ноль
29.09.2024 v1.61 29.09.2024 v1.61