mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-14 05:23:09 +00:00
[feature] WARP via wireguard
This commit is contained in:
@@ -26,6 +26,7 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
|
||||
g.POST("/update", a.updateSetting)
|
||||
g.GET("/getXrayResult", a.getXrayResult)
|
||||
g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
|
||||
g.POST("/warp/:action", a.warp)
|
||||
}
|
||||
|
||||
func (a *XraySettingController) getXraySetting(c *gin.Context) {
|
||||
@@ -61,3 +62,25 @@ func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) {
|
||||
func (a *XraySettingController) getXrayResult(c *gin.Context) {
|
||||
jsonObj(c, a.XrayService.GetXrayResult(), nil)
|
||||
}
|
||||
|
||||
func (a *XraySettingController) warp(c *gin.Context) {
|
||||
action := c.Param("action")
|
||||
var resp string
|
||||
var err error
|
||||
switch action {
|
||||
case "data":
|
||||
resp, err = a.XraySettingService.GetWarp()
|
||||
case "config":
|
||||
resp, err = a.XraySettingService.GetWarpConfig()
|
||||
case "reg":
|
||||
skey := c.PostForm("privateKey")
|
||||
pkey := c.PostForm("publicKey")
|
||||
resp, err = a.XraySettingService.RegWarp(skey, pkey)
|
||||
case "license":
|
||||
license := c.PostForm("license")
|
||||
println(license)
|
||||
resp, err = a.XraySettingService.SetWarpLicence(license)
|
||||
}
|
||||
|
||||
jsonObj(c, resp, err)
|
||||
}
|
||||
|
||||
204
web/html/xui/warp_modal.html
Normal file
204
web/html/xui/warp_modal.html
Normal file
@@ -0,0 +1,204 @@
|
||||
{{define "warpModal"}}
|
||||
<a-modal id="warp-modal" v-model="warpModal.visible" title="Cloudflare WARP"
|
||||
:confirm-loading="warpModal.confirmLoading" :closable="true" :mask-closable="true"
|
||||
:footer="null" :class="themeSwitcher.currentTheme">
|
||||
<template v-if="ObjectUtil.isEmpty(warpModal.warpData)">
|
||||
<a-button icon="api" @click="register" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.create" }}</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<table style="margin: 5px 0; width: 100%;">
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Access Token</td>
|
||||
<td>[[ warpModal.warpData.access_token ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Devide ID</td>
|
||||
<td>[[ warpModal.warpData.device_id ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>License Key</td>
|
||||
<td>[[ warpModal.warpData.license_key ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Private Key</td>
|
||||
<td>[[ warpModal.warpData.private_key ]]</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a-divider style="margin: 0;">{{ i18n "pages.settings.toasts.modifySettings" }}</a-divider>
|
||||
<a-collapse style="margin: 10px 0;">
|
||||
<a-collapse-panel header='WARP/WARP+ License Key'>
|
||||
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label="License Key">
|
||||
<a-input v-model="warpPlus"></a-input>
|
||||
<a-button @click="updateLicense(warpPlus)" :disabled="warpPlus.length<26" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.update" }}</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
<a-divider style="margin: 0;">{{ i18n "pages.settings.toasts.getSettings" }}</a-divider>
|
||||
<a-button icon="sync" @click="getConfig" style="margin-bottom: 10px;" :loading="warpModal.confirmLoading">{{ i18n "info" }}</a-button>
|
||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig)">
|
||||
<table style="width: 100%">
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Device Name</td>
|
||||
<td>[[ warpModal.warpConfig.name ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Device Model</td>
|
||||
<td>[[ warpModal.warpConfig.model ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Device Active</td>
|
||||
<td>[[ warpModal.warpConfig.enabled ]]</td>
|
||||
</tr>
|
||||
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account)">
|
||||
<tr>
|
||||
<td>Account Type</td>
|
||||
<td>[[ warpModal.warpConfig.account.account_type ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Role</td>
|
||||
<td>[[ warpModal.warpConfig.account.role ]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Premium Data</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.premium_data) ]]</td>
|
||||
</tr>
|
||||
<tr class="client-table-odd-row">
|
||||
<td>Quota</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.quota) ]]</td>
|
||||
</tr>
|
||||
<tr v-if="!ObjectUtil.isEmpty(warpModal.warpConfig.account.usage)">
|
||||
<td>Usage</td>
|
||||
<td>[[ sizeFormat(warpModal.warpConfig.account.usage) ]]</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
<a-divider style="margin: 10px 0;">WARP {{ i18n "pages.xray.rules.outbound" }}</a-divider>
|
||||
<a-form :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label="{{ i18n "status" }}">
|
||||
<template v-if="warpOutboundIndex>=0">
|
||||
<a-tag color="green">{{ i18n "enabled" }}</a-tag>
|
||||
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading">{{ i18n "reset" }}</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-tag color="orange">{{ i18n "disabled" }}</a-tag>
|
||||
<a-button @click="addOutbound" :loading="warpModal.confirmLoading">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
|
||||
</template>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
</template>
|
||||
</a-modal>
|
||||
<script>
|
||||
|
||||
const warpModal = {
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
warpData: null,
|
||||
warpConfig: null,
|
||||
warpOutbound: null,
|
||||
show() {
|
||||
this.visible = true;
|
||||
this.warpConfig = null;
|
||||
this.getData();
|
||||
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
this.loading(false);
|
||||
},
|
||||
loading(loading) {
|
||||
this.confirmLoading = loading;
|
||||
},
|
||||
async getData(){
|
||||
this.loading(true);
|
||||
const msg = await HttpUtil.post('/xui/xray/warp/data');
|
||||
this.loading(false);
|
||||
if (msg.success) {
|
||||
this.warpData = msg.obj.length>0 ? JSON.parse(msg.obj): null;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
new Vue({
|
||||
delimiters: ['[[', ']]'],
|
||||
el: '#warp-modal',
|
||||
data: {
|
||||
warpModal: warpModal,
|
||||
warpPlus: '',
|
||||
},
|
||||
methods: {
|
||||
collectConfig() {
|
||||
config = warpModal.warpConfig.config;
|
||||
peer = config.peers[0];
|
||||
if(config){
|
||||
warpModal.warpOutbound = Outbound.fromJson({
|
||||
tag: 'warp',
|
||||
protocol: Protocols.Wireguard,
|
||||
settings: {
|
||||
mtu: 1420,
|
||||
secretKey: warpModal.warpData.private_key,
|
||||
address: Object.values(config.interface.addresses),
|
||||
peers: [{
|
||||
publicKey: peer.public_key,
|
||||
endpoint: peer.endpoint.host,
|
||||
}],
|
||||
kernelMode: false
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
async register(){
|
||||
warpModal.loading(true);
|
||||
keys = Wireguard.generateKeypair();
|
||||
const msg = await HttpUtil.post('/xui/xray/warp/reg',keys);
|
||||
if (msg.success) {
|
||||
resp = JSON.parse(msg.obj);
|
||||
warpModal.warpData = resp.data;
|
||||
warpModal.warpConfig = resp.config;
|
||||
this.collectConfig();
|
||||
}
|
||||
warpModal.loading(false);
|
||||
},
|
||||
async updateLicense(l){
|
||||
warpModal.loading(true);
|
||||
const msg = await HttpUtil.post('/xui/xray/warp/license',{license: l});
|
||||
if (msg.success) {
|
||||
warpModal.warpData = JSON.parse(msg.obj);
|
||||
warpModal.warpConfig = null;
|
||||
this.warpPlus = '';
|
||||
}
|
||||
warpModal.loading(false);
|
||||
},
|
||||
async getConfig(){
|
||||
warpModal.loading(true);
|
||||
const msg = await HttpUtil.post('/xui/xray/warp/config');
|
||||
warpModal.loading(false);
|
||||
if (msg.success) {
|
||||
warpModal.warpConfig = JSON.parse(msg.obj);
|
||||
this.collectConfig();
|
||||
}
|
||||
},
|
||||
addOutbound(){
|
||||
app.templateSettings.outbounds.push(warpModal.warpOutbound.toJson());
|
||||
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
|
||||
warpModal.close();
|
||||
},
|
||||
resetOutbound(){
|
||||
app.templateSettings.outbounds[this.warpOutboundIndex] = warpModal.warpOutbound.toJson();
|
||||
app.outboundSettings = JSON.stringify(app.templateSettings.outbounds);
|
||||
warpModal.close();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
warpOutboundIndex: {
|
||||
get: function() {
|
||||
return app.templateSettings ? app.templateSettings.outbounds.findIndex((o) => o.tag == 'warp') : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
{{end}}
|
||||
@@ -209,6 +209,23 @@
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.GoogleIPv4"}}' desc='{{ i18n "pages.xray.GoogleIPv4Desc"}}' v-model="GoogleIPv4Settings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.NetflixIPv4"}}' desc='{{ i18n "pages.xray.NetflixIPv4Desc"}}' v-model="NetflixIPv4Settings"></setting-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.warpConfigs"}}'>
|
||||
<a-row :xs="24" :sm="24" :lg="12">
|
||||
<a-alert type="warning" style="text-align: center;">
|
||||
<template slot="message">
|
||||
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
|
||||
{{ i18n "pages.xray.warpConfigsDesc" }}
|
||||
</template>
|
||||
</a-alert>
|
||||
</a-row>
|
||||
<template v-if="WarpExist">
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.GoogleWARP"}}' desc='{{ i18n "pages.xray.GoogleWARPDesc"}}' v-model="GoogleWARPSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.OpenAIWARP"}}' desc='{{ i18n "pages.xray.OpenAIWARPDesc"}}' v-model="OpenAIWARPSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.NetflixWARP"}}' desc='{{ i18n "pages.xray.NetflixWARPDesc"}}' v-model="NetflixWARPSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.SpotifyWARP"}}' desc='{{ i18n "pages.xray.SpotifyWARPDesc"}}' v-model="SpotifyWARPSettings"></setting-list-item>
|
||||
</template>
|
||||
<a-button v-else style="margin: 10px 0;" @click="showWarp">WARP {{ i18n "pages.xray.rules.outbound" }}</a-button>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.settings.resetDefaultConfig"}}'>
|
||||
<a-space direction="horizontal" style="padding: 0 20px">
|
||||
<a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
|
||||
@@ -326,6 +343,7 @@
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="tpl-3" tab='{{ i18n "pages.xray.Outbounds"}}' style="padding-top: 20px;" force-render="true">
|
||||
<a-button type="primary" icon="plus" @click="addOutbound()" style="margin-bottom: 10px;">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
|
||||
<a-button type="primary" @click="showWarp()" style="margin-bottom: 10px;">WARP</a-button>
|
||||
<a-table :columns="outboundColumns" bordered
|
||||
:row-key="r => r.key"
|
||||
:data-source="outboundData"
|
||||
@@ -413,6 +431,7 @@
|
||||
{{template "ruleModal"}}
|
||||
{{template "outModal"}}
|
||||
{{template "reverseModal"}}
|
||||
{{template "warpModal"}}
|
||||
<script>
|
||||
const rulesColumns = [
|
||||
{ title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } },
|
||||
@@ -519,7 +538,9 @@
|
||||
"geosite:category-ads-all",
|
||||
"ext:geosite_IR.dat:category-ads-all"
|
||||
],
|
||||
openai: ["geosite:openai"],
|
||||
google: ["geosite:google"],
|
||||
spotify: ["geosite:spotify"],
|
||||
netflix: ["geosite:netflix"],
|
||||
cn: [
|
||||
"geosite:cn",
|
||||
@@ -701,6 +722,8 @@
|
||||
break;
|
||||
case Protocols.DNS:
|
||||
return [o.settings.address + ':' + o.settings.port];
|
||||
case Protocols.Wireguard:
|
||||
return o.settings.peers.map(peer => peer.endpoint);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -866,6 +889,9 @@
|
||||
rules = this.templateSettings.routing.rules;
|
||||
rules.splice(index,1);
|
||||
this.routingRuleSettings = JSON.stringify(rules);
|
||||
},
|
||||
showWarp(){
|
||||
warpModal.show();
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
@@ -1041,6 +1067,14 @@
|
||||
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 });
|
||||
}
|
||||
},
|
||||
torrentSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.protocols.bittorrent, this.blockedProtocols);
|
||||
@@ -1260,6 +1294,59 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
WarpExist: {
|
||||
get: function() {
|
||||
return this.templateSettings ? this.templateSettings.outbounds.findIndex((o) => o.tag == "warp")>=0 : false;
|
||||
},
|
||||
},
|
||||
GoogleWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.google, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.google];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.google.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
OpenAIWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.openai, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.openai];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.openai.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
NetflixWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.netflix, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.netflix];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.netflix.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
SpotifyWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.spotify, this.warpDomains);
|
||||
},
|
||||
set: function (newValue) {
|
||||
if (newValue) {
|
||||
this.warpDomains = [...this.warpDomains, ...this.settingsData.domains.spotify];
|
||||
} else {
|
||||
this.warpDomains = this.warpDomains.filter(data => !this.settingsData.domains.spotify.includes(data));
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -55,6 +55,7 @@ var defaultValueMap = map[string]string{
|
||||
"subEncrypt": "true",
|
||||
"subShowInfo": "false",
|
||||
"subURI": "",
|
||||
"warp": "",
|
||||
}
|
||||
|
||||
type SettingService struct {
|
||||
@@ -397,6 +398,13 @@ func (s *SettingService) GetSubURI() (string, error) {
|
||||
return s.getString("subURI")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetWarp() (string, error) {
|
||||
return s.getString("warp")
|
||||
}
|
||||
func (s *SettingService) SetWarp(data string) error {
|
||||
return s.setString("warp", data)
|
||||
}
|
||||
|
||||
func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
|
||||
if err := allSetting.CheckValid(); err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
"x-ui/util/common"
|
||||
"x-ui/xray"
|
||||
)
|
||||
@@ -26,3 +31,142 @@ func (s *XraySettingService) CheckXrayConfig(XrayTemplateConfig string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) GetWarpData() (string, error) {
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return warp, nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) GetWarpConfig() (string, error) {
|
||||
var warpData map[string]string
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(warp), &warpData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s", warpData["device_id"])
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) RegWarp(secretKey string, publicKey string) (string, error) {
|
||||
tos := time.Now().UTC().Format("2006-01-02T15:04:05.000Z")
|
||||
hostName, _ := os.Hostname()
|
||||
data := fmt.Sprintf(`{"key":"%s","tos":"%s","type": "PC","model": "x-ui", "name": "%s"}`, publicKey, tos, hostName)
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg")
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Add("CF-Client-Version", "a-7.21-0721")
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var rspData map[string]interface{}
|
||||
err = json.Unmarshal(buffer.Bytes(), &rspData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deviceId := rspData["id"].(string)
|
||||
token := rspData["token"].(string)
|
||||
license, ok := rspData["account"].(map[string]interface{})["license"].(string)
|
||||
if !ok {
|
||||
fmt.Println("Error accessing license value.")
|
||||
return "", err
|
||||
}
|
||||
|
||||
warpData := fmt.Sprintf("{\n \"access_token\": \"%s\",\n \"device_id\": \"%s\",", token, deviceId)
|
||||
warpData += fmt.Sprintf("\n \"license_key\": \"%s\",\n \"private_key\": \"%s\"\n}", license, secretKey)
|
||||
|
||||
s.SettingService.SetWarp(warpData)
|
||||
|
||||
result := fmt.Sprintf("{\n \"data\": %s,\n \"config\": %s\n}", warpData, buffer.String())
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *XraySettingService) SetWarpLicence(license string) (string, error) {
|
||||
var warpData map[string]string
|
||||
warp, err := s.SettingService.GetWarp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(warp), &warpData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.cloudflareclient.com/v0a2158/reg/%s/account", warpData["device_id"])
|
||||
data := fmt.Sprintf(`{"license": "%s"}`, license)
|
||||
|
||||
req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+warpData["access_token"])
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.NewBuffer(make([]byte, 8192))
|
||||
buffer.Reset()
|
||||
_, err = buffer.ReadFrom(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
warpData["license_key"] = license
|
||||
newWarpData, err := json.MarshalIndent(warpData, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s.SettingService.SetWarp(string(newWarpData))
|
||||
println(string(newWarpData))
|
||||
|
||||
return string(newWarpData), nil
|
||||
}
|
||||
|
||||
@@ -312,6 +312,8 @@
|
||||
"directCountryConfigsDesc" = "These options will directly forward traffic based on the specific requested country."
|
||||
"ipv4Configs" = "IPv4 Routing"
|
||||
"ipv4ConfigsDesc" = "These options will route requests to destination only via IPv4."
|
||||
"warpConfigs" = "WARP Routing"
|
||||
"warpConfigsDesc" = "WARP will route traffic to websites through Cloudflare servers."
|
||||
"Template" = "Advanced Xray Configuration Template"
|
||||
"TemplateDesc" = "The final Xray configuration file will be generated based on this template."
|
||||
"FreedomStrategy" = "Freedom Protocol Strategy"
|
||||
@@ -354,6 +356,14 @@
|
||||
"GoogleIPv4Desc" = "Routes traffic to Google via IPv4."
|
||||
"NetflixIPv4" = "Netflix"
|
||||
"NetflixIPv4Desc" = "Routes traffic to Netflix via IPv4."
|
||||
"GoogleWARP" = "Route Google through WARP."
|
||||
"GoogleWARPDesc" = "Add routing for Google via WARP."
|
||||
"OpenAIWARP" = "Route OpenAI (ChatGPT) through WARP."
|
||||
"OpenAIWARPDesc" = "Add routing for OpenAI (ChatGPT) via WARP."
|
||||
"NetflixWARP" = "Route Netflix through WARP."
|
||||
"NetflixWARPDesc" = "Add routing for Netflix via WARP."
|
||||
"SpotifyWARP" = "Route Spotify through WARP."
|
||||
"SpotifyWARPDesc" = "Add routing for Spotify via WARP."
|
||||
"completeTemplate" = "All"
|
||||
"Inbounds" = "Inbounds"
|
||||
"Outbounds" = "Outbounds"
|
||||
|
||||
@@ -311,6 +311,8 @@
|
||||
"directCountryConfigsDesc" = "این گزینهها ترافیک را بر اساس کشور درخواستی خاص بصورت مستقیم ارسال میکند"
|
||||
"ipv4Configs" = "IPv4 مسیریابی"
|
||||
"ipv4ConfigsDesc" = "این گزینهها درخواستها را فقط از طریق آیپینسخه4 به مقصد هدایت میکند"
|
||||
"warpConfigs" = "تنظیمات برای وارپ"
|
||||
"warpConfigsDesc" = ".وارپ ترافیک را از طریق سرورهای کلادفلر به وب سایت ها هدایت می کند"
|
||||
"Template" = "پیکربندی پیشرفته الگو ایکسری"
|
||||
"TemplateDesc" = "فایل پیکربندی نهایی ایکسری بر اساس این الگو ایجاد میشود"
|
||||
"FreedomStrategy" = "Freedom استراتژی پروتکل"
|
||||
@@ -354,6 +356,14 @@
|
||||
"NetflixIPv4" = "نتفلیکس"
|
||||
"NetflixIPv4Desc" = "ترافیک را از طریق آیپینسخه4 به نتفلیکس هدایت میکند"
|
||||
"completeTemplate" = "کامل"
|
||||
"GoogleWARP" = "مسیردهی گوگل به وارپ"
|
||||
"GoogleWARPDesc" = "مسیردهی جدید برای اتصال به گوگل به وارپ اضافه میکند"
|
||||
"OpenAIWARP" = "مسیردهی چت جیبیتی به وارپ"
|
||||
"OpenAIWARPDesc" = "مسیردهی جدید برای اتصال به چت جیبیتی به وارپ اضافه میکند"
|
||||
"NetflixWARP" = "مسیردهی نتفلیکس به وارپ"
|
||||
"NetflixWARPDesc" = "مسیردهی جدید برای اتصال به نتفلیکس به وارپ اضافه میکند"
|
||||
"SpotifyWARP" = "مسیردهی اسپاتیفای به وارپ"
|
||||
"SpotifyWARPDesc" = "مسیردهی جدید برای اتصال به اسپاتیفای به وارپ اضافه میکند"
|
||||
"Inbounds" = "ورودیها"
|
||||
"Outbounds" = "خروجیها"
|
||||
"Routings" = "قوانین مسیریابی"
|
||||
|
||||
@@ -312,6 +312,8 @@
|
||||
"directCountryConfigsDesc" = "Эти параметры будут подключать пользователей напрямую к доменам определенной страны."
|
||||
"ipv4Configs" = "Настройки IPv4"
|
||||
"ipv4ConfigsDesc" = "Эти параметры будут маршрутизироваться к целевым доменам только через IPv4"
|
||||
"warpConfigs" = "Настройки WARP"
|
||||
"warpConfigsDesc" = "WARP будет направлять трафик на веб-сайты через серверы Cloudflare"
|
||||
"Template" = "Шаблон конфигурации Xray"
|
||||
"TemplateDesc" = "Создание файла конфигурации Xray на основе этого шаблона."
|
||||
"FreedomStrategy" = "Настроить стратегию протокола Freedom"
|
||||
@@ -354,6 +356,14 @@
|
||||
"GoogleIPv4Desc" = "Применить маршрутизацию Google для подключения к IPv4."
|
||||
"NetflixIPv4" = "Использовать IPv4 для Netflix"
|
||||
"NetflixIPv4Desc" = "Применить маршрутизацию Netflix для подключения к IPv4."
|
||||
"GoogleWARP" = "Маршрутизация Google через WARP"
|
||||
"GoogleWARPDesc" = "Добавить маршрутизацию для Google через WARP"
|
||||
"OpenAIWARP" = "Маршрутизация OpenAI (ChatGPT) через WARP"
|
||||
"OpenAIWARPDesc" = "Добавить маршрутизацию для OpenAI (ChatGPT) через WARP"
|
||||
"NetflixWARP" = "Маршрутизация Netflix через WARP"
|
||||
"NetflixWARPDesc" = "Добавить маршрутизацию для Netflix через WARP"
|
||||
"SpotifyWARP" = "Маршрутизация Spotify через WARP"
|
||||
"SpotifyWARPDesc" = "Добавить маршрутизацию для Spotify через WARP"
|
||||
"completeTemplate" = "Все"
|
||||
"Inbounds" = "Входящие"
|
||||
"Outbounds" = "Исходящие"
|
||||
|
||||
@@ -312,6 +312,8 @@
|
||||
"directCountryConfigsDesc" = "Những tùy chọn này sẽ kết nối người dùng trực tiếp đến các tên miền quốc gia cụ thể."
|
||||
"ipv4Configs" = "Cấu hình IPv4"
|
||||
"ipv4ConfigsDesc" = "Những tùy chọn này sẽ chỉ định kết nối đến các tên miền mục tiêu qua IPv4."
|
||||
"warpConfigs" = "Cấu hình WARP"
|
||||
"warpConfigsDesc" = "WARP sẽ định tuyến lưu lượng đến các trang web qua máy chủ Cloudflare."
|
||||
"Template" = "Mẫu cấu hình Xray"
|
||||
"TemplateDesc" = "Tạo tệp cấu hình Xray cuối cùng dựa trên mẫu này."
|
||||
"FreedomStrategy" = "Cấu hình chiến lược cho giao thức tự do"
|
||||
@@ -354,6 +356,14 @@
|
||||
"GoogleIPv4Desc" = "Thêm định tuyến để Google kết nối với IPv4."
|
||||
"NetflixIPv4" = "Sử dụng IPv4 cho Netflix"
|
||||
"NetflixIPv4Desc" = "Thêm định tuyến cho Netflix để kết nối với IPv4."
|
||||
"GoogleWARP" = "Định tuyến Google qua WARP."
|
||||
"GoogleWARPDesc" = "Thêm định tuyến cho Google qua WARP."
|
||||
"OpenAIWARP" = "Định tuyến OpenAI (ChatGPT) qua WARP."
|
||||
"OpenAIWARPDesc" = "Thêm định tuyến cho OpenAI (ChatGPT) qua WARP."
|
||||
"NetflixWARP" = "Định tuyến Netflix qua WARP."
|
||||
"NetflixWARPDesc" = "Thêm định tuyến cho Netflix qua WARP."
|
||||
"SpotifyWARP" = "Định tuyến Spotify qua WARP."
|
||||
"SpotifyWARPDesc" = "Thêm định tuyến cho Spotify qua WARP."
|
||||
"completeTemplate" = "Tất cả"
|
||||
"Inbounds" = "Đầu vào"
|
||||
"Outbounds" = "Đầu ra"
|
||||
|
||||
@@ -312,6 +312,8 @@
|
||||
"directCountryConfigsDesc" = "这些选项会将用户直接连接到特定国家/地区的域。"
|
||||
"ipv4Configs" = "IPv4 配置"
|
||||
"ipv4ConfigsDesc" = "此选项将仅通过 IPv4 路由到目标域"
|
||||
"warpConfigs" = "WARP 配置"
|
||||
"warpConfigsDesc" = "WARP 将通过 Cloudflare 服务器将流量路由到网站。"
|
||||
"Template" = "Xray 配置模板"
|
||||
"TemplateDesc" = "以该模型为基础生成最终的Xray配置文件,重新启动面板生成效率"
|
||||
"FreedomStrategy" = "配置自由协议的策略"
|
||||
@@ -354,6 +356,14 @@
|
||||
"GoogleIPv4Desc" = "添加谷歌连接IPv4的路由"
|
||||
"NetflixIPv4" = "为 Netflix 使用 IPv4"
|
||||
"NetflixIPv4Desc" = "添加Netflix连接IPv4的路由"
|
||||
"GoogleWARP" = "将谷歌路由到 WARP"
|
||||
"GoogleWARPDesc" = "为谷歌添加路由到WARP"
|
||||
"OpenAIWARP" = "将 OpenAI (ChatGPT) 路由到 WARP"
|
||||
"OpenAIWARPDesc" = "将OpenAI(ChatGPT)路由添加到WARP"
|
||||
"NetflixWARP" = "将 Netflix 路由到 WARP"
|
||||
"NetflixWARPDesc" = "为Netflix添加路由到WARP"
|
||||
"SpotifyWARP" = "将 Spotify 路由到 WARP"
|
||||
"SpotifyWARPDesc" = "为Spotify添加路由到WARP"
|
||||
"completeTemplate" = "全部"
|
||||
"Inbounds" = "界内"
|
||||
"Outbounds" = "出站"
|
||||
|
||||
Reference in New Issue
Block a user