mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-03-19 17:15:49 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d03e049320 | ||
|
|
957d9e24fb | ||
|
|
865e47e9a6 | ||
|
|
607c5d3598 | ||
|
|
8879541999 | ||
|
|
0b896d9c31 | ||
|
|
6f4a2809e2 | ||
|
|
103a26edb6 |
@@ -20,10 +20,10 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
|||||||
|
|
||||||
## Install custom version
|
## Install custom version
|
||||||
|
|
||||||
To install your desired version you can add the version to the end of install command. Example for ver `v1.3.2`:
|
To install your desired version you can add the version to the end of install command. Example for ver `v1.3.3`:
|
||||||
|
|
||||||
```
|
```
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.3.2
|
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.3.3
|
||||||
```
|
```
|
||||||
|
|
||||||
# SSL
|
# SSL
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.3.2
|
1.3.3
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -9,8 +9,6 @@ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.8.7 h1:d3sry5vGgVq/OpgozRUNP6xBsSo0mtNdwliApw+SAMQ=
|
|
||||||
github.com/bytedance/sonic v1.8.7/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
|
||||||
github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q=
|
github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q=
|
||||||
github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package logger
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/op/go-logging"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/op/go-logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger *logging.Logger
|
var logger *logging.Logger
|
||||||
|
|||||||
@@ -28,20 +28,6 @@ const SSMethods = {
|
|||||||
BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305',
|
BLAKE3_CHACHA20_POLY1305: '2022-blake3-chacha20-poly1305',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RULE_IP = {
|
|
||||||
PRIVATE: 'geoip:private',
|
|
||||||
CN: 'geoip:cn',
|
|
||||||
};
|
|
||||||
|
|
||||||
const RULE_DOMAIN = {
|
|
||||||
ADS: 'geosite:category-ads',
|
|
||||||
ADS_ALL: 'geosite:category-ads-all',
|
|
||||||
CN: 'geosite:cn',
|
|
||||||
GOOGLE: 'geosite:google',
|
|
||||||
FACEBOOK: 'geosite:facebook',
|
|
||||||
SPEEDTEST: 'geosite:speedtest',
|
|
||||||
};
|
|
||||||
|
|
||||||
const XTLS_FLOW_CONTROL = {
|
const XTLS_FLOW_CONTROL = {
|
||||||
ORIGIN: "xtls-rprx-origin",
|
ORIGIN: "xtls-rprx-origin",
|
||||||
DIRECT: "xtls-rprx-direct",
|
DIRECT: "xtls-rprx-direct",
|
||||||
@@ -101,8 +87,6 @@ const ALPN_OPTION = {
|
|||||||
Object.freeze(Protocols);
|
Object.freeze(Protocols);
|
||||||
Object.freeze(VmessMethods);
|
Object.freeze(VmessMethods);
|
||||||
Object.freeze(SSMethods);
|
Object.freeze(SSMethods);
|
||||||
Object.freeze(RULE_IP);
|
|
||||||
Object.freeze(RULE_DOMAIN);
|
|
||||||
Object.freeze(XTLS_FLOW_CONTROL);
|
Object.freeze(XTLS_FLOW_CONTROL);
|
||||||
Object.freeze(TLS_FLOW_CONTROL);
|
Object.freeze(TLS_FLOW_CONTROL);
|
||||||
Object.freeze(TLS_VERSION_OPTION);
|
Object.freeze(TLS_VERSION_OPTION);
|
||||||
@@ -456,18 +440,26 @@ class QuicStreamSettings extends XrayCommonClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GrpcStreamSettings extends XrayCommonClass {
|
class GrpcStreamSettings extends XrayCommonClass {
|
||||||
constructor(serviceName="") {
|
constructor(
|
||||||
|
serviceName="",
|
||||||
|
multiMode=false
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this.serviceName = serviceName;
|
this.serviceName = serviceName;
|
||||||
|
this.multiMode = multiMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json={}) {
|
static fromJson(json={}) {
|
||||||
return new GrpcStreamSettings(json.serviceName);
|
return new GrpcStreamSettings(
|
||||||
|
json.serviceName,
|
||||||
|
json.multiMode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson() {
|
toJson() {
|
||||||
return {
|
return {
|
||||||
serviceName: this.serviceName,
|
serviceName: this.serviceName,
|
||||||
|
multiMode: this.multiMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1160,6 +1152,7 @@ class Inbound extends XrayCommonClass {
|
|||||||
case Protocols.VMESS:
|
case Protocols.VMESS:
|
||||||
case Protocols.VLESS:
|
case Protocols.VLESS:
|
||||||
case Protocols.TROJAN:
|
case Protocols.TROJAN:
|
||||||
|
case Protocols.SHADOWSOCKS:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -1261,50 +1254,6 @@ class Inbound extends XrayCommonClass {
|
|||||||
if (this.protocol !== Protocols.VMESS) {
|
if (this.protocol !== Protocols.VMESS) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
let network = this.stream.network;
|
|
||||||
let type = 'none';
|
|
||||||
let host = '';
|
|
||||||
let path = '';
|
|
||||||
if (network === 'tcp') {
|
|
||||||
let tcp = this.stream.tcp;
|
|
||||||
type = tcp.type;
|
|
||||||
if (type === 'http') {
|
|
||||||
let request = tcp.request;
|
|
||||||
path = request.path.join(',');
|
|
||||||
let index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
|
||||||
if (index >= 0) {
|
|
||||||
host = request.headers[index].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (network === 'kcp') {
|
|
||||||
let kcp = this.stream.kcp;
|
|
||||||
type = kcp.type;
|
|
||||||
path = kcp.seed;
|
|
||||||
} else if (network === 'ws') {
|
|
||||||
let ws = this.stream.ws;
|
|
||||||
path = ws.path;
|
|
||||||
let index = ws.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
|
||||||
if (index >= 0) {
|
|
||||||
host = ws.headers[index].value;
|
|
||||||
}
|
|
||||||
} else if (network === 'http') {
|
|
||||||
network = 'h2';
|
|
||||||
path = this.stream.http.path;
|
|
||||||
host = this.stream.http.host.join(',');
|
|
||||||
} else if (network === 'quic') {
|
|
||||||
type = this.stream.quic.type;
|
|
||||||
host = this.stream.quic.security;
|
|
||||||
path = this.stream.quic.key;
|
|
||||||
} else if (network === 'grpc') {
|
|
||||||
path = this.stream.grpc.serviceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.stream.security === 'tls') {
|
|
||||||
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
|
||||||
address = this.stream.tls.server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let obj = {
|
let obj = {
|
||||||
v: '2',
|
v: '2',
|
||||||
ps: remark,
|
ps: remark,
|
||||||
@@ -1312,16 +1261,66 @@ class Inbound extends XrayCommonClass {
|
|||||||
port: this.port,
|
port: this.port,
|
||||||
id: this.settings.vmesses[clientIndex].id,
|
id: this.settings.vmesses[clientIndex].id,
|
||||||
aid: this.settings.vmesses[clientIndex].alterId,
|
aid: this.settings.vmesses[clientIndex].alterId,
|
||||||
net: network,
|
net: this.stream.network,
|
||||||
type: type,
|
type: 'none',
|
||||||
host: host,
|
|
||||||
path: path,
|
|
||||||
tls: this.stream.security,
|
tls: this.stream.security,
|
||||||
sni: this.stream.tls.settings.serverName,
|
|
||||||
fp: this.stream.tls.settings.fingerprint,
|
|
||||||
alpn: this.stream.tls.alpn.join(','),
|
|
||||||
allowInsecure: this.stream.tls.settings.allowInsecure,
|
|
||||||
};
|
};
|
||||||
|
let network = this.stream.network;
|
||||||
|
if (network === 'tcp') {
|
||||||
|
let tcp = this.stream.tcp;
|
||||||
|
obj.type = tcp.type;
|
||||||
|
if (tcp.type === 'http') {
|
||||||
|
let request = tcp.request;
|
||||||
|
obj.path = request.path.join(',');
|
||||||
|
let index = request.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
||||||
|
if (index >= 0) {
|
||||||
|
obj.host = request.headers[index].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (network === 'kcp') {
|
||||||
|
let kcp = this.stream.kcp;
|
||||||
|
obj.type = kcp.type;
|
||||||
|
obj.path = kcp.seed;
|
||||||
|
} else if (network === 'ws') {
|
||||||
|
let ws = this.stream.ws;
|
||||||
|
obj.path = ws.path;
|
||||||
|
let index = ws.headers.findIndex(header => header.name.toLowerCase() === 'host');
|
||||||
|
if (index >= 0) {
|
||||||
|
obj.host = ws.headers[index].value;
|
||||||
|
}
|
||||||
|
} else if (network === 'http') {
|
||||||
|
obj.net = 'h2';
|
||||||
|
obj.path = this.stream.http.path;
|
||||||
|
obj.host = this.stream.http.host.join(',');
|
||||||
|
} else if (network === 'quic') {
|
||||||
|
obj.type = this.stream.quic.type;
|
||||||
|
obj.host = this.stream.quic.security;
|
||||||
|
obj.path = this.stream.quic.key;
|
||||||
|
} else if (network === 'grpc') {
|
||||||
|
obj.path = this.stream.grpc.serviceName;
|
||||||
|
if (this.stream.grpc.multiMode){
|
||||||
|
obj.type = 'multi'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stream.security === 'tls') {
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
|
||||||
|
obj.add = this.stream.tls.server;
|
||||||
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.settings.serverName)){
|
||||||
|
obj.sni = this.stream.tls.settings.serverName;
|
||||||
|
}
|
||||||
|
if (!ObjectUtil.isEmpty(this.stream.tls.settings.fingerprint)){
|
||||||
|
obj.fp = this.stream.tls.settings.fingerprint;
|
||||||
|
}
|
||||||
|
if (this.stream.tls.alpn.length>0){
|
||||||
|
obj.alpn = this.stream.tls.alpn.join(',');
|
||||||
|
}
|
||||||
|
if (this.stream.tls.settings.allowInsecure){
|
||||||
|
obj.allowInsecure = this.stream.tls.settings.allowInsecure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
|
return 'vmess://' + base64(JSON.stringify(obj, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1374,6 +1373,9 @@ class Inbound extends XrayCommonClass {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
const grpc = this.stream.grpc;
|
const grpc = this.stream.grpc;
|
||||||
params.set("serviceName", grpc.serviceName);
|
params.set("serviceName", grpc.serviceName);
|
||||||
|
if(grpc.multiMode){
|
||||||
|
params.set("mode", "multi");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1491,6 +1493,9 @@ class Inbound extends XrayCommonClass {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
const grpc = this.stream.grpc;
|
const grpc = this.stream.grpc;
|
||||||
params.set("serviceName", grpc.serviceName);
|
params.set("serviceName", grpc.serviceName);
|
||||||
|
if(grpc.multiMode){
|
||||||
|
params.set("mode", "multi");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package global
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var webServer WebServer
|
var webServer WebServer
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
const siderDrawer = {
|
const siderDrawer = {
|
||||||
visible: false,
|
visible: false,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
isDarkTheme: localStorage.getItem("dark-mode") === 'true' ? true : false,
|
isDarkTheme: localStorage.getItem("dark-mode") === 'false' ? false : true,
|
||||||
show() {
|
show() {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,5 +3,8 @@
|
|||||||
<a-form-item label="ServiceName">
|
<a-form-item label="ServiceName">
|
||||||
<a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
|
<a-input v-model.trim="inbound.stream.grpc.serviceName"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="Multi Mode">
|
||||||
|
<a-switch v-model="inbound.stream.grpc.multiMode"></a-switch>
|
||||||
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
<template v-if="inbound.isGrpc">
|
<template v-if="inbound.isGrpc">
|
||||||
<tr><td>grpc serviceName</td><td><a-tag color="green">[[ inbound.serviceName ]]</a-tag></td></tr>
|
<tr><td>grpc serviceName</td><td><a-tag color="green">[[ inbound.serviceName ]]</a-tag></td></tr>
|
||||||
|
<tr><td>grpc multiMode</td><td><a-tag color="green">[[ inbound.stream.grpc.multiMode ]]</a-tag></td></tr>
|
||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
|||||||
@@ -4,23 +4,22 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
ss "strings"
|
|
||||||
"x-ui/database"
|
"x-ui/database"
|
||||||
"x-ui/database/model"
|
"x-ui/database/model"
|
||||||
"x-ui/logger"
|
"x-ui/logger"
|
||||||
"x-ui/web/service"
|
"x-ui/web/service"
|
||||||
"x-ui/xray"
|
"x-ui/xray"
|
||||||
// "strconv"
|
|
||||||
"github.com/go-cmd/cmd"
|
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-cmd/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CheckClientIpJob struct {
|
type CheckClientIpJob struct {
|
||||||
xrayService service.XrayService
|
xrayService service.XrayService
|
||||||
inboundService service.InboundService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var job *CheckClientIpJob
|
var job *CheckClientIpJob
|
||||||
@@ -36,7 +35,7 @@ func (j *CheckClientIpJob) Run() {
|
|||||||
processLogFile()
|
processLogFile()
|
||||||
|
|
||||||
// disAllowedIps = []string{"192.168.1.183","192.168.1.197"}
|
// disAllowedIps = []string{"192.168.1.183","192.168.1.197"}
|
||||||
blockedIps := []byte(ss.Join(disAllowedIps, ","))
|
blockedIps := []byte(strings.Join(disAllowedIps, ","))
|
||||||
err := os.WriteFile(xray.GetBlockedIPsPath(), blockedIps, 0755)
|
err := os.WriteFile(xray.GetBlockedIPsPath(), blockedIps, 0755)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ func processLogFile() {
|
|||||||
checkError(err)
|
checkError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := ss.Split(string(data), "\n")
|
lines := strings.Split(string(data), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`)
|
ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`)
|
||||||
emailRegx, _ := regexp.Compile(`email:.+`)
|
emailRegx, _ := regexp.Compile(`email:.+`)
|
||||||
@@ -74,7 +73,7 @@ func processLogFile() {
|
|||||||
if matchesEmail == "" {
|
if matchesEmail == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
matchesEmail = ss.Split(matchesEmail, "email: ")[1]
|
matchesEmail = strings.Split(matchesEmail, "email: ")[1]
|
||||||
|
|
||||||
if InboundClientIps[matchesEmail] != nil {
|
if InboundClientIps[matchesEmail] != nil {
|
||||||
if contains(InboundClientIps[matchesEmail], ip) {
|
if contains(InboundClientIps[matchesEmail], ip) {
|
||||||
@@ -92,14 +91,12 @@ func processLogFile() {
|
|||||||
|
|
||||||
for clientEmail, ips := range InboundClientIps {
|
for clientEmail, ips := range InboundClientIps {
|
||||||
inboundClientIps, err := GetInboundClientIps(clientEmail)
|
inboundClientIps, err := GetInboundClientIps(clientEmail)
|
||||||
sort.Sort(sort.StringSlice(ips))
|
sort.Strings(ips)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addInboundClientIps(clientEmail, ips)
|
addInboundClientIps(clientEmail, ips)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
updateInboundClientIps(inboundClientIps, clientEmail, ips)
|
updateInboundClientIps(inboundClientIps, clientEmail, ips)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if inbound connection is more than limited ip and drop connection
|
// check if inbound connection is more than limited ip and drop connection
|
||||||
@@ -202,6 +199,8 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|||||||
json.Unmarshal([]byte(inbound.Settings), &settings)
|
json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||||
clients := settings["clients"]
|
clients := settings["clients"]
|
||||||
|
|
||||||
|
var disAllowedIps []string // initialize the slice
|
||||||
|
|
||||||
for _, client := range clients {
|
for _, client := range clients {
|
||||||
if client.Email == clientEmail {
|
if client.Email == clientEmail {
|
||||||
|
|
||||||
@@ -214,7 +213,7 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.Debug("disAllowedIps ", disAllowedIps)
|
logger.Debug("disAllowedIps ", disAllowedIps)
|
||||||
sort.Sort(sort.StringSlice(disAllowedIps))
|
sort.Strings(disAllowedIps)
|
||||||
|
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
err = db.Save(inboundClientIps).Error
|
err = db.Save(inboundClientIps).Error
|
||||||
@@ -223,6 +222,7 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DisableInbound(id int) error {
|
func DisableInbound(id int) error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
result := db.Model(model.Inbound{}).
|
result := db.Model(model.Inbound{}).
|
||||||
|
|||||||
@@ -912,6 +912,8 @@ func (s *InboundService) SearchInbounds(query string) ([]*model.Inbound, error)
|
|||||||
|
|
||||||
func (s *InboundService) MigrationRequirements() {
|
func (s *InboundService) MigrationRequirements() {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
|
||||||
|
// Fix inbounds based problems
|
||||||
var inbounds []*model.Inbound
|
var inbounds []*model.Inbound
|
||||||
err := db.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error
|
err := db.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error
|
||||||
if err != nil && err != gorm.ErrRecordNotFound {
|
if err != nil && err != gorm.ErrRecordNotFound {
|
||||||
@@ -922,6 +924,7 @@ func (s *InboundService) MigrationRequirements() {
|
|||||||
json.Unmarshal([]byte(inbounds[inbound_index].Settings), &settings)
|
json.Unmarshal([]byte(inbounds[inbound_index].Settings), &settings)
|
||||||
clients, ok := settings["clients"].([]interface{})
|
clients, ok := settings["clients"].([]interface{})
|
||||||
if ok {
|
if ok {
|
||||||
|
// Fix Clinet configuration problems
|
||||||
var newClients []interface{}
|
var newClients []interface{}
|
||||||
for client_index := range clients {
|
for client_index := range clients {
|
||||||
c := clients[client_index].(map[string]interface{})
|
c := clients[client_index].(map[string]interface{})
|
||||||
@@ -947,6 +950,7 @@ func (s *InboundService) MigrationRequirements() {
|
|||||||
|
|
||||||
inbounds[inbound_index].Settings = string(modifiedSettings)
|
inbounds[inbound_index].Settings = string(modifiedSettings)
|
||||||
}
|
}
|
||||||
|
// Add client traffic row for all clients which has email
|
||||||
modelClients, err := s.getClients(inbounds[inbound_index])
|
modelClients, err := s.getClients(inbounds[inbound_index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -962,4 +966,7 @@ func (s *InboundService) MigrationRequirements() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.Save(inbounds)
|
db.Save(inbounds)
|
||||||
|
|
||||||
|
// Remove orphaned traffics
|
||||||
|
db.Where("inbound_id = 0").Delete(xray.ClientTraffic{})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,80 +102,89 @@ func (s *SubService) getLink(inbound *model.Inbound, email string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
||||||
address := s.address
|
|
||||||
if inbound.Protocol != model.VMess {
|
if inbound.Protocol != model.VMess {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
obj := map[string]interface{}{
|
||||||
|
"v": "2",
|
||||||
|
"ps": email,
|
||||||
|
"add": s.address,
|
||||||
|
"port": inbound.Port,
|
||||||
|
"type": "none",
|
||||||
|
}
|
||||||
var stream map[string]interface{}
|
var stream map[string]interface{}
|
||||||
json.Unmarshal([]byte(inbound.StreamSettings), &stream)
|
json.Unmarshal([]byte(inbound.StreamSettings), &stream)
|
||||||
network, _ := stream["network"].(string)
|
network, _ := stream["network"].(string)
|
||||||
typeStr := "none"
|
obj["net"] = network
|
||||||
host := ""
|
|
||||||
path := ""
|
|
||||||
sni := ""
|
|
||||||
fp := ""
|
|
||||||
var alpn []string
|
|
||||||
allowInsecure := false
|
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
tcp, _ := stream["tcpSettings"].(map[string]interface{})
|
tcp, _ := stream["tcpSettings"].(map[string]interface{})
|
||||||
header, _ := tcp["header"].(map[string]interface{})
|
header, _ := tcp["header"].(map[string]interface{})
|
||||||
typeStr, _ = header["type"].(string)
|
typeStr, _ := header["type"].(string)
|
||||||
|
obj["type"] = typeStr
|
||||||
if typeStr == "http" {
|
if typeStr == "http" {
|
||||||
request := header["request"].(map[string]interface{})
|
request := header["request"].(map[string]interface{})
|
||||||
requestPath, _ := request["path"].([]interface{})
|
requestPath, _ := request["path"].([]interface{})
|
||||||
path = requestPath[0].(string)
|
obj["path"] = requestPath[0].(string)
|
||||||
headers, _ := request["headers"].(map[string]interface{})
|
headers, _ := request["headers"].(map[string]interface{})
|
||||||
host = searchHost(headers)
|
obj["host"] = searchHost(headers)
|
||||||
}
|
}
|
||||||
case "kcp":
|
case "kcp":
|
||||||
kcp, _ := stream["kcpSettings"].(map[string]interface{})
|
kcp, _ := stream["kcpSettings"].(map[string]interface{})
|
||||||
header, _ := kcp["header"].(map[string]interface{})
|
header, _ := kcp["header"].(map[string]interface{})
|
||||||
typeStr, _ = header["type"].(string)
|
obj["type"], _ = header["type"].(string)
|
||||||
path, _ = kcp["seed"].(string)
|
obj["path"], _ = kcp["seed"].(string)
|
||||||
case "ws":
|
case "ws":
|
||||||
ws, _ := stream["wsSettings"].(map[string]interface{})
|
ws, _ := stream["wsSettings"].(map[string]interface{})
|
||||||
path = ws["path"].(string)
|
obj["path"] = ws["path"].(string)
|
||||||
headers, _ := ws["headers"].(map[string]interface{})
|
headers, _ := ws["headers"].(map[string]interface{})
|
||||||
host = searchHost(headers)
|
obj["host"] = searchHost(headers)
|
||||||
case "http":
|
case "http":
|
||||||
network = "h2"
|
obj["net"] = "h2"
|
||||||
http, _ := stream["httpSettings"].(map[string]interface{})
|
http, _ := stream["httpSettings"].(map[string]interface{})
|
||||||
path, _ = http["path"].(string)
|
obj["path"], _ = http["path"].(string)
|
||||||
host = searchHost(http)
|
obj["host"] = searchHost(http)
|
||||||
case "quic":
|
case "quic":
|
||||||
quic, _ := stream["quicSettings"].(map[string]interface{})
|
quic, _ := stream["quicSettings"].(map[string]interface{})
|
||||||
header := quic["header"].(map[string]interface{})
|
header := quic["header"].(map[string]interface{})
|
||||||
typeStr, _ = header["type"].(string)
|
obj["type"], _ = header["type"].(string)
|
||||||
host, _ = quic["security"].(string)
|
obj["host"], _ = quic["security"].(string)
|
||||||
path, _ = quic["key"].(string)
|
obj["path"], _ = quic["key"].(string)
|
||||||
case "grpc":
|
case "grpc":
|
||||||
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
||||||
path = grpc["serviceName"].(string)
|
obj["path"] = grpc["serviceName"].(string)
|
||||||
|
if grpc["multiMode"].(bool) {
|
||||||
|
obj["type"] = "multi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
security, _ := stream["security"].(string)
|
security, _ := stream["security"].(string)
|
||||||
|
obj["tls"] = security
|
||||||
if security == "tls" {
|
if security == "tls" {
|
||||||
tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
|
tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
|
||||||
alpns, _ := tlsSetting["alpn"].([]interface{})
|
alpns, _ := tlsSetting["alpn"].([]interface{})
|
||||||
for _, a := range alpns {
|
if len(alpns) > 0 {
|
||||||
alpn = append(alpn, a.(string))
|
var alpn []string
|
||||||
|
for _, a := range alpns {
|
||||||
|
alpn = append(alpn, a.(string))
|
||||||
|
}
|
||||||
|
obj["alpn"] = strings.Join(alpn, ",")
|
||||||
}
|
}
|
||||||
tlsSettings, _ := searchKey(tlsSetting, "settings")
|
tlsSettings, _ := searchKey(tlsSetting, "settings")
|
||||||
if tlsSetting != nil {
|
if tlsSetting != nil {
|
||||||
if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
|
if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
|
||||||
sni, _ = sniValue.(string)
|
obj["sni"], _ = sniValue.(string)
|
||||||
}
|
}
|
||||||
if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
|
if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
|
||||||
fp, _ = fpValue.(string)
|
obj["fp"], _ = fpValue.(string)
|
||||||
}
|
}
|
||||||
if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
|
if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
|
||||||
allowInsecure, _ = insecure.(bool)
|
obj["allowInsecure"], _ = insecure.(bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverName, _ := tlsSetting["serverName"].(string)
|
serverName, _ := tlsSetting["serverName"].(string)
|
||||||
if serverName != "" {
|
if serverName != "" {
|
||||||
address = serverName
|
obj["add"] = serverName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,24 +196,9 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
obj["id"] = clients[clientIndex].ID
|
||||||
|
obj["aid"] = clients[clientIndex].AlterIds
|
||||||
|
|
||||||
obj := map[string]interface{}{
|
|
||||||
"v": "2",
|
|
||||||
"ps": email,
|
|
||||||
"add": address,
|
|
||||||
"port": inbound.Port,
|
|
||||||
"id": clients[clientIndex].ID,
|
|
||||||
"aid": clients[clientIndex].AlterIds,
|
|
||||||
"net": network,
|
|
||||||
"type": typeStr,
|
|
||||||
"host": host,
|
|
||||||
"path": path,
|
|
||||||
"tls": security,
|
|
||||||
"sni": sni,
|
|
||||||
"fp": fp,
|
|
||||||
"alpn": strings.Join(alpn, ","),
|
|
||||||
"allowInsecure": allowInsecure,
|
|
||||||
}
|
|
||||||
jsonStr, _ := json.MarshalIndent(obj, "", " ")
|
jsonStr, _ := json.MarshalIndent(obj, "", " ")
|
||||||
return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
|
return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
|
||||||
}
|
}
|
||||||
@@ -266,6 +260,9 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
||||||
params["serviceName"] = grpc["serviceName"].(string)
|
params["serviceName"] = grpc["serviceName"].(string)
|
||||||
|
if grpc["multiMode"].(bool) {
|
||||||
|
params["mode"] = "multi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
security, _ := stream["security"].(string)
|
security, _ := stream["security"].(string)
|
||||||
@@ -444,6 +441,9 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
grpc, _ := stream["grpcSettings"].(map[string]interface{})
|
||||||
params["serviceName"] = grpc["serviceName"].(string)
|
params["serviceName"] = grpc["serviceName"].(string)
|
||||||
|
if grpc["multiMode"].(bool) {
|
||||||
|
params["mode"] = "multi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
security, _ := stream["security"].(string)
|
security, _ := stream["security"].(string)
|
||||||
|
|||||||
Reference in New Issue
Block a user