Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'web/html/xui/xray.html')
-rw-r--r--web/html/xui/xray.html911
1 files changed, 911 insertions, 0 deletions
diff --git a/web/html/xui/xray.html b/web/html/xui/xray.html
new file mode 100644
index 00000000..db5aa202
--- /dev/null
+++ b/web/html/xui/xray.html
@@ -0,0 +1,911 @@
+<!DOCTYPE html>
+<html lang="en">
+{{template "head" .}}
+<style>
+ @media (min-width: 769px) {
+ .ant-layout-content {
+ margin: 24px 16px;
+ }
+ }
+
+ @media (max-width: 768px) {
+ .ant-tabs-nav .ant-tabs-tab {
+ margin: 0;
+ padding: 12px .5rem;
+ }
+ }
+
+ .ant-tabs-bar {
+ margin: 0;
+ }
+
+ .ant-list-item {
+ display: block;
+ }
+
+ .collapse-title {
+ color: inherit;
+ font-weight: bold;
+ font-size: 18px;
+ padding: 10px 20px;
+ border-bottom: 2px solid;
+ }
+
+ .collapse-title > i {
+ color: inherit;
+ font-size: 24px;
+ }
+</style>
+<body>
+<a-layout id="app" v-cloak :class="themeSwitcher.currentTheme">
+ {{ template "commonSider" . }}
+ <a-layout id="content-layout">
+ <a-layout-content>
+ <a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'>
+ <a-space direction="vertical">
+ <a-card hoverable style="margin-bottom: .5rem;">
+ <a-row>
+ <a-col :xs="24" :sm="8" style="padding: 4px;">
+ <a-space direction="horizontal">
+ <a-button type="primary" :disabled="saveBtnDisable" @click="updateXraySetting">{{ i18n "pages.settings.save" }}</a-button>
+ <a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.settings.restartPanel" }}</a-button>
+ </a-space>
+ </a-col>
+ <a-col :xs="24" :sm="16">
+ <a-alert type="warning" style="float: right; width: fit-content"
+ message='{{ i18n "pages.settings.infoDesc" }}'
+ show-icon
+ >
+ </a-col>
+ </a-row>
+ </a-card>
+ <a-tabs class="ant-card-dark-box-nohover" default-active-key="tpl-1" :class="themeSwitcher.currentTheme" style="padding: 20px 20px;">
+ <a-tab-pane key="tpl-1" tab='{{ i18n "pages.settings.templates.basicTemplate"}}' style="padding-top: 20px;">
+ <a-space direction="horizontal" style="padding: 20px 20px">
+ <a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
+ </a-space>
+ <a-collapse>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.generalConfigs"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.generalConfigsDesc" }}
+ </h2>
+ </a-row>
+ <a-list-item>
+ <a-row style="padding: 20px">
+ <a-col :lg="24" :xl="12">
+ <a-list-item-meta
+ title='{{ i18n "pages.settings.templates.xrayConfigFreedomStrategy" }}'
+ description='{{ i18n "pages.settings.templates.xrayConfigFreedomStrategyDesc" }}'/>
+ </a-col>
+ <a-col :lg="24" :xl="12">
+ <template>
+ <a-select
+ v-model="freedomStrategy"
+ :dropdown-class-name="themeSwitcher.currentTheme"
+ style="width: 100%">
+ <a-select-option v-for="s in outboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
+ </a-select>
+ </template>
+ </a-col>
+ </a-row>
+ </a-list-item>
+ <a-row style="padding: 20px">
+ <a-col :lg="24" :xl="12">
+ <a-list-item-meta
+ title='{{ i18n "pages.settings.templates.xrayConfigRoutingStrategy" }}'
+ description='{{ i18n "pages.settings.templates.xrayConfigRoutingStrategyDesc" }}'/>
+ </a-col>
+ <a-col :lg="24" :xl="12">
+ <template>
+ <a-select
+ v-model="routingStrategy"
+ :dropdown-class-name="themeSwitcher.currentTheme"
+ style="width: 100%">
+ <a-select-option v-for="s in routingDomainStrategies" :value="s">[[ s ]]</a-select-option>
+ </a-select>
+ </template>
+ </a-col>
+ </a-row>
+ </a-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.blockConfigs"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.blockConfigsDesc" }}
+ </h2>
+ </a-row>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigTorrent"}}' desc='{{ i18n "pages.settings.templates.xrayConfigTorrentDesc"}}' v-model="torrentSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigPrivateIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigPrivateIpDesc"}}' v-model="privateIpSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigAds"}}' desc='{{ i18n "pages.settings.templates.xrayConfigAdsDesc"}}' v-model="AdsSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigFamily"}}' desc='{{ i18n "pages.settings.templates.xrayConfigFamilyDesc"}}' v-model="familyProtectSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigSpeedtest"}}' desc='{{ i18n "pages.settings.templates.xrayConfigSpeedtestDesc"}}' v-model="SpeedTestSettings"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.blockCountryConfigs"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.blockCountryConfigsDesc" }}
+ </h2>
+ </a-row>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigIRIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigIRIpDesc"}}' v-model="IRIpSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigIRDomain"}}' desc='{{ i18n "pages.settings.templates.xrayConfigIRDomainDesc"}}' v-model="IRDomainSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigChinaIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigChinaIpDesc"}}' v-model="ChinaIpSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigChinaDomain"}}' desc='{{ i18n "pages.settings.templates.xrayConfigChinaDomainDesc"}}' v-model="ChinaDomainSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigRussiaIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigRussiaIpDesc"}}' v-model="RussiaIpSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigRussiaDomain"}}' desc='{{ i18n "pages.settings.templates.xrayConfigRussiaDomainDesc"}}' v-model="RussiaDomainSettings"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.directCountryConfigs"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.directCountryConfigsDesc" }}
+ </h2>
+ </a-row>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigDirectIRIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigDirectIRIpDesc"}}' v-model="IRIpDirectSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigDirectIRDomain"}}' desc='{{ i18n "pages.settings.templates.xrayConfigDirectIRDomainDesc"}}' v-model="IRDomainDirectSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigDirectChinaIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigDirectChinaIpDesc"}}' v-model="ChinaIpDirectSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigDirectChinaDomain"}}' desc='{{ i18n "pages.settings.templates.xrayConfigDirectChinaDomainDesc"}}' v-model="ChinaDomainDirectSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigDirectRussiaIp"}}' desc='{{ i18n "pages.settings.templates.xrayConfigDirectRussiaIpDesc"}}' v-model="RussiaIpDirectSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigDirectRussiaDomain"}}' desc='{{ i18n "pages.settings.templates.xrayConfigDirectRussiaDomainDesc"}}' v-model="RussiaDomainDirectSettings"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.ipv4Configs"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.ipv4ConfigsDesc" }}
+ </h2>
+ </a-row>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigGoogleIPv4"}}' desc='{{ i18n "pages.settings.templates.xrayConfigGoogleIPv4Desc"}}' v-model="GoogleIPv4Settings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigNetflixIPv4"}}' desc='{{ i18n "pages.settings.templates.xrayConfigNetflixIPv4Desc"}}' v-model="NetflixIPv4Settings"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.warpConfigs"}}'>
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.warpConfigsDesc" }}
+ </h2>
+ </a-row>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigGoogleWARP"}}' desc='{{ i18n "pages.settings.templates.xrayConfigGoogleWARPDesc"}}' v-model="GoogleWARPSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigOpenAIWARP"}}' desc='{{ i18n "pages.settings.templates.xrayConfigOpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigNetflixWARP"}}' desc='{{ i18n "pages.settings.templates.xrayConfigNetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
+ <setting-list-item type="switch" title='{{ i18n "pages.settings.templates.xrayConfigSpotifyWARP"}}' desc='{{ i18n "pages.settings.templates.xrayConfigSpotifyWARPDesc"}}' v-model="SpotifyWARPSettings"></setting-list-item>
+ </a-collapse-panel>
+ </a-collapse>
+ </a-tab-pane>
+ <a-tab-pane key="tpl-2" tab='{{ i18n "pages.settings.templates.manualLists"}}' style="padding-top: 20px;">
+ <a-row :xs="24" :sm="24" :lg="12">
+ <h2 class="collapse-title">
+ <a-icon type="warning"></a-icon>
+ {{ i18n "pages.settings.templates.manualListsDesc" }}
+ </h2>
+ </a-row>
+ <a-collapse>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualBlockedIPs"}}'>
+ <setting-list-item type="textarea" v-model="manualBlockedIPs"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualBlockedDomains"}}'>
+ <setting-list-item type="textarea" v-model="manualBlockedDomains"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualDirectIPs"}}'>
+ <setting-list-item type="textarea" v-model="manualDirectIPs"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualDirectDomains"}}'>
+ <setting-list-item type="textarea" v-model="manualDirectDomains"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualIPv4Domains"}}'>
+ <setting-list-item type="textarea" v-model="manualIPv4Domains"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.manualWARPDomains"}}'>
+ <setting-list-item type="textarea" v-model="manualWARPDomains"></setting-list-item>
+ </a-collapse-panel>
+ </a-collapse>
+ </a-tab-pane>
+ <a-tab-pane key="tpl-3" tab='{{ i18n "pages.settings.templates.advancedTemplate"}}' style="padding-top: 20px;">
+ <a-collapse>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.xrayConfigInbounds"}}'>
+ <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.xrayConfigInbounds"}}' desc='{{ i18n "pages.settings.templates.xrayConfigInboundsDesc"}}' v-model="inboundSettings"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.xrayConfigOutbounds"}}'>
+ <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.xrayConfigOutbounds"}}' desc='{{ i18n "pages.settings.templates.xrayConfigOutboundsDesc"}}' v-model="outboundSettings"></setting-list-item>
+ </a-collapse-panel>
+ <a-collapse-panel header='{{ i18n "pages.settings.templates.xrayConfigRoutings"}}'>
+ <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.xrayConfigRoutings"}}' desc='{{ i18n "pages.settings.templates.xrayConfigRoutingsDesc"}}' v-model="routingRuleSettings"></setting-list-item>
+ </a-collapse-panel>
+ </a-collapse>
+ </a-tab-pane>
+ <a-tab-pane key="tpl-4" tab='{{ i18n "pages.settings.templates.completeTemplate"}}' style="padding-top: 20px;">
+ <setting-list-item type="textarea" title='{{ i18n "pages.settings.templates.xrayConfigTemplate"}}' desc='{{ i18n "pages.settings.templates.xrayConfigTemplateDesc"}}' v-model="this.xraySetting"></setting-list-item>
+ </a-tab-pane>
+ </a-tabs>
+ </a-space>
+ </a-spin>
+ </a-layout-content>
+ </a-layout>
+</a-layout>
+{{template "js" .}}
+{{template "component/themeSwitcher" .}}
+{{template "component/setting"}}
+<script>
+ const app = new Vue({
+ delimiters: ['[[', ']]'],
+ el: '#app',
+ data: {
+ siderDrawer,
+ themeSwitcher,
+ spinning: false,
+ oldXraySetting: '',
+ xraySetting: '',
+ saveBtnDisable: true,
+ ipv4Settings: {
+ tag: "IPv4",
+ protocol: "freedom",
+ settings: {
+ domainStrategy: "UseIPv4"
+ }
+ },
+ warpSettings: {
+ tag: "WARP",
+ protocol: "socks",
+ settings: {
+ servers: [
+ {
+ address: "127.0.0.1",
+ port: 40000
+ }
+ ]
+ }
+ },
+ directSettings: {
+ tag: "direct",
+ protocol: "freedom"
+ },
+ outboundDomainStrategies: ["AsIs", "UseIP", "UseIPv4", "UseIPv6"],
+ routingDomainStrategies: ["AsIs", "IPIfNonMatch", "IPOnDemand"],
+ settingsData: {
+ protocols: {
+ bittorrent: ["bittorrent"],
+ },
+ ips: {
+ local: ["geoip:private"],
+ cn: ["geoip:cn"],
+ ir: ["ext:geoip_IR.dat:ir","ext:geoip_IR.dat:arvancloud","ext:geoip_IR.dat:derakcloud","ext:geoip_IR.dat:iranserver"],
+ ru: ["geoip:ru"],
+ },
+ domains: {
+ ads: [
+ "geosite:category-ads-all",
+ "ext:geosite_IR.dat:category-ads-all"
+ ],
+ speedtest: ["geosite:speedtest"],
+ openai: ["geosite:openai"],
+ google: ["geosite:google"],
+ spotify: ["geosite:spotify"],
+ netflix: ["geosite:netflix"],
+ cn: [
+ "geosite:cn",
+ "regexp:.*\\.cn$"
+ ],
+ ru: [
+ "geosite:category-gov-ru",
+ "regexp:.*\\.ru$"
+ ],
+ ir: [
+ "regexp:.*\\.ir$",
+ "regexp:.*\\.xn--mgba3a4f16a$", // .ایران
+ "ext:geosite_IR.dat:ir" // have rules to bypass all .ir domains.
+ ]
+ },
+ familyProtectDNS: {
+ "servers": [
+ "1.1.1.3", // https://developers.cloudflare.com/1.1.1.1/setup/
+ "1.0.0.3",
+ "94.140.14.15", // https://adguard-dns.io/kb/general/dns-providers/
+ "94.140.15.16"
+ ],
+ "queryStrategy": "UseIPv4"
+ },
+ }
+ },
+ methods: {
+ loading(spinning = true) {
+ this.spinning = spinning;
+ },
+ async getXraySetting() {
+ this.loading(true);
+ const msg = await HttpUtil.post("/panel/xray/");
+ this.loading(false);
+ if (msg.success) {
+ this.oldXraySetting = msg.obj;
+ this.xraySetting = msg.obj;
+ this.saveBtnDisable = true;
+ }
+ },
+ async updateXraySetting() {
+ this.loading(true);
+ const msg = await HttpUtil.post("/panel/xray/update", {xraySetting : this.xraySetting});
+ this.loading(false);
+ if (msg.success) {
+ await this.getXraySetting();
+ }
+ },
+ async restartPanel() {
+ await new Promise(resolve => {
+ this.$confirm({
+ title: '{{ i18n "pages.settings.restartPanel" }}',
+ content: '{{ i18n "pages.settings.restartPanelDesc" }}',
+ class: themeSwitcher.currentTheme,
+ okText: '{{ i18n "sure" }}',
+ cancelText: '{{ i18n "cancel" }}',
+ onOk: () => resolve(),
+ });
+ });
+ this.loading(true);
+ const msg = await HttpUtil.post("/panel/setting/restartPanel");
+ this.loading(false);
+ if (msg.success) {
+ this.loading(true);
+ await PromiseUtil.sleep(5000);
+ var { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.xraySetting;
+ if (host == this.oldXraySetting.webDomain) host = null;
+ if (port == this.oldXraySetting.webPort) port = null;
+ const isTLS = webCertFile !== "" || webKeyFile !== "";
+ const url = buildURL({ host, port, isTLS, base, path: "panel/settings" });
+ window.location.replace(url);
+ }
+ },
+ async fetchUserSecret() {
+ this.loading(true);
+ const userMessage = await HttpUtil.post("/panel/setting/getUserSecret", this.user);
+ if (userMessage.success) {
+ this.user = userMessage.obj;
+ }
+ this.loading(false);
+ },
+ async updateSecret() {
+ this.loading(true);
+ const msg = await HttpUtil.post("/panel/setting/updateUserSecret", this.user);
+ if (msg.success) {
+ this.user = msg.obj;
+ window.location.replace(basePath + "logout");
+ }
+ this.loading(false);
+ await this.updateXraySetting();
+ },
+ generateRandomString(length) {
+ var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+ let randomString = "";
+ for (let i = 0; i < length; i++) {
+ randomString += chars[Math.floor(Math.random() * chars.length)];
+ }
+ return randomString;
+ },
+ async getNewSecret() {
+ this.loading(true);
+ await PromiseUtil.sleep(600);
+ const newSecret = this.generateRandomString(64);
+ this.user.loginSecret = newSecret;
+ document.getElementById("token").textContent = newSecret;
+ this.loading(false);
+ },
+ async toggleToken(value) {
+ if (value) {
+ await this.getNewSecret();
+ } else {
+ this.user.loginSecret = "";
+ }
+ },
+ async resetXrayConfigToDefault() {
+ this.loading(true);
+ const msg = await HttpUtil.get("/panel/setting/getDefaultJsonConfig");
+ this.loading(false);
+ if (msg.success) {
+ this.templateSettings = JSON.parse(JSON.stringify(msg.obj, null, 2));
+ this.saveBtnDisable = true;
+ }
+ },
+ syncRulesWithOutbound(tag, setting) {
+ const newTemplateSettings = {...this.templateSettings};
+ const haveRules = newTemplateSettings.routing.rules.some((r) => r?.outboundTag === tag);
+ const outboundIndex = newTemplateSettings.outbounds.findIndex((o) => o.tag === tag);
+ if (!haveRules && outboundIndex >= 0) {
+ newTemplateSettings.outbounds.splice(outboundIndex, 1);
+ }
+ if (haveRules && outboundIndex === -1) {
+ newTemplateSettings.outbounds.push(setting);
+ }
+ this.templateSettings = newTemplateSettings;
+ },
+ templateRuleGetter(routeSettings) {
+ const { property, outboundTag } = routeSettings;
+ let result = [];
+ if (this.templateSettings != null) {
+ this.templateSettings.routing.rules.forEach(
+ (routingRule) => {
+ if (
+ routingRule.hasOwnProperty(property) &&
+ routingRule.hasOwnProperty("outboundTag") &&
+ routingRule.outboundTag === outboundTag
+ ) {
+ result.push(...routingRule[property]);
+ }
+ }
+ );
+ }
+ return result;
+ },
+ templateRuleSetter(routeSettings) {
+ const { data, property, outboundTag } = routeSettings;
+ const oldTemplateSettings = this.templateSettings;
+ const newTemplateSettings = oldTemplateSettings;
+ currentProperty = this.templateRuleGetter({ outboundTag, property })
+ if (currentProperty.length == 0) {
+ const propertyRule = {
+ type: "field",
+ outboundTag,
+ [property]: data
+ };
+ newTemplateSettings.routing.rules.push(propertyRule);
+ }
+ else {
+ const newRules = [];
+ insertedOnce = false;
+ newTemplateSettings.routing.rules.forEach(
+ (routingRule) => {
+ if (
+ routingRule.hasOwnProperty(property) &&
+ routingRule.hasOwnProperty("outboundTag") &&
+ routingRule.outboundTag === outboundTag
+ ) {
+ if (!insertedOnce && data.length > 0) {
+ insertedOnce = true;
+ routingRule[property] = data;
+ newRules.push(routingRule);
+ }
+ }
+ else {
+ newRules.push(routingRule);
+ }
+ }
+ );
+ newTemplateSettings.routing.rules = newRules;
+ }
+ this.templateSettings = newTemplateSettings;
+ }
+ },
+ async mounted() {
+ await this.getXraySetting();
+ while (true) {
+ await PromiseUtil.sleep(600);
+ this.saveBtnDisable = this.oldXraySetting === this.xraySetting;
+ }
+ },
+ computed: {
+ templateSettings: {
+ get: function () { return this.xraySetting ? JSON.parse(this.xraySetting) : null; },
+ set: function (newValue) { this.xraySetting = JSON.stringify(newValue, null, 2); },
+ },
+ inboundSettings: {
+ get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.inbounds, null, 2) : null; },
+ set: function (newValue) {
+ newTemplateSettings = this.templateSettings;
+ newTemplateSettings.inbounds = JSON.parse(newValue);
+ this.templateSettings = newTemplateSettings;
+ },
+ },
+ outboundSettings: {
+ get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.outbounds, null, 2) : null; },
+ set: function (newValue) {
+ newTemplateSettings = this.templateSettings;
+ newTemplateSettings.outbounds = JSON.parse(newValue);
+ this.templateSettings = newTemplateSettings;
+ },
+ },
+ routingRuleSettings: {
+ get: function () { return this.templateSettings ? JSON.stringify(this.templateSettings.routing.rules, null, 2) : null; },
+ set: function (newValue) {
+ newTemplateSettings = this.templateSettings;
+ newTemplateSettings.routing.rules = JSON.parse(newValue);
+ this.templateSettings = newTemplateSettings;
+ },
+ },
+ freedomStrategy: {
+ get: function () {
+ if (!this.templateSettings) return "AsIs";
+ freedomOutbound = this.templateSettings.outbounds.find((o) => o.protocol === "freedom" && !o.tag);
+ if (!freedomOutbound) return "AsIs";
+ if (!freedomOutbound.settings || !freedomOutbound.settings.domainStrategy) return "AsIs";
+ return freedomOutbound.settings.domainStrategy;
+ },
+ set: function (newValue) {
+ newTemplateSettings = this.templateSettings;
+ freedomOutboundIndex = newTemplateSettings.outbounds.findIndex((o) => o.protocol === "freedom" && !o.tag);
+ if (!newTemplateSettings.outbounds[freedomOutboundIndex].settings) {
+ newTemplateSettings.outbounds[freedomOutboundIndex].settings = {"domainStrategy": newValue};
+ } else {
+ newTemplateSettings.outbounds[freedomOutboundIndex].settings.domainStrategy = newValue;
+ }
+ this.templateSettings = newTemplateSettings;
+ }
+ },
+ routingStrategy: {
+ get: function () {
+ if (!this.templateSettings || !this.templateSettings.routing || !this.templateSettings.routing.domainStrategy) return "AsIs";
+ return this.templateSettings.routing.domainStrategy;
+ },
+ set: function (newValue) {
+ newTemplateSettings = this.templateSettings;
+ newTemplateSettings.routing.domainStrategy = newValue;
+ this.templateSettings = newTemplateSettings;
+ }
+ },
+ blockedIPs: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "blocked", property: "ip" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "blocked", property: "ip", data: newValue });
+ }
+ },
+ blockedDomains: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "blocked", property: "domain" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "blocked", property: "domain", data: newValue });
+ }
+ },
+ blockedProtocols: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "blocked", property: "protocol" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "blocked", property: "protocol", data: newValue });
+ }
+ },
+ directIPs: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "direct", property: "ip" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "direct", property: "ip", data: newValue });
+ this.syncRulesWithOutbound("direct", this.directSettings);
+ }
+ },
+ directDomains: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "direct", property: "domain" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "direct", property: "domain", data: newValue });
+ this.syncRulesWithOutbound("direct", this.directSettings);
+ }
+ },
+ ipv4Domains: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "IPv4", property: "domain" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "IPv4", property: "domain", data: newValue });
+ this.syncRulesWithOutbound("IPv4", this.ipv4Settings);
+ }
+ },
+ warpDomains: {
+ get: function () {
+ return this.templateRuleGetter({ outboundTag: "WARP", property: "domain" });
+ },
+ set: function (newValue) {
+ this.templateRuleSetter({ outboundTag: "WARP", property: "domain", data: newValue });
+ this.syncRulesWithOutbound("WARP", this.warpSettings);
+ }
+ },
+ manualBlockedIPs: {
+ get: function () { return JSON.stringify(this.blockedIPs, null, 2); },
+ set: debounce(function (value) { this.blockedIPs = JSON.parse(value); }, 1000)
+ },
+ manualBlockedDomains: {
+ get: function () { return JSON.stringify(this.blockedDomains, null, 2); },
+ set: debounce(function (value) { this.blockedDomains = JSON.parse(value); }, 1000)
+ },
+ manualDirectIPs: {
+ get: function () { return JSON.stringify(this.directIPs, null, 2); },
+ set: debounce(function (value) { this.directIPs = JSON.parse(value); }, 1000)
+ },
+ manualDirectDomains: {
+ get: function () { return JSON.stringify(this.directDomains, null, 2); },
+ set: debounce(function (value) { this.directDomains = JSON.parse(value); }, 1000)
+ },
+ manualIPv4Domains: {
+ get: function () { return JSON.stringify(this.ipv4Domains, null, 2); },
+ set: debounce(function (value) { this.ipv4Domains = JSON.parse(value); }, 1000)
+ },
+ manualWARPDomains: {
+ get: function () { return JSON.stringify(this.warpDomains, null, 2); },
+ set: debounce(function (value) { this.warpDomains = JSON.parse(value); }, 1000)
+ },
+ torrentSettings: {
+ get: function () {
+ return doAllItemsExist(this.settingsData.protocols.bittorrent, this.blockedProtocols);
+ },
+ set: function (newValue) {
+ if (newValue) {
+ this.blockedProtocols = [...this.blockedProtocols, ...this.settingsData.protocols.bittorrent];
+ } else {
+ this.blockedProtocols = this.blockedProtocols.filter(data => !this.settingsData.protocols.bittorrent.includes(data));
+ }
+ },
+ },
+ privateIpSettings: {
+ get: function () {
+ return doAllItemsExist(this.settingsData.ips.local, this.blockedIPs);
+ },
+ set: function (newValue) {
+ if (newValue) {
+ this.blockedIPs = [...this.blockedIPs, ...this.settingsData.ips.local];
+ } else {
+ this.blockedIPs = this.blockedIPs.filter(data => !this.settingsData.ips.local.includes(data));
+ }
+ },
+ },
+ AdsSettings: {
+ get: function () {
+ return doAllItemsExist(this.settingsData.domains.ads, this.blockedDomains);
+ },
+ set: function (newValue) {
+ if (newValue) {
+ this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.ads];
+ } else {
+ this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.ads.includes(data));
+ }
+ },
+ },
+ SpeedTestSettings: {
+ get: function () {
+ return doAllItemsExist(this.settingsData.domains.speedtest, this.blockedDomains);
+ },
+ set: function (newValue) {
+ if (newValue) {
+ this.blockedDomains = [...this.blockedDomains, ...this.settingsData.domains.speedtest];
+ } else {
+ this.blockedDomains = this.blockedDomains.filter(data => !this.settingsData.domains.speedtest.includes(data));
+ }
+ },
+ },
+ familyProtectSettings: {
+ get: function () {
+ if (!this.templateSettings || !this.templateSettings.dns || !this.templateSettings.dns.servers) return false;
+ return doAllItemsExist(this.templateSettings.dns.servers, this.settingsData.familyProtectDNS.servers);
+ },
+ set: function (newValue) {
+ newTemplateSettings = this.templateSettings;
+ if (newValue) {
+ newTemplateSettings.dns = this.settingsData.familyProtectDNS;
+ } else {
+ delete newTemplateSettings.dns;
+ }
+ this.templateSettings = newTemplateSettings;
+ },
+ },
+ GoogleIPv4Settings: {
+ get: function () {
+ return doAllItemsExist(this.settingsData.domains.google, this.ipv4Domains);
+ },
+ set: function (newValue) {
+ if (newValue) {
+ this.ipv4Domains = [...this.ipv4Domains, ...this.settingsData.domains.google];
+ } else {
+ this.ipv4Domains = this.ipv4Domains.filter(data => !this.settingsData.domains.google.includes(data));
+ }
+ },
+ },
+ NetflixIPv4Settings: {
+ get: function () {
+ return doAllItemsExist(this.settingsData.domains.netflix, this.ipv4Domains);
+ },
+ set: function (newValue) {
+ if (newValue) {
+ this.ipv4Domains = [...this.ipv4Domains, ...this.setting