mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-19 23:35:48 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4838b0f6f0 | ||
|
|
bb8807129a | ||
|
|
cb050bfe34 | ||
|
|
76a996cc2d | ||
|
|
7fec1dd5cf | ||
|
|
a24e9089b6 | ||
|
|
b6474eaef6 | ||
|
|
76f90b0a46 | ||
|
|
42abffdaef |
@@ -10,8 +10,11 @@ else
|
|||||||
FNAME="amd64";
|
FNAME="amd64";
|
||||||
fi
|
fi
|
||||||
mkdir -p build/bin
|
mkdir -p build/bin
|
||||||
|
cd build/bin
|
||||||
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.1/Xray-linux-${ARCH}.zip"
|
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.1/Xray-linux-${ARCH}.zip"
|
||||||
wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" -o build/bin/geoip.dat
|
unzip "Xray-linux-${ARCH}.zip"
|
||||||
wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" -o build/bin/geosite.dat
|
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat
|
||||||
mv xray "build/bin/xray-linux-${FNAME}"
|
mv xray "xray-linux-${FNAME}"
|
||||||
mv main build/x-ui
|
wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||||
|
wget "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||||
|
cd ../../
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
FROM golang:1.20-alpine AS builder
|
FROM golang:1.20-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
RUN apk --no-cache --update add build-base gcc wget
|
RUN apk --no-cache --update add build-base gcc wget unzip
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN env CGO_ENABLED=1 go build main.go
|
RUN env CGO_ENABLED=1 go build -o build/x-ui main.go
|
||||||
RUN ./DockerInitFiles.sh "$TARGETARCH"
|
RUN ./DockerInitFiles.sh "$TARGETARCH"
|
||||||
|
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.0.0
|
1.0.1
|
||||||
8
main.go
8
main.go
@@ -51,8 +51,8 @@ func runWebServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
//信号量捕获处理
|
// Trap shutdown signals
|
||||||
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL)
|
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM)
|
||||||
for {
|
for {
|
||||||
sig := <-sigCh
|
sig := <-sigCh
|
||||||
|
|
||||||
@@ -133,7 +133,6 @@ func updateTgbotEnableSts(status bool) {
|
|||||||
logger.Infof("SetTgbotenabled[%v] success", status)
|
logger.Infof("SetTgbotenabled[%v] success", status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) {
|
func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) {
|
||||||
@@ -290,6 +289,9 @@ func main() {
|
|||||||
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
|
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
|
||||||
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
|
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
|
||||||
}
|
}
|
||||||
|
if enabletgbot {
|
||||||
|
updateTgbotEnableSts(enabletgbot)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Println("except 'run' or 'v2-ui' or 'setting' subcommands")
|
fmt.Println("except 'run' or 'v2-ui' or 'setting' subcommands")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|||||||
@@ -647,7 +647,7 @@ class RealityStreamSettings extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RealityStreamSettings.Settings = class extends XrayCommonClass {
|
RealityStreamSettings.Settings = class extends XrayCommonClass {
|
||||||
constructor(publicKey = '', fingerprint = '', serverName = '', spiderX= '/') {
|
constructor(publicKey = '', fingerprint = UTLS_FINGERPRINT.UTLS_FIREFOX, serverName = '', spiderX= '/') {
|
||||||
super();
|
super();
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
this.fingerprint = fingerprint;
|
this.fingerprint = fingerprint;
|
||||||
@@ -1243,15 +1243,13 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (this.reality) {
|
if (this.reality) {
|
||||||
params.set("security", "reality");
|
params.set("security", "reality");
|
||||||
params.set("pbk", this.stream.reality.settings.publicKey);
|
params.set("pbk", this.stream.reality.settings.publicKey);
|
||||||
|
params.set("fp", this.stream.reality.settings.fingerprint);
|
||||||
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
|
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
|
||||||
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
|
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (this.stream.reality.shortIds.length > 0) {
|
if (this.stream.reality.shortIds.length > 0) {
|
||||||
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (!ObjectUtil.isEmpty(this.stream.reality.fingerprint)) {
|
|
||||||
params.set("fp", this.stream.reality.settings.fingerprint);
|
|
||||||
}
|
|
||||||
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
||||||
address = this.stream.reality.settings.serverName;
|
address = this.stream.reality.settings.serverName;
|
||||||
}
|
}
|
||||||
@@ -1355,15 +1353,13 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (this.reality) {
|
if (this.reality) {
|
||||||
params.set("security", "reality");
|
params.set("security", "reality");
|
||||||
params.set("pbk", this.stream.reality.settings.publicKey);
|
params.set("pbk", this.stream.reality.settings.publicKey);
|
||||||
|
params.set("fp", this.stream.reality.settings.fingerprint);
|
||||||
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
|
if (!ObjectUtil.isArrEmpty(this.stream.reality.serverNames)) {
|
||||||
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
|
params.set("sni", this.stream.reality.serverNames.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (this.stream.reality.shortIds.length > 0) {
|
if (this.stream.reality.shortIds.length > 0) {
|
||||||
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
params.set("sid", this.stream.reality.shortIds.split(",")[0]);
|
||||||
}
|
}
|
||||||
if (!ObjectUtil.isEmpty(this.stream.reality.fingerprint)) {
|
|
||||||
params.set("fp", this.stream.reality.settings.fingerprint);
|
|
||||||
}
|
|
||||||
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
if (!ObjectUtil.isEmpty(this.stream.reality.settings.serverName)) {
|
||||||
address = this.stream.reality.settings.serverName;
|
address = this.stream.reality.settings.serverName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (a *SUBController) subs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add subscription-userinfo
|
// Add subscription-userinfo
|
||||||
c.Writer.Header().Set("subscription-userinfo", header)
|
c.Writer.Header().Set("Subscription-Userinfo", header)
|
||||||
|
|
||||||
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,24 @@
|
|||||||
}
|
}
|
||||||
client.email = string;
|
client.email = string;
|
||||||
},
|
},
|
||||||
|
resetClientTraffic(email,dbInboundId,iconElement) {
|
||||||
|
this.$confirm({
|
||||||
|
title: '{{ i18n "pages.inbounds.resetTraffic"}}',
|
||||||
|
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
||||||
|
class: siderDrawer.isDarkTheme ? darkClass : '',
|
||||||
|
okText: '{{ i18n "reset"}}',
|
||||||
|
cancelText: '{{ i18n "cancel"}}',
|
||||||
|
onOk: async () => {
|
||||||
|
iconElement.disabled = true;
|
||||||
|
const msg = await HttpUtil.postWithModal('/xui/inbound/' + dbInboundId + '/resetClientTraffic/'+ email);
|
||||||
|
if (msg.success) {
|
||||||
|
this.clientModal.clientStats.up = 0;
|
||||||
|
this.clientModal.clientStats.down = 0;
|
||||||
|
}
|
||||||
|
iconElement.disabled = false;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<a-input :value="value" @input="$emit('input', $event.target.value)"></a-input>
|
<a-input :value="value" @input="$emit('input', $event.target.value)"></a-input>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="type === 'number'">
|
<template v-else-if="type === 'number'">
|
||||||
<a-input-number :value="value" @input="$emit('input', $event.target.value)"></a-input-number>
|
<a-input type="number" :value="value" @input="$emit('input', $event.target.value)"></a-input>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="type === 'textarea'">
|
<template v-else-if="type === 'textarea'">
|
||||||
<a-textarea :value="value" @input="$emit('input', $event.target.value)" :auto-size="{ minRows: 10, maxRows: 10 }"></a-textarea>
|
<a-textarea :value="value" @input="$emit('input', $event.target.value)" :auto-size="{ minRows: 10, maxRows: 10 }"></a-textarea>
|
||||||
|
|||||||
@@ -103,6 +103,10 @@
|
|||||||
[[ sizeFormat(clientStats.down) ]]
|
[[ sizeFormat(clientStats.down) ]]
|
||||||
([[ sizeFormat(clientStats.up + clientStats.down) ]])
|
([[ sizeFormat(clientStats.up + clientStats.down) ]])
|
||||||
</a-tag>
|
</a-tag>
|
||||||
|
<a-tooltip>
|
||||||
|
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
|
||||||
|
<a-icon type="retweet" @click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)" v-if="client.email.length > 0"></a-icon>
|
||||||
|
</a-tooltip>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
{{define "form/streamSettings"}}
|
{{define "form/streamSettings"}}
|
||||||
<!-- select stream network -->
|
<!-- select stream network -->
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<table width="100%" class="ant-table-tbody">
|
<a-form-item label="{{ i18n "transmission" }}">
|
||||||
<tr>
|
<a-select v-model="inbound.stream.network" @change="streamNetworkChange"
|
||||||
<td>{{ i18n "transmission" }}</td>
|
:dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
|
||||||
<td>
|
<a-select-option value="tcp">tcp</a-select-option>
|
||||||
<a-form-item>
|
<a-select-option value="kcp">kcp</a-select-option>
|
||||||
<a-select v-model="inbound.stream.network" @change="streamNetworkChange"
|
<a-select-option value="ws">ws</a-select-option>
|
||||||
:dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
|
<a-select-option value="http">http</a-select-option>
|
||||||
<a-select-option value="tcp">tcp</a-select-option>
|
<a-select-option value="quic">quic</a-select-option>
|
||||||
<a-select-option value="kcp">kcp</a-select-option>
|
<a-select-option value="grpc">grpc</a-select-option>
|
||||||
<a-select-option value="ws">ws</a-select-option>
|
</a-select>
|
||||||
<a-select-option value="http">http</a-select-option>
|
</a-form-item>
|
||||||
<a-select-option value="quic">quic</a-select-option>
|
|
||||||
<a-select-option value="grpc">grpc</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|
||||||
<!-- tcp -->
|
<!-- tcp -->
|
||||||
|
|||||||
@@ -176,7 +176,6 @@
|
|||||||
<td>
|
<td>
|
||||||
<a-form-item >
|
<a-form-item >
|
||||||
<a-select v-model="inbound.stream.reality.settings.fingerprint" style="width: 250px">
|
<a-select v-model="inbound.stream.reality.settings.fingerprint" style="width: 250px">
|
||||||
<a-select-option value=''>None</a-select-option>
|
|
||||||
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td v-else-if="inbound.reality">
|
<td v-else-if="inbound.reality">
|
||||||
reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
|
reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br />
|
||||||
reality {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag>
|
reality Destination: <a-tag :color="inbound.stream.reality.dest ? 'green' : 'orange'">[[ inbound.stream.reality.dest ]]</a-tag>
|
||||||
</td>
|
</td>
|
||||||
<td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag>
|
<td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -66,13 +66,7 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, string, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
header = fmt.Sprintf("upload=%d;download=%d", traffic.Up, traffic.Down)
|
header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
|
||||||
if traffic.Total > 0 {
|
|
||||||
header = header + fmt.Sprintf(";total=%d", traffic.Total)
|
|
||||||
}
|
|
||||||
if traffic.ExpiryTime > 0 {
|
|
||||||
header = header + fmt.Sprintf(";expire=%d", traffic.ExpiryTime)
|
|
||||||
}
|
|
||||||
return result, header, nil
|
return result, header, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user