Compare commits

...

21 Commits

Author SHA1 Message Date
mercury b227431b7a singbox ruleset 2024-04-19 15:40:45 +04:00
mercury bb83ab0684 warp status on menu 2024-04-18 16:10:13 +04:00
mercury 05267f44be fix naming templates 2024-04-18 15:52:37 +04:00
mercury d1be532270 warp+ set key 2024-04-18 01:58:25 +04:00
mercury 48798c7e61 add restart for singbox window 2024-04-16 23:06:25 +04:00
mercury 84e71ab45b improve mtproto menu 2024-04-16 19:22:21 +04:00
mercury 068f2d0cc9 improve message update 2024-04-16 17:51:23 +04:00
mercury 759cf1973a update version 2024-04-16 17:45:55 +04:00
mercury a11b7e0664 improve update script 2024-04-16 17:43:07 +04:00
mercury d370b78815 refactoring subscription + v2ray templates 2024-04-16 15:20:44 +04:00
mercury 913f75b4a8 improve on/off on paclist 2024-04-15 13:49:14 +04:00
mercury c3e850b102 warp 2024-04-15 13:43:43 +04:00
mercury 3a89a1543b add block and warp list domains for xray 2024-04-15 12:08:43 +04:00
mercury 2a3e8e393c improve timer 2024-04-15 12:04:52 +04:00
mercury 332b74e366 winsw3 + update script for singbox windows 2024-04-14 13:05:55 +04:00
mercury dfa9efec7a fix singbox zip 2024-04-13 19:30:57 +04:00
mercury e1902827ce singbox for windows as service 2024-04-13 19:20:54 +04:00
mercury 95fea3bb7b improve xtls user menu 2024-04-13 04:22:09 +04:00
mercury 80a9f9f32d github btns 2024-04-12 21:38:54 +04:00
mercury 7fc1105728 update readme 2024-04-12 17:05:48 +04:00
mercury d46679caf6 log upstream 2024-04-12 15:47:58 +04:00
25 changed files with 753 additions and 295 deletions
+499 -169
View File
@@ -7,6 +7,8 @@ class Bot
public $update;
public $ip;
public $limit;
public $key;
public $file;
public function __construct($key, $i18n)
{
@@ -123,7 +125,6 @@ class Bot
case preg_match('~^/menu (?P<type>wg) (?P<arg>(?:-)?\d+)$~', $this->input['callback'], $m):
case preg_match('~^/menu (?P<type>client) (?P<arg>\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
case preg_match('~^/menu (?P<type>pac|adguard|config|ss|lang|oc|naive|mirror|update)$~', $this->input['callback'], $m):
case preg_match('~^/menu (?P<type>subzoneslist|reverselist|includelist|excludelist) (?P<arg>(?:-)?\d+)$~', $this->input['callback'], $m):
$this->menu(type: $m['type'] ?? false, arg: $m['arg'] ?? false);
break;
case preg_match('~^/changeWG (\d+)$~', $this->input['callback'], $m):
@@ -285,11 +286,11 @@ class Bot
case preg_match('~^/userXr (\d+)$~', $this->input['callback'], $m):
$this->userXr($m[1]);
break;
case preg_match('~^/choiceTemplate (\d+(?:_.+)?)$~', $this->input['callback'], $m):
case preg_match('~^/choiceTemplate (.+)$~', $this->input['callback'], $m):
$this->choiceTemplate($m[1]);
break;
case preg_match('~^/templateUser (\d+)$~', $this->input['callback'], $m):
$this->templateUser($m[1]);
case preg_match('~^/templateUser (\w+) (\d+)$~', $this->input['callback'], $m):
$this->templateUser($m[1], $m[2]);
break;
case preg_match('~^/timerXr (\d+)$~', $this->input['callback'], $m):
$this->timerXr($m[1]);
@@ -349,7 +350,7 @@ class Bot
case preg_match('~^/deldomain$~', $this->input['callback'], $m):
$this->delDomain();
break;
case preg_match('~^/(?P<action>change|delete)(?P<typelist>includelist) (?P<arg>[^\s]+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
case preg_match('~^/(?P<action>change|delete)(?P<typelist>\w+) (?P<arg>[^\s]+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
$this->listPacChange($m['typelist'], $m['action'], ...explode('_', $m['arg']));
break;
case preg_match('~^/paczapret$~', $this->input['callback'], $m):
@@ -367,23 +368,35 @@ class Bot
case preg_match('~^/domain$~', $this->input['callback'], $m):
$this->domain();
break;
case preg_match('~^/warp$~', $this->input['callback'], $m):
$this->warp();
break;
case preg_match('~^/warpPlus$~', $this->input['callback'], $m):
$this->warpPlus();
break;
case preg_match('~^/xray(?: (\d+))?$~', $this->input['callback'], $m):
$this->xray($m[1] ?: 0);
break;
case preg_match('~^/delTemplate(?: (.+))?$~', $this->input['callback'], $m):
$this->delTemplate($m[1] ?: 0);
case preg_match('~^/xtlsblock(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsblock($m[1] ?: 0);
break;
case preg_match('~^/downloadTemplate(?: (.+))?$~', $this->input['callback'], $m):
$this->downloadTemplate($m[1] ?: 0);
case preg_match('~^/xtlswarp(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlswarp($m[1] ?: 0);
break;
case preg_match('~^/defaultTemplate(?: (.+))?$~', $this->input['callback'], $m):
$this->defaultTemplate($m[1] ?: 0);
case preg_match('~^/delTemplate (\w+)(?: (.+))?$~', $this->input['callback'], $m):
$this->delTemplate($m[1], $m[2]);
break;
case preg_match('~^/singbox(?: (\w+))?$~', $this->input['callback'], $m):
$this->singbox($m[1] ?: false);
case preg_match('~^/downloadTemplate (\w+)(?: (.+))?$~', $this->input['callback'], $m):
$this->downloadTemplate($m[1], $m[2]);
break;
case preg_match('~^/singAdd$~', $this->input['callback'], $m):
$this->singAdd();
case preg_match('~^/defaultTemplate (\w+)(?: (.+))?$~', $this->input['callback'], $m):
$this->defaultTemplate($m[1], $m[2]);
break;
case preg_match('~^/templates (\w+)$~', $this->input['callback'], $m):
$this->templates($m[1]);
break;
case preg_match('~^/templateAdd (\w+)$~', $this->input['callback'], $m):
$this->templateAdd($m[1]);
break;
case preg_match('~^/generateSecretXray$~', $this->input['callback'], $m):
$this->generateSecretXray();
@@ -397,7 +410,7 @@ class Bot
case preg_match('~^/changeTGDomain$~', $this->input['callback'], $m):
$this->changeTGDomain();
break;
case preg_match('~^/include (\d+)$~', $this->input['callback'], $m):
case preg_match('~^/include (\w+)$~', $this->input['callback'], $m):
$this->include($m[1]);
break;
case preg_match('~^/exclude (\d+)$~', $this->input['callback'], $m):
@@ -448,9 +461,9 @@ class Bot
{
$r = $this->send(
$this->input['chat'],
"@{$this->input['username']} enter url",
"@{$this->input['username']} enter key or 0 for stop mtproto",
$this->input['message_id'],
reply: 'enter url',
reply: 'enter key or 0 for stop mtproto',
);
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
@@ -505,10 +518,7 @@ class Bot
public function mtproto()
{
$s = file_get_contents('/config/mtprotosecret');
$d = file_get_contents('/config/mtprotodomain') ?: 'vk.com';
$p = getenv('TGPORT');
$ip = $this->getPacConf()['domain'] ?: $this->ip;
$st = $this->ssh('pgrep mtproto-proxy', 'tg') ? 'on' : 'off';
$text[] = "Menu -> MTProto\n";
$text[] = "status: $st\n";
@@ -987,13 +997,15 @@ class Bot
if (!empty($c['admin']) && (empty($this->time) || ((time() - $this->time) > 3600))) {
$this->time = time();
$current = file_get_contents('/version');
$last = file_get_contents('https://raw.githubusercontent.com/mercurykd/vpnbot/master/version');
$b = exec('git -C / rev-parse --abbrev-ref HEAD');
$last = file_get_contents("https://raw.githubusercontent.com/mercurykd/vpnbot/$b/version");
if (!empty($last) && $last != $this->last && $last != $current) {
$this->last = $last;
$diff = array_slice(explode("\n", $last), 0, count(explode("\n", $last)) - count(explode("\n", $current)));
$diff = array_slice($diff, 0, 10);
if (!empty($diff)) {
foreach ($c['admin'] as $k => $v) {
$this->send($v, "update:\n{$diff[0]}");
$this->send($v, implode("\n", $diff));
}
}
}
@@ -1051,7 +1063,10 @@ class Bot
foreach ($items as $k => $v) {
if (($t = gmdate($k, $seconds) - $v['diff']) > 0) {
$text .= " $t{$v['sign']}";
break;
if (!empty($i)) {
break;
}
$i++;
}
}
return trim($text) ?: '♾';
@@ -2113,7 +2128,7 @@ DNS-over-HTTPS with IP:
$this->setSSL('self');
}
public function include(int $count)
public function include($type)
{
$r = $this->send(
$this->input['chat'],
@@ -2124,25 +2139,86 @@ DNS-over-HTTPS with IP:
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'callback' => 'addInclude',
'args' => [$count],
'args' => [$type],
];
}
public function addInclude(string $domains, int $count)
public function addInclude(string $domains, $type)
{
$domains = explode(',', $domains);
$domains = array_filter($domains, fn($x) => !empty(trim($x)));
if (!empty($domains)) {
$conf = $this->getPacConf();
foreach ($domains as $k => $v) {
$conf['includelist'][idn_to_ascii(trim($v))] = true;
$conf[$type][idn_to_ascii(trim($v))] = true;
}
ksort($conf['includelist']);
ksort($conf[$type]);
$this->setPacConf($conf);
$page = (int) floor(array_search($v, array_keys($conf['includelist'])) / $count);
$page = (int) floor(array_search($v, array_keys($conf[$type])) / $this->limit);
}
$page = $page ?: -2;
$this->pacUpdate();
$this->backXtlsList($type);
}
public function backXtlsList($type)
{
switch ($type) {
case 'includelist':
$this->pacUpdate();
break;
case 'blocklist':
$this->xrayUpdateRules();
$this->xtlsblock();
break;
case 'warplist':
$this->xrayUpdateRules();
$this->xtlswarp();
break;
}
}
public function xrayUpdateRules()
{
$c = $this->getPacConf();
$xr = $this->getXray();
$xr['outbounds'] = [
[
"protocol" => "freedom",
"tag" => "direct",
],
[
"protocol" => "blackhole",
"tag" => "block",
],
[
"protocol" => "socks",
"tag" => "warp",
"settings" => [
'servers' => [
[
"address" => "10.10.0.13",
"port" => 4000,
],
],
],
],
];
if (!empty($c['blocklist']) && !empty(array_filter($c['blocklist']))) {
$rules[] = [
"type" => "field",
"outboundTag" => "block",
"domain" => array_keys(array_filter($c['blocklist'])),
];
}
if (!empty($c['warplist']) && !empty(array_filter($c['warplist']))) {
$rules[] = [
"type" => "field",
"outboundTag" => "warp",
"domain" => array_keys(array_filter($c['warplist'])),
];
}
$xr['routing']['rules'] = $rules ?: [];
$this->restartXray($xr);
}
public function reverse(int $count)
@@ -2962,44 +3038,7 @@ DNS-over-HTTPS with IP:
'callback_data' => "/addCommunityFilter",
],
];
$data[] = [
[
'text' => $this->i18n('add'),
'callback_data' => "/include {$this->limit}",
],
];
$domains = $this->getPacConf()['includelist'];
if (!empty($domains)) {
ksort($domains);
$all = (int) ceil(count($domains) / $this->limit);
$page = min($page, $all - 1);
$page = $page < 0 ? $all - 1 : $page;
$domains = array_slice($domains, $page * $this->limit, $this->limit, true);
foreach ($domains as $k => $v) {
$data[] = [
[
'text' => '(' . ($v ? 'ON' : 'OFF') . ') ' . idn_to_utf8($k),
'callback_data' => "/changeincludelist {$k}_{$this->limit}",
],
[
'text' => 'delete',
'callback_data' => "/deleteincludelist {$k}_{$this->limit}",
],
];
}
if ($all > 1) {
$data[] = [
[
'text' => '<<',
'callback_data' => "/pacMenu " . ($page - 1 >= 0 ? $page - 1 : $all - 1),
],
[
'text' => '>>',
'callback_data' => "/pacMenu " . ($page < $all - 1 ? $page + 1 : 0),
]
];
}
}
$data = array_merge($data, $this->listPac('includelist', $page, 'pacMenu'));
$data[] = [
[
'text' => $this->i18n('back'),
@@ -3014,22 +3053,101 @@ DNS-over-HTTPS with IP:
);
}
public function listPacChange($type, $action, $key, int $count)
public function xtlsblock($page = 0)
{
$text[] = "Menu -> " . $this->i18n('xray') . ' -> block list';
$data = $this->listPac('blocklist', $page, 'xtlsblock');
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/xray",
],
];
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
$data ?: false,
);
}
public function xtlswarp($page = 0)
{
$text[] = "Menu -> " . $this->i18n('xray') . ' -> warp list';
$data = $this->listPac('warplist', $page, 'xtlswarp');
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/xray",
],
];
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
$data ?: false,
);
}
public function listPac($type, $page, $menu)
{
$data[] = [
[
'text' => $this->i18n('add'),
'callback_data' => "/include $type",
],
];
$domains = $this->getPacConf()[$type];
if (!empty($domains)) {
ksort($domains);
$all = (int) ceil(count($domains) / $this->limit);
$page = min($page, $all - 1);
$page = $page < 0 ? $all - 1 : $page;
$domains = array_slice($domains, $page * $this->limit, $this->limit, true);
foreach ($domains as $k => $v) {
$data[] = [
[
'text' => $this->i18n($v ? 'on' : 'off') . ' ' . idn_to_utf8($k),
'callback_data' => "/change$type {$k}_{$this->limit}",
],
[
'text' => 'delete',
'callback_data' => "/delete$type {$k}_{$this->limit}",
],
];
}
if ($all > 1) {
$data[] = [
[
'text' => '<<',
'callback_data' => "/$menu " . ($page - 1 >= 0 ? $page - 1 : $all - 1),
],
[
'text' => '>>',
'callback_data' => "/$menu " . ($page < $all - 1 ? $page + 1 : 0),
]
];
}
}
return $data;
}
public function listPacChange($type, $action, $key)
{
$conf = $this->getPacConf();
ksort($conf[$type]);
$page = (int) floor(array_search($key, array_keys($conf[$type])) / $count);
switch ($action) {
case 'change':
$conf[$type][$key] = !$conf[$type][$key];
$page = (int) floor(array_search($key, array_keys($conf[$type])) / $count);
break;
case 'delete':
unset($conf[$type][$key]);
break;
}
$this->setPacConf($conf);
$this->pacUpdate();
$this->backXtlsList($type);
}
public function pacZapret()
@@ -3163,8 +3281,8 @@ DNS-over-HTTPS with IP:
'callback_data' => "/menu ss",
],
[
'text' => $this->i18n('mirror'),
'callback_data' => "/menu mirror",
'text' => $this->i18n('warp') . ': ' . $this->warpStatus(),
'callback_data' => "/warp",
],
],
[
@@ -3500,7 +3618,7 @@ DNS-over-HTTPS with IP:
$this->xray();
}
public function singAdd()
public function templateAdd($type)
{
$r = $this->send(
$this->input['chat'],
@@ -3511,12 +3629,12 @@ DNS-over-HTTPS with IP:
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'start_callback' => $this->input['callback_id'],
'callback' => 'singAddTemplate',
'args' => [],
'callback' => 'addTemplate',
'args' => [$type],
];
}
public function singAddTemplate($n = null)
public function addTemplate($n, $type)
{
if (empty($this->input['caption'])) {
$this->send($this->input['chat'], 'empty name');
@@ -3529,79 +3647,79 @@ DNS-over-HTTPS with IP:
return;
}
$pac = $this->getPacConf();
$pac['singtemplates'][$this->input['caption']] = $json;
$pac["{$type}templates"][$this->input['caption']] = $json;
$this->setPacConf($pac);
$this->singbox();
$this->templates($type);
}
public function delTemplate($name)
public function delTemplate($type, $name)
{
$pac = $this->getPacConf();
unset($pac['singtemplates'][base64_decode($name)]);
unset($pac["{$type}templates"][base64_decode($name)]);
$this->setPacConf($pac);
$this->singbox();
$this->templates($type);
}
public function downloadTemplate($name)
public function downloadTemplate($type, $name)
{
$pac = $this->getPacConf();
$f = new \CURLStringFile(json_encode($pac['singtemplates'][base64_decode($name)], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), base64_decode($name) . '.json', 'application/json');
$f = new \CURLStringFile(json_encode($pac["{$type}templates"][base64_decode($name)], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), base64_decode($name) . '.json', 'application/json');
$this->sendFile($this->input['chat'], $f);
}
public function defaultTemplate($name)
public function defaultTemplate($type, $name)
{
$pac = $this->getPacConf();
if (!empty($name)) {
$pac['defaulttemplate'] = $name;
$pac["default{$type}template"] = $name;
} else {
unset($pac['defaulttemplate']);
unset($pac["default{$type}template"]);
}
$this->setPacConf($pac);
$this->singbox();
$this->templates($type);
}
public function singbox($name = false)
public function templates($type)
{
$pac = $this->getPacConf();
$domain = $pac['domain'] ?: $this->ip;
$hash = substr(md5($this->key), 0, 8);
$text[] = "Menu -> " . $this->i18n('xray') . ' -> Sing-box templates';
$templates = $pac['singtemplates'];
$text[] = "Menu -> " . $this->i18n('xray') . " -> $type templates";
$templates = $pac["{$type}templates"];
$data[] = [
[
'text' => $this->i18n('add'),
'callback_data' => "/singAdd",
'callback_data' => "/templateAdd $type",
],
];
$data[] = [
[
'text' => "origin",
'web_app' => ['url' => "https://$domain/pac?h=$hash&t=te"],
'web_app' => ['url' => "https://$domain/pac?h=$hash&t=te&ty=$type"],
],
[
'text' => $this->i18n($pac['defaulttemplate'] ? 'off' : 'on'),
'callback_data' => "/defaultTemplate",
'text' => $this->i18n($pac["default{$type}template"] && !empty($pac["{$type}templates"][$pac["default{$type}template"]]) ? 'off' : 'on'),
'callback_data' => "/defaultTemplate $type",
],
];
foreach ($templates as $k => $v) {
$data[] = [
[
'text' => "$k",
'web_app' => ['url' => "https://$domain/pac?h=$hash&t=te&te=" . urlencode($k)],
'web_app' => ['url' => "https://$domain/pac?h=$hash&t=te&ty=$type&te=" . urlencode($k)],
],
[
'text' => $this->i18n('download'),
'callback_data' => "/downloadTemplate " . base64_encode($k),
'callback_data' => "/downloadTemplate $type " . base64_encode($k),
],
[
'text' => $this->i18n('delete'),
'callback_data' => "/delTemplate " . base64_encode($k),
'callback_data' => "/delTemplate $type " . base64_encode($k),
],
[
'text' => $this->i18n($pac['defaulttemplate'] == base64_encode($k) ? 'on' : 'off'),
'callback_data' => "/defaultTemplate " . base64_encode($k),
'text' => $this->i18n($pac["default{$type}template"] == base64_encode($k) ? 'on' : 'off'),
'callback_data' => "/defaultTemplate $type " . base64_encode($k),
],
];
}
@@ -3639,9 +3757,23 @@ DNS-over-HTTPS with IP:
],
];
$data[] = [
[
'text' => $this->i18n('v2ray templates'),
'callback_data' => "/templates v2ray",
],
[
'text' => $this->i18n('sing-box templates'),
'callback_data' => "/singbox",
'callback_data' => "/templates sing",
],
];
$data[] = [
[
'text' => $this->i18n('block'),
'callback_data' => "/xtlsblock",
],
[
'text' => $this->i18n('warp'),
'callback_data' => "/xtlswarp",
],
];
$data[] = [
@@ -3711,42 +3843,100 @@ DNS-over-HTTPS with IP:
);
}
public function warpPlus()
{
$r = $this->send(
$this->input['chat'],
"@{$this->input['username']} enter key",
$this->input['message_id'],
reply: 'enter key',
);
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'start_callback' => $this->input['callback_id'],
'callback' => 'addWarpPlus',
'args' => [],
];
}
public function addWarpPlus($key)
{
$c = $this->getPacConf();
$c['warp'] = $key;
$this->setPacConf($c);
$this->send($this->input['chat'], 'Warp registration license: ' . $this->ssh("warp-cli --accept-tos registration license $key", 'wp'));
sleep(1);
$this->warp();
}
public function warpStatus()
{
$st = $this->ssh('curl -m 1 -x socks5://127.0.0.1:40000 https://cloudflare.com/cdn-cgi/trace', 'wp');
preg_match('~warp=(\w+)~', $st, $m);
return $m[1];
}
public function warp()
{
$text[] = "Menu -> " . $this->i18n('warp');
$text[] = "status: " . $this->warpStatus();
$data[] = [
[
'text' => $this->i18n('set key'),
'callback_data' => "/warpPlus",
],
];
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/menu",
],
];
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
$data ?: false,
);
}
public function choiceTemplate($arg)
{
$arg = explode('_', $arg);
$c = $this->getXray();
if (!empty($arg[1])) {
$c['inbounds'][0]['settings']['clients'][$arg[0]]['template'] = $arg[1];
$c = $this->getXray();
if (!empty($arg[2])) {
$c['inbounds'][0]['settings']['clients'][$arg[1]]["{$arg[0]}template"] = $arg[2];
} else {
unset($c['inbounds'][0]['settings']['clients'][$arg[0]]['template']);
unset($c['inbounds'][0]['settings']['clients'][$arg[1]]["{$arg[0]}template"]);
}
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->userXr($arg[0]);
$this->userXr($arg[1]);
}
public function templateUser($i)
public function templateUser($type, $i)
{
$c = $this->getXray();
$pac = $this->getPacConf();
$text[] = "Menu -> " . $this->i18n('xray') . " -> {$c['inbounds'][0]['settings']['clients'][$i]['email']}\n";
$templates = $pac['singtemplates'];
$data[] = [
$text[] = "Menu -> " . $this->i18n('xray') . " -> {$c['inbounds'][0]['settings']['clients'][$i]['email']}\n";
$templates = $pac["{$type}templates"];
$data[] = [
[
'text' => 'default',
'callback_data' => "/choiceTemplate $i",
'callback_data' => "/choiceTemplate {$type}_$i",
],
];
$data[] = [
[
'text' => 'origin',
'callback_data' => "/choiceTemplate {$i}_" . base64_encode('origin'),
'callback_data' => "/choiceTemplate {$type}_{$i}_" . base64_encode('origin'),
],
];
foreach ($templates as $k => $v) {
$data[] = [
[
'text' => $k,
'callback_data' => "/choiceTemplate {$i}_" . base64_encode($k),
'callback_data' => "/choiceTemplate {$type}_{$i}_" . base64_encode($k),
],
];
}
@@ -3764,44 +3954,57 @@ DNS-over-HTTPS with IP:
);
}
public function userXr($i, $fs = 0, $fv = 0)
public function userXr($i)
{
$c = $this->getXray();
$pac = $this->getPacConf() ?: $this->ip;
$domain = $pac['domain'] ?: $this->ip;
$scheme = empty($this->nginxGetTypeCert()) ? 'http' : 'https';
$hash = substr(md5($this->key), 0, 8);
$v2ray = "$scheme://{$domain}/pac?h=$hash&t=s&b=1&s={$c['inbounds'][0]['settings']['clients'][$i]['id']}";
$sing = "$scheme://{$domain}/pac?h=$hash&t=si&b=1&s={$c['inbounds'][0]['settings']['clients'][$i]['id']}";
$fullsing = 'sing-box://import-remote-profile/?url=' . urlencode("$scheme://{$domain}/pac?h=$hash&t=si&s={$c['inbounds'][0]['settings']['clients'][$i]['id']}") . "#{$c['inbounds'][0]['settings']['clients'][$i]['email']}";
$fullv2ray = 'v2rayng://install-config?url=' . urlencode("$scheme://{$domain}/pac?h=$hash&t=s&s={$c['inbounds'][0]['settings']['clients'][$i]['id']}") . "#{$c['inbounds'][0]['settings']['clients'][$i]['email']}";
if (!empty($fs)) {
return $fullsing;
}
if (!empty($fv)) {
return $fullv2ray;
}
$c = $this->getXray()['inbounds'][0]['settings']['clients'][$i];
$pac = $this->getPacConf();
$domain = $pac['domain'] ?: $this->ip;
$scheme = empty($this->nginxGetTypeCert()) ? 'http' : 'https';
$hash = substr(md5($this->key), 0, 8);
$text[] = "Menu -> " . $this->i18n('xray') . " -> {$c['inbounds'][0]['settings']['clients'][$i]['email']}\n";
$text[] = "Menu -> " . $this->i18n('xray') . " -> {$c['email']}\n";
$text[] = "<code>{$this->linkXray($i)}</code>\n";
$text[] = "v2ray: <a href='$v2ray'>$v2ray</a>\n";
$text[] = "sing-box: <a href='$sing'>$sing</a>";
$text[] = "import subscribe:";
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=v&s={$c['id']}#{$c['email']}'>v2rayng</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=si&r=h&s={$c['id']}#{$c['email']}'>hiddify</a>";
$text[] = "\nv2ray config: <code>$scheme://{$domain}/pac?h=$hash&t=s&s={$c['id']}</code>";
$text[] = "sing-box config: <code>$scheme://{$domain}/pac?h=$hash&t=si&s={$c['id']}</code>";
$text[] = "sing-box windows: <a href='$scheme://{$domain}/pac?h=$hash&t=si&r=w&s={$c['id']}'>windows service</a>";
$data[] = [
[
'text' => $c['inbounds'][0]['settings']['clients'][$i]['time'] ? "timer: " . $this->getTime($c['inbounds'][0]['settings']['clients'][$i]['time']) : $this->i18n('timer'),
'text' => 'v2ray',
'web_app' => ['url' => "https://{$domain}/pac?h=$hash&t=s&s={$c['id']}"],
],
[
'text' => 'sing-box',
'web_app' => ['url' => "https://{$domain}/pac?h=$hash&t=si&s={$c['id']}"],
],
];
$data[] = [
[
'text' => $c['time'] ? "timer: " . $this->getTime($c['time']) : $this->i18n('timer'),
'callback_data' => "/timerXr $i",
],
[
'text' => $this->i18n($c['inbounds'][0]['settings']['clients'][$i]['off'] ? 'off' : 'on'),
'text' => $this->i18n($c['off'] ? 'off' : 'on'),
'callback_data' => "/switchXr $i",
],
];
$template = $c['inbounds'][0]['settings']['clients'][$i]['template'] ? base64_decode($c['inbounds'][0]['settings']['clients'][$i]['template']) : 'default(' . ($pac['defaulttemplate'] ? base64_decode($pac['defaulttemplate']) : 'origin') . ')';
$data[] = [
$singtemplate = $c['singtemplate'] ? base64_decode($c['singtemplate']) : 'default(' . ($pac['defaultsingtemplate'] && !empty($pac['singtemplates'][base64_decode($pac['defaultsingtemplate'])]) ? base64_decode($pac['defaultsingtemplate']) : 'origin') . ')';
$v2raytemplate = $c['v2raytemplate'] ? base64_decode($c['v2raytemplate']) : 'default(' . ($pac['defaultv2raytemplate'] && !empty($pac['v2raytemplates'][base64_decode($pac['defaultv2raytemplate'])]) ? base64_decode($pac['defaultv2raytemplate']) : 'origin') . ')';
$data[] = [
[
'text' => $this->i18n('template singbox') . ": $template",
'callback_data' => "/templateUser $i",
'text' => $this->i18n('v2ray') . ": $v2raytemplate",
'callback_data' => "/templateUser v2ray $i",
],
[
'text' => $this->i18n('singbox') . ": $singtemplate",
'callback_data' => "/templateUser sing $i",
],
];
$data[] = [
@@ -3815,8 +4018,6 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n('rename'),
'callback_data' => "/renameXrUser $i",
],
];
$data[] = [
[
'text' => $this->i18n('delete'),
'callback_data' => "/delxr $i",
@@ -3875,22 +4076,22 @@ DNS-over-HTTPS with IP:
echo json_encode($c);
}
public function singboxSubscription($key, $fs = 0)
public function subscription()
{
$pac = $this->getPacConf();
$domain = $pac['domain'] ?: $this->ip;
$xr = $this->getXray();
$scheme = empty($this->nginxGetTypeCert()) ? 'http' : 'https';
$hash = substr(md5($this->key), 0, 8);
$flag = true;
foreach ($xr['inbounds'][0]['settings']['clients'] as $k => $v) {
if ($v['id'] == $key) {
if (!empty($fs)) {
return $this->userXr($k, 1);
}
if ($v['id'] == $_GET['s']) {
if (empty($v['off'])) {
$flag = false;
}
$template = base64_decode($v['template']);
$template = base64_decode($_GET['t'] == 's' ? $v['v2raytemplate'] : $v['singtemplate']);
$uid = $v['id'];
break;
}
}
@@ -3898,40 +4099,162 @@ DNS-over-HTTPS with IP:
return false;
}
if (!empty($_GET['r'])) {
$si = "$scheme://{$domain}/pac?h=$hash&t=si&s=$uid";
$v2 = "$scheme://{$domain}/pac?h=$hash&t=s&s=$uid";
switch ($_GET['r']) {
case 'si':
header("Location: sing-box://import-remote-profile/?url=" . urlencode($si));
exit;
case 'st':
header("Location: streisand://import/$v2");
exit;
case 'v':
header("Location: v2rayng://install-config?url=" . urlencode($v2));
exit;
case 'h':
header("Location: hiddify://install-config/?url=" . urlencode($si));
exit;
case 'w':
$link = htmlspecialchars($si, ENT_XML1, 'UTF-8');
file_put_contents('/singbox/winsw3.xml', preg_replace('#~url~#', $link, file_get_contents('/singbox/winsw3.xml')));
$zip = new ZipArchive();
$n = "singbox_$uid.zip";
$zip->open($n, ZipArchive::CREATE | ZipArchive::OVERWRITE);
foreach (scandir('/singbox') as $k => $v) {
if (!empty(!in_array($v, ['.', '..']))) {
$zip->addFile("/singbox/$v", $v);
}
}
$zip->close();
header('Content-Disposition: attachment; filename="singbox.zip"');
echo file_get_contents($n);
unlink($n);
exit;
}
}
switch (true) {
case !empty($template) && $template == 'origin':
case empty($template) && empty($pac['defaulttemplate']):
$c = json_decode(file_get_contents('/config/sing.json'), true);
case empty($template) && empty($pac['default' . ($_GET['t'] == 's' ? 'v2ray' : 'sing') . 'template']):
case empty($template) && !empty($pac['default' . ($_GET['t'] == 's' ? 'v2ray' : 'sing') . 'template']) && empty($pac[($_GET['t'] == 's' ? 'v2ray' : 'sing') . 'templates'][$pac['default' . ($_GET['t'] == 's' ? 'v2ray' : 'sing') . 'template']]):
$c = json_decode(file_get_contents('/config/' . ($_GET['t'] == 's' ? 'v2ray' : 'sing') . '.json'), true);
break;
case !empty($template):
$c = $pac['singtemplates'][$template];
$c = $pac[$_GET['t'] == 's' ? 'v2raytemplates' : 'singtemplates'][$template];
break;
default:
$c = $pac['singtemplates'][base64_decode($pac['defaulttemplate'])];
$c = $pac[$_GET['t'] == 's' ? 'v2raytemplates' : 'singtemplates'][base64_decode($pac['default' . ($_GET['t'] == 's' ? 'v2ray' : 'sing') . 'template'])];
break;
}
if ($c['dns']['servers'][0]['address'] == '~dns~') {
$c['dns']['servers'][0]['address'] = "tls://" . ($pac['adguardkey'] ? "{$pac['adguardkey']}." : '') . "$domain";
switch ($_GET['t']) {
case 's':
$c['outbounds'][0]['settings']['vnext'][0]['address'] = $domain;
$c['outbounds'][0]['settings']['vnext'][0]['users'][0]['id'] = $uid;
$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];
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;
case 'si':
if ($c['dns']['servers'][0]['address'] == '~dns~') {
$c['dns']['servers'][0]['address'] = "tls://" . ($pac['adguardkey'] ? "{$pac['adguardkey']}." : '') . "$domain";
}
$c['outbounds'][0]['server'] = $domain;
$c['outbounds'][0]['uuid'] = $uid;
$c['outbounds'][0]['tls']['reality']['public_key'] = $pac['xray'];
$c['outbounds'][0]['tls']['server_name'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0];
$c['outbounds'][0]['tls']['reality']['short_id'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0];
foreach ($c['route']['rules'] as $k => $v) {
if (array_key_exists('domain_suffix', $v) && $v['domain_suffix'] == '~pac~') {
$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->createRuleSet($c['route'], $uid);
break;
}
$c['outbounds'][0]['server'] = $domain;
$c['outbounds'][0]['uuid'] = $key;
$c['outbounds'][0]['tls']['reality']['public_key'] = $pac['xray'];
$c['outbounds'][0]['tls']['server_name'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0];
$c['outbounds'][0]['tls']['reality']['short_id'] = $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0];
foreach ($c['route']['rules'] as $k => $v) {
if (array_key_exists('domain_suffix', $v) && $v['domain_suffix'] == '~pac~') {
$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]);
header('Content-type: application/json');
echo json_encode($c);
}
public function createRuleSet($route, $uid)
{
$pac = $this->getPacConf();
$domain = $pac['domain'] ?: $this->ip;
$scheme = empty($this->nginxGetTypeCert()) ? 'http' : 'https';
$hash = substr(md5($this->key), 0, 8);
foreach ($route['rules'] as $k => $v) {
if (!empty($v['createruleset'])) {
foreach ($v['createruleset'] as $i => $r) {
foreach ($r['rules'] as $l => $n) {
if (array_key_exists('domain_suffix', $n) && $n['domain_suffix'] == '~pac~') {
$r['rules'][$l]['domain_suffix'] = array_keys(array_filter($pac['includelist'] ?: []));
if (empty($r['rules'][$l]['domain_suffix'])) {
unset($r['rules'][$l]);
}
}
}
if (!empty($_GET['r']) && $r['name'] == $_GET['r']) {
$f = "/tmp/{$r['name']}" . time() . rand(1, 100);
file_put_contents($f, json_encode([
'version' => 1,
'rules' => $r['rules'],
]));
exec("sing-box rule-set compile $f");
header("Content-Disposition: attachment; filename={$r['name']}.srs");
header('Content-Type: application/binary');
echo file_get_contents("$f.srs");
unlink($f);
unlink("$f.srs");
exit;
}
if (!empty($r['rules'])) {
$ruleset[] = [
"tag" => $r['name'],
"url" => "$scheme://{$domain}/pac?" . http_build_query([
'h' => $hash,
't' => 'si',
's' => $uid,
'r' => $r['name'],
]),
"update_interval" => $r['interval'],
"type" => "remote",
"format" => "binary",
"download_detour" => "direct",
];
$route['rules'][$k]['rule_set'][] = $r['name'];
}
}
unset($route['rules'][$k]['createruleset']);
if (empty($route['rules'][$k]['rule_set'])) {
unset($route['rules'][$k]);
}
}
}
$c['route']['rules'] = array_values($c['route']['rules']);
return json_encode($c);
$route['rules'] = array_values($route['rules']);
$route['rule_set'] = array_merge($route['rule_set'] ?: [], $ruleset ?: []);
if (empty($route['rule_set'])) {
unset($route['rule_set']);
}
return $route;
}
public function getXray()
@@ -4223,6 +4546,12 @@ DNS-over-HTTPS with IP:
$this->exportManual($this->update);
$r = $this->send($this->input['from'], 'update...');
file_put_contents('/update/reload_message', "{$this->input['from']}:{$r['result']['message_id']}");
file_put_contents('/update/key', $this->key);
file_put_contents('/update/curl', json_encode([
'chat_id' => $this->input['chat'],
'message_id' => $r['result']['message_id'],
'text' => '~t~'
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
file_put_contents('/update/pipe', '1');
$this->delete($this->input['from'], $this->input['message_id']);
}
@@ -4860,8 +5189,9 @@ DNS-over-HTTPS with IP:
fclose($s);
ssh2_disconnect($c);
} catch (Exception | Error $e) {
$this->send($this->input['chat'], $e->getMessage(), $this->input['message_id']);
die();
if (!empty($GLOBALS['debug'])) {
$this->send($this->input['chat'], $e->getMessage(), $this->input['message_id']);
}
}
return $data;
}
+4
View File
@@ -1,6 +1,10 @@
<?php
$i = [
'warp' => [
'en' => 'Warp',
'ru' => 'Warp',
],
'wg_title' => [
'en' => 'Wireguard',
'ru' => 'Wireguard',
+6 -33
View File
@@ -22,50 +22,23 @@ $address = $_GET['a'] ?: '127.0.0.1';
$port = $_GET['p'] ?: '1080';
$hash = $_GET['h'];
if ($hash == substr(md5($c['key']), 0, 8)) {
require __DIR__ . '/bot.php';
require __DIR__ . '/i18n.php';
$bot = new Bot($c['key'], $i);
switch ($type) {
case 'mirror':
require __DIR__ . '/bot.php';
require __DIR__ . '/i18n.php';
$bot = new Bot($c['key'], $i);
$bot->getMirror();
break;
case 's':
require __DIR__ . '/bot.php';
require __DIR__ . '/i18n.php';
$bot = new Bot($c['key'], $i);
if (!empty($_GET['b'])) {
$fs = $bot->v2raySubscription($_GET['s'], 1);
header("Location: $fs");
exit;
} else {
header('Content-Type: application/json');
echo $bot->v2raySubscription($_GET['s']);
}
exit;
case 'si':
require __DIR__ . '/bot.php';
require __DIR__ . '/i18n.php';
$bot = new Bot($c['key'], $i);
if (!empty($_GET['b'])) {
$fs = $bot->singboxSubscription($_GET['s'], 1);
header("Location: $fs");
exit;
} else {
header('Content-Type: application/json');
echo $bot->singboxSubscription($_GET['s']);
}
$bot->subscription();
exit;
case 'te':
require __DIR__ . '/bot.php';
require __DIR__ . '/i18n.php';
$bot = new Bot($c['key'], $i);
if (!empty($_GET['te'])) {
$t = $bot->getPacConf()['singtemplates'][urldecode($_GET['te'])];
$t = $bot->getPacConf()["{$_GET['ty']}templates"][$_GET['te']];
} else {
$t = json_decode(file_get_contents('/config/sing.json'), true);
$t = json_decode(file_get_contents("/config/{$_GET['ty']}.json"), true);
}
if ($t) {
header('Content-Type: application/json');
+3 -1
View File
@@ -2,10 +2,12 @@
require __DIR__ . '/timezone.php';
// require __DIR__ . '/debug.php';
require __DIR__ . '/bot.php';
require __DIR__ . '/config.php';
require __DIR__ . '/i18n.php';
if ($c['debug']) {
require __DIR__ . '/debug.php';
}
$bot = new Bot($c['key'], $i);
$bot->adguardProtect();
+4 -1
View File
@@ -2,11 +2,14 @@
require __DIR__ . '/timezone.php';
// require __DIR__ . '/debug.php';
require __DIR__ . '/bot.php';
require __DIR__ . '/config.php';
require __DIR__ . '/i18n.php';
if ($c['debug']) {
require __DIR__ . '/debug.php';
}
$bot = new Bot($c['key'], $i);
if (!empty($c['admin'])) {
+1
View File
@@ -16,6 +16,7 @@
<div style="position:absolute;top:0;right:0;width:35%;text-align:center;background-color: #17212b;">
<img src="toncoin.png" width="100%" alt="">
<a href="javascript:;" id="copy" style="color:white;text-decoration:none" data-id="UQCDDkaX3fCAFBek28Hx4TfvDDRqeizOW74blVMVAM4_m4OW">copy</a>
<iframe src="https://ghbtns.com/github-btn.html?user=mercurykd&repo=vpnbot&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
</div>
<a style="background-color: #8B3FFD;height: 46px;display:inline-block;padding:0 54px;color: white;border-radius: 12px;text-decoration: none;font-size: 20px;line-height: 46px;font-family: arial;" href="https://yoomoney.ru/to/410011827900450">
<svg style="width: 24px;fill: white;position: relative;top: 4px;" class="qa-fundraise-button-logo mui-m0okdh" viewBox="0 0 16 16"><path d="M4.638 8.5a5.67 5.67 0 015.681-5.68A5.693 5.693 0 0116 8.5a5.693 5.693 0 01-5.68 5.682A5.67 5.67 0 014.637 8.5zm3.56 0c0 1.151.97 2.122 2.121 2.122 1.15 0 2.085-.97 2.121-2.121 0-1.15-.97-2.121-2.12-2.121-1.151 0-2.122.97-2.122 2.12zm-3.596 4.243v-8.27H0l2.589 8.27h2.013z" clip-rule="evenodd"></path></svg>
+111 -87
View File
@@ -3,104 +3,128 @@
"level": "error",
"timestamp": true
},
"inbounds": [{
"type": "tun",
"tag": "tun-in",
"domain_strategy": "prefer_ipv4",
"interface_name": "sing-tun",
"inet4_address": "172.19.0.1\/30",
"mtu": 1400,
"gso": true,
"auto_route": true,
"strict_route": true,
"sniff": true,
"endpoint_independent_nat": false,
"stack": "mixed",
"platform": {
"http_proxy": {
"enabled": false,
"server": "127.0.0.1",
"server_port": 2080
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"domain_strategy": "prefer_ipv4",
"interface_name": "sing-tun",
"inet4_address": "172.19.0.1\/30",
"mtu": 1400,
"gso": true,
"auto_route": true,
"strict_route": true,
"sniff": true,
"endpoint_independent_nat": false,
"stack": "mixed",
"platform": {
"http_proxy": {
"enabled": false,
"server": "127.0.0.1",
"server_port": 2080
}
}
},
{
"type": "mixed",
"tag": "mixed-in",
"domain_strategy": "prefer_ipv4",
"listen": "127.0.0.1",
"listen_port": 2080,
"tcp_fast_open": true,
"sniff": true,
"sniff_override_destination": false,
"users": []
}
}, {
"type": "mixed",
"tag": "mixed-in",
"domain_strategy": "prefer_ipv4",
"listen": "127.0.0.1",
"listen_port": 2080,
"tcp_fast_open": true,
"sniff": true,
"sniff_override_destination": false,
"users": []
}],
],
"dns": {
"servers": [{
"tag": "dns_direct",
"address": "~dns~",
"address_resolver": "dns-remote",
"strategy": "prefer_ipv4",
"detour": "direct"
}, {
"tag": "dns-remote",
"address": "tcp:\/\/8.8.8.8",
"address_strategy": "prefer_ipv4",
"strategy": "prefer_ipv4",
"detour": "direct"
}],
"rules": [{
"outbound": "any",
"server": "dns-direct",
"disable_cache": false
}],
"servers": [
{
"tag": "dns_direct",
"address": "~dns~",
"address_resolver": "dns-remote",
"strategy": "prefer_ipv4",
"detour": "direct"
},
{
"tag": "dns-remote",
"address": "tcp:\/\/8.8.8.8",
"address_strategy": "prefer_ipv4",
"strategy": "prefer_ipv4",
"detour": "direct"
}
],
"rules": [
{
"outbound": "any",
"server": "dns-direct",
"disable_cache": false
}
],
"strategy": "ipv4_only",
"independent_cache": true
},
"outbounds": [{
"flow": "xtls-rprx-vision",
"packet_encoding": "",
"server": "",
"server_port": 443,
"tls": {
"enabled": true,
"insecure": false,
"reality": {
"outbounds": [
{
"flow": "xtls-rprx-vision",
"packet_encoding": "",
"server": "",
"server_port": 443,
"tls": {
"enabled": true,
"public_key": "",
"short_id": ""
"insecure": false,
"reality": {
"enabled": true,
"public_key": "",
"short_id": ""
},
"server_name": "",
"utls": {
"enabled": true,
"fingerprint": "chrome"
}
},
"server_name": "",
"utls": {
"enabled": true,
"fingerprint": "chrome"
}
"uuid": "",
"type": "vless",
"domain_strategy": "ipv4_only",
"tag": "proxy"
},
"uuid": "",
"type": "vless",
"domain_strategy": "ipv4_only",
"tag": "proxy"
}, {
"type": "direct",
"tag": "direct"
}, {
"type": "block",
"tag": "block"
}, {
"type": "dns",
"tag": "dns-out"
}],
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
},
{
"type": "dns",
"tag": "dns-out"
}
],
"route": {
"auto_detect_interface": true,
"override_android_vpn": true,
"rules": [{
"protocol": "dns",
"outbound": "dns-out"
}, {
"domain_suffix": "~pac~",
"outbound": "proxy"
}, {
"ip_cidr": ["0.0.0.0\/0"],
"outbound": "direct"
}]
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"createruleset": [
{
"name": "selfpac",
"interval": "15s",
"rules": [
{
"domain_suffix": "~pac~"
}
]
}
],
"outbound": "proxy"
}
],
"final": "direct"
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ worker_processes auto;
load_module /usr/lib/nginx/modules/ngx_stream_module.so;
error_log /logs/nginx_error;
error_log /logs/upstream_error;
pid /var/run/nginx.pid;
events {
+1 -1
View File
@@ -85,7 +85,7 @@
"rules": [{
"type": "field",
"outboundTag": "proxy",
"domain": []
"domain": "~pac~"
}, {
"type": "field",
"port": "0-65535",
+32 -1
View File
@@ -93,7 +93,7 @@ services:
ipv4_address: 10.10.1.2
logging: *default-logging
php:
image: mercurykd/vpnbot-php:1.3
image: mercurykd/vpnbot-php:1.5
build:
dockerfile: dockerfile/php.dockerfile
args:
@@ -115,6 +115,7 @@ services:
- ./.env:/mirror/.env
- ./update:/update
- ./.git:/.git
- ./singbox_windows:/singbox
environment:
IP: ${IP}
VER: ${VER}
@@ -489,3 +490,33 @@ services:
default:
ipv4_address: 10.10.0.12
logging: *default-logging
wp:
image: mercurykd/vpnbot-wp:1.1
build:
dockerfile: dockerfile/warp.dockerfile
args:
image: ${IMAGE}
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./config/.profile:/root/.bashrc:ro
- ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config
- ./config:/config
- ./certs:/certs
- ./scripts/start_wp.sh:/start_wp.sh
hostname: warp
container_name: warp-${VER}
depends_on:
php:
condition: service_healthy
environment:
TZ: ${TZ}
stop_grace_period: 1s
command: ["/bin/sh", "/start_wp.sh"]
networks:
default:
ipv4_address: 10.10.0.13
logging: *default-logging
+7 -1
View File
@@ -4,6 +4,7 @@ RUN apk add --no-cache --update php81 \
php81-mbstring \
php81-session \
php81-phar \
php81-zip \
php81-curl \
php81-opcache \
php81-openssl \
@@ -25,5 +26,10 @@ RUN apk add --no-cache --update php81 \
&& tar -xf dnslookup-linux-amd64-v1.9.1.tar.gz \
&& mv linux-amd64/dnslookup /usr/bin \
&& rm dnslookup-linux-amd64-v1.9.1.tar.gz \
&& rm -rf /linux-amd64
&& rm -rf /linux-amd64 \
&& wget https://github.com/SagerNet/sing-box/releases/download/v1.8.11/sing-box-1.8.11-linux-amd64.tar.gz \
&& tar -xf sing-box-1.8.11-linux-amd64.tar.gz \
&& mv sing-box-1.8.11-linux-amd64/sing-box /usr/bin \
&& rm sing-box-1.8.11-linux-amd64.tar.gz \
&& rm -rf /sing-box-1.8.11-linux-amd64
ENV ENV="/root/.ashrc"
+6
View File
@@ -0,0 +1,6 @@
FROM ubuntu:22.04
RUN apt update && apt install -y curl gpg socat jq lsb-release openssh-server \
&& curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/cloudflare-client.list \
&& apt update && apt install -y cloudflare-warp \
&& mkdir /root/.ssh
+4
View File
@@ -6,6 +6,10 @@ telegram bot to manage servers (inside the bot)
- change secret
- qr/config
- change fake domain
- multiple users
- subscriptions with routing
- routing templates per user
- steal from yourself
<img src="https://github.com/mercurykd/vpnbot/assets/30900414/39bdf4e0-96a6-4257-b61e-30a14122e236" width="200">
### NaiveProxy
+15
View File
@@ -0,0 +1,15 @@
cat /ssh/key.pub > /root/.ssh/authorized_keys
echo 'HostKeyAlgorithms +ssh-rsa' >> /etc/ssh/sshd_config
echo 'PubkeyAcceptedKeyTypes +ssh-rsa' >> /etc/ssh/sshd_config
service ssh start
warp-svc > /dev/null &
sleep 3
warp-cli --accept-tos registration new
key=$(cat /config/pac.json | jq -r .warp)
if [ ! -z "$key" ]
then
warp-cli --accept-tos registration license $key
fi
warp-cli --accept-tos mode proxy
warp-cli --accept-tos connect
socat TCP-LISTEN:4000,fork TCP:127.0.0.1:40000
+2
View File
@@ -0,0 +1,2 @@
winsw3.exe install
pause
+2
View File
@@ -0,0 +1,2 @@
winsw3.exe stop
winsw3.exe start
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
winsw3.exe start
+2
View File
@@ -0,0 +1,2 @@
winsw3.exe status
pause
+1
View File
@@ -0,0 +1 @@
winsw3.exe stop
+2
View File
@@ -0,0 +1,2 @@
winsw3.exe uninstall
pause
Binary file not shown.
+17
View File
@@ -0,0 +1,17 @@
<service>
<id>singbox</id>
<name>singbox</name>
<description>singbox</description>
<executable>%BASE%\sing-box.exe</executable>
<arguments>run -c %BASE%\config.json</arguments>
<logmode>rotate</logmode>
<onfailure action="restart" delay="10 sec" />
<onfailure action="restart" delay="20 sec" />
<onfailure action="restart" delay="30 sec" />
<onfailure action="none" />
<onexit action="restart" />
<onexit action="restart" />
<onexit action="restart" />
<onexit action="none" />
<download from="~url~" to="%BASE%\config.json"/>
</service>
+9
View File
@@ -9,16 +9,25 @@ do
branch=$(cat $pwd/update/branch 2>/dev/null)
if [[ -n "$cmd" ]]
then
key=$(cat $pwd/update/key)
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "останавливаю бота"/')"
docker compose down --remove-orphans
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "очищаю директорию"/')"
git reset --hard && git clean -fd
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "скачиваю обновление"/')"
git fetch
if [[ -n "$branch" ]]
then
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "меняю ветку"/')"
git checkout -t origin/$branch || git checkout $branch
fi
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "применяю обновления"/')"
git pull > ./update/message
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "запускаю бота"/')"
IP=$(curl https://ipinfo.io/ip) VER=$(git describe --tags) docker compose up -d --force-recreate
bash $pwd/update/update.sh &
> $pwd/update/key
> $pwd/update/curl
exit 0
fi
sleep 1
+23
View File
@@ -1,3 +1,26 @@
19.04.2024 v1.34
- формирование rule_set из шаблона singbox
18.04.2024 v1.33
- вывод статуса warp в меню
18.04.2024 v1.32
- фиксы в названии и отображении выбранного шаблона xtls
18.04.2024 v1.31
- возможность устанавливать ключ для warp
16.04.2024 v1.30.1
- улучшение сообщения об обновлениях
16.04.2024 v1.30
- улучшение скрипта обновления
16.04.2024 v1.29
- рефакторинг подписок
- кнопки импорта для различных клиентов
- шаблоны для v2ray
15.04.2024 v1.28
- xtls: список блокировки, список warp
- улучшение отображения таймера
14.04.2024 v1.27.1
- singbox windows: замена winsw на winsw3, + скрипт обновления подписки
13.04.2024 v1.27
- архив сингбокса для windows, работает как служба
12.04.2024 v1.26
- имя клиента xtls подтягивается по подписке из бота
11.04.2024 v1.25