3 Commits fe9f0d1d0e ... c2d6dd923f

Author SHA1 Message Date
  Sanaei c2d6dd923f windows workflow (#3439) 20 hours ago
  mhsanaei 723ec25fb2 renamed dest to target 1 day ago
  mhsanaei 7dc52e9a53 dokodemo-door, socks renamed to mixed, tunnel 1 day ago

+ 76 - 0
.github/workflows/release.yml

@@ -146,3 +146,79 @@ jobs:
           asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
           overwrite: true
           prerelease: true
+
+  # =================================
+  #  Windows Build
+  # =================================
+  build-windows:
+    name: Build for Windows
+    permissions:
+      contents: write
+    strategy:
+      matrix:
+        platform:
+          - amd64
+    runs-on: windows-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v5
+
+      - name: Setup Go
+        uses: actions/setup-go@v6
+        with:
+          go-version-file: go.mod
+          check-latest: true
+
+      - name: Build 3X-UI for Windows
+        shell: pwsh
+        run: |
+          $env:CGO_ENABLED="1"
+          $env:GOOS="windows"
+          $env:GOARCH="amd64"
+          go build -ldflags "-w -s" -o xui-release.exe -v main.go
+          
+          mkdir x-ui
+          Copy-Item xui-release.exe x-ui\
+          mkdir x-ui\bin
+          cd x-ui\bin
+          
+          # Download Xray for Windows
+          $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v25.6.8/"
+          Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip"
+          Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath .
+          Remove-Item "Xray-windows-64.zip"
+          Remove-Item geoip.dat, geosite.dat -ErrorAction SilentlyContinue
+          Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip.dat"
+          Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite.dat"
+          Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat" -OutFile "geoip_IR.dat"
+          Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat" -OutFile "geosite_IR.dat"
+          Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip_RU.dat"
+          Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite_RU.dat"
+          Rename-Item xray.exe xray-windows-amd64.exe
+          cd ..
+          Copy-Item -Path ..\windows_files\* -Destination . -Recurse
+          cd ..
+
+      - name: Package to Zip
+        shell: pwsh
+        run: |
+          Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip"
+
+      - name: Upload files to Artifacts
+        uses: actions/upload-artifact@v4
+        with:
+          name: x-ui-windows-amd64
+          path: ./x-ui-windows-amd64.zip
+
+      - name: Upload files to GH release
+        uses: svenstaro/upload-release-action@v2
+        if: |
+          (github.event_name == 'release' && github.event.action == 'published') ||
+          (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
+        with:
+          repo_token: ${{ secrets.GITHUB_TOKEN }}
+          tag: ${{ github.ref }}
+          file: x-ui-windows-amd64.zip
+          asset_name: x-ui-windows-amd64.zip
+          overwrite: true
+          prerelease: true

+ 2 - 2
database/model/model.go

@@ -12,11 +12,11 @@ type Protocol string
 const (
 	VMESS       Protocol = "vmess"
 	VLESS       Protocol = "vless"
-	DOKODEMO    Protocol = "dokodemo-door"
+	Tunnel      Protocol = "tunnel"
 	HTTP        Protocol = "http"
 	Trojan      Protocol = "trojan"
 	Shadowsocks Protocol = "shadowsocks"
-	Socks       Protocol = "socks"
+	Mixed       Protocol = "mixed"
 	WireGuard   Protocol = "wireguard"
 )
 

+ 2 - 2
sub/default.json

@@ -13,7 +13,7 @@
   "inbounds": [
     {
       "port": 10808,
-      "protocol": "socks",
+      "protocol": "mixed",
       "settings": {
         "auth": "noauth",
         "udp": true,
@@ -28,7 +28,7 @@
         ],
         "enabled": true
       },
-      "tag": "socks"
+      "tag": "mixed"
     },
     {
       "port": 10809,

+ 2 - 2
web/assets/js/model/dbinbound.js

@@ -49,8 +49,8 @@ class DBInbound {
         return this.protocol === Protocols.SHADOWSOCKS;
     }
 
-    get isSocks() {
-        return this.protocol === Protocols.SOCKS;
+    get isMixed() {
+        return this.protocol === Protocols.MIXED;
     }
 
     get isHTTP() {

+ 20 - 20
web/assets/js/model/inbound.js

@@ -3,8 +3,8 @@ const Protocols = {
     VLESS: 'vless',
     TROJAN: 'trojan',
     SHADOWSOCKS: 'shadowsocks',
-    DOKODEMO: 'dokodemo-door',
-    SOCKS: 'socks',
+    TUNNEL: 'tunnel',
+    MIXED: 'mixed',
     HTTP: 'http',
     WIREGUARD: 'wireguard',
 };
@@ -729,7 +729,7 @@ class RealityStreamSettings extends XrayCommonClass {
     constructor(
         show = false,
         xver = 0,
-        dest = 'google.com:443',
+        target = 'google.com:443',
         serverNames = 'google.com,www.google.com',
         privateKey = '',
         minClientVer = '',
@@ -742,7 +742,7 @@ class RealityStreamSettings extends XrayCommonClass {
         super();
         this.show = show;
         this.xver = xver;
-        this.dest = dest;
+        this.target = target;
         this.serverNames = Array.isArray(serverNames) ? serverNames.join(",") : serverNames;
         this.privateKey = privateKey;
         this.minClientVer = minClientVer;
@@ -767,7 +767,7 @@ class RealityStreamSettings extends XrayCommonClass {
         return new RealityStreamSettings(
             json.show,
             json.xver,
-            json.dest,
+            json.target,
             json.serverNames,
             json.privateKey,
             json.minClientVer,
@@ -783,7 +783,7 @@ class RealityStreamSettings extends XrayCommonClass {
         return {
             show: this.show,
             xver: this.xver,
-            dest: this.dest,
+            target: this.target,
             serverNames: this.serverNames.split(","),
             privateKey: this.privateKey,
             minClientVer: this.minClientVer,
@@ -1712,8 +1712,8 @@ Inbound.Settings = class extends XrayCommonClass {
             case Protocols.VLESS: return new Inbound.VLESSSettings(protocol);
             case Protocols.TROJAN: return new Inbound.TrojanSettings(protocol);
             case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings(protocol);
-            case Protocols.DOKODEMO: return new Inbound.DokodemoSettings(protocol);
-            case Protocols.SOCKS: return new Inbound.SocksSettings(protocol);
+            case Protocols.TUNNEL: return new Inbound.TunnelSettings(protocol);
+            case Protocols.MIXED: return new Inbound.MixedSettings(protocol);
             case Protocols.HTTP: return new Inbound.HttpSettings(protocol);
             case Protocols.WIREGUARD: return new Inbound.WireguardSettings(protocol);
             default: return null;
@@ -1726,8 +1726,8 @@ Inbound.Settings = class extends XrayCommonClass {
             case Protocols.VLESS: return Inbound.VLESSSettings.fromJson(json);
             case Protocols.TROJAN: return Inbound.TrojanSettings.fromJson(json);
             case Protocols.SHADOWSOCKS: return Inbound.ShadowsocksSettings.fromJson(json);
-            case Protocols.DOKODEMO: return Inbound.DokodemoSettings.fromJson(json);
-            case Protocols.SOCKS: return Inbound.SocksSettings.fromJson(json);
+            case Protocols.TUNNEL: return Inbound.TunnelSettings.fromJson(json);
+            case Protocols.MIXED: return Inbound.MixedSettings.fromJson(json);
             case Protocols.HTTP: return Inbound.HttpSettings.fromJson(json);
             case Protocols.WIREGUARD: return Inbound.WireguardSettings.fromJson(json);
             default: return null;
@@ -2327,7 +2327,7 @@ Inbound.ShadowsocksSettings.Shadowsocks = class extends XrayCommonClass {
 
 };
 
-Inbound.DokodemoSettings = class extends Inbound.Settings {
+Inbound.TunnelSettings = class extends Inbound.Settings {
     constructor(
         protocol,
         address,
@@ -2345,8 +2345,8 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
     }
 
     static fromJson(json = {}) {
-        return new Inbound.DokodemoSettings(
-            Protocols.DOKODEMO,
+        return new Inbound.TunnelSettings(
+            Protocols.TUNNEL,
             json.address,
             json.port,
             XrayCommonClass.toHeaders(json.portMap),
@@ -2366,8 +2366,8 @@ Inbound.DokodemoSettings = class extends Inbound.Settings {
     }
 };
 
-Inbound.SocksSettings = class extends Inbound.Settings {
-    constructor(protocol, auth = 'password', accounts = [new Inbound.SocksSettings.SocksAccount()], udp = false, ip = '127.0.0.1') {
+Inbound.MixedSettings = class extends Inbound.Settings {
+    constructor(protocol, auth = 'password', accounts = [new Inbound.MixedSettings.SocksAccount()], udp = false, ip = '127.0.0.1') {
         super(protocol);
         this.auth = auth;
         this.accounts = accounts;
@@ -2387,11 +2387,11 @@ Inbound.SocksSettings = class extends Inbound.Settings {
         let accounts;
         if (json.auth === 'password') {
             accounts = json.accounts.map(
-                account => Inbound.SocksSettings.SocksAccount.fromJson(account)
+                account => Inbound.MixedSettings.SocksAccount.fromJson(account)
             )
         }
-        return new Inbound.SocksSettings(
-            Protocols.SOCKS,
+        return new Inbound.MixedSettings(
+            Protocols.MIXED,
             json.auth,
             accounts,
             json.udp,
@@ -2408,7 +2408,7 @@ Inbound.SocksSettings = class extends Inbound.Settings {
         };
     }
 };
-Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass {
+Inbound.MixedSettings.SocksAccount = class extends XrayCommonClass {
     constructor(user = RandomUtil.randomSeq(10), pass = RandomUtil.randomSeq(10)) {
         super();
         this.user = user;
@@ -2416,7 +2416,7 @@ Inbound.SocksSettings.SocksAccount = class extends XrayCommonClass {
     }
 
     static fromJson(json = {}) {
-        return new Inbound.SocksSettings.SocksAccount(json.user, json.pass);
+        return new Inbound.MixedSettings.SocksAccount(json.user, json.pass);
     }
 };
 

+ 9 - 9
web/assets/js/model/outbound.js

@@ -6,7 +6,7 @@ const Protocols = {
     VLESS: "vless",
     Trojan: "trojan",
     Shadowsocks: "shadowsocks",
-    Socks: "socks",
+    Mixed: "mixed",
     HTTP: "http",
     Wireguard: "wireguard"
 };
@@ -643,7 +643,7 @@ class Outbound extends CommonClass {
             Protocols.Trojan,
             Protocols.Shadowsocks,
             Protocols.HTTP,
-            Protocols.Socks
+            Protocols.Mixed
         ].includes(this.protocol);
     }
 
@@ -652,7 +652,7 @@ class Outbound extends CommonClass {
     }
 
     hasServers() {
-        return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Socks, Protocols.HTTP].includes(this.protocol);
+        return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Mixed, Protocols.HTTP].includes(this.protocol);
     }
 
     hasAddressPort() {
@@ -662,13 +662,13 @@ class Outbound extends CommonClass {
             Protocols.VLESS,
             Protocols.Trojan,
             Protocols.Shadowsocks,
-            Protocols.Socks,
+            Protocols.Mixed,
             Protocols.HTTP
         ].includes(this.protocol);
     }
 
     hasUsername() {
-        return [Protocols.Socks, Protocols.HTTP].includes(this.protocol);
+        return [Protocols.Mixed, Protocols.HTTP].includes(this.protocol);
     }
 
     static fromJson(json = {}) {
@@ -847,7 +847,7 @@ Outbound.Settings = class extends CommonClass {
             case Protocols.VLESS: return new Outbound.VLESSSettings();
             case Protocols.Trojan: return new Outbound.TrojanSettings();
             case Protocols.Shadowsocks: return new Outbound.ShadowsocksSettings();
-            case Protocols.Socks: return new Outbound.SocksSettings();
+            case Protocols.Mixed: return new Outbound.MixedSettings();
             case Protocols.HTTP: return new Outbound.HttpSettings();
             case Protocols.Wireguard: return new Outbound.WireguardSettings();
             default: return null;
@@ -863,7 +863,7 @@ Outbound.Settings = class extends CommonClass {
             case Protocols.VLESS: return Outbound.VLESSSettings.fromJson(json);
             case Protocols.Trojan: return Outbound.TrojanSettings.fromJson(json);
             case Protocols.Shadowsocks: return Outbound.ShadowsocksSettings.fromJson(json);
-            case Protocols.Socks: return Outbound.SocksSettings.fromJson(json);
+            case Protocols.Mixed: return Outbound.MixedSettings.fromJson(json);
             case Protocols.HTTP: return Outbound.HttpSettings.fromJson(json);
             case Protocols.Wireguard: return Outbound.WireguardSettings.fromJson(json);
             default: return null;
@@ -1141,7 +1141,7 @@ Outbound.ShadowsocksSettings = class extends CommonClass {
     }
 };
 
-Outbound.SocksSettings = class extends CommonClass {
+Outbound.MixedSettings = class extends CommonClass {
     constructor(address, port, user, pass) {
         super();
         this.address = address;
@@ -1153,7 +1153,7 @@ Outbound.SocksSettings = class extends CommonClass {
     static fromJson(json = {}) {
         let servers = json.servers;
         if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }];
-        return new Outbound.SocksSettings(
+        return new Outbound.MixedSettings(
             servers[0].address,
             servers[0].port,
             ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user,

+ 6 - 6
web/html/form/inbound.html

@@ -83,14 +83,14 @@
     {{template "form/shadowsocks"}}
 </template>
 
-<!-- dokodemo-door -->
-<template v-if="inbound.protocol === Protocols.DOKODEMO">
-    {{template "form/dokodemo"}}
+<!-- tunnel -->
+<template v-if="inbound.protocol === Protocols.TUNNEL">
+    {{template "form/tunnel"}}
 </template>
 
-<!-- socks -->
-<template v-if="inbound.protocol === Protocols.SOCKS">
-    {{template "form/socks"}}
+<!-- mixed -->
+<template v-if="inbound.protocol === Protocols.MIXED">
+    {{template "form/mixed"}}
 </template>
 
 <!-- http -->

+ 2 - 2
web/html/form/outbound.html

@@ -241,9 +241,9 @@
         </template>
       </template>
 
-      <!-- Servers (trojan/shadowsocks/socks/http) settings -->
+      <!-- Servers (trojan/shadowsocks/mixed/http) settings -->
       <template v-if="outbound.hasServers()">
-        <!-- http / socks -->
+        <!-- http / mixed -->
         <template v-if="outbound.hasUsername()">
           <a-form-item label='{{ i18n "username" }}'>
             <a-input v-model.trim="outbound.settings.user"></a-input>

+ 1 - 1
web/html/form/protocol/dokodemo.html

@@ -1,4 +1,4 @@
-{{define "form/dokodemo"}}
+{{define "form/tunnel"}}
 <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
     <a-form-item label='{{ i18n "pages.inbounds.targetAddress"}}'>
         <a-input v-model.trim="inbound.settings.address"></a-input>

+ 2 - 2
web/html/form/protocol/socks.html

@@ -1,4 +1,4 @@
-{{define "form/socks"}}
+{{define "form/mixed"}}
 <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
   <a-form-item label='{{ i18n "pages.inbounds.enable" }} UDP'>
     <a-switch v-model="inbound.settings.udp"></a-switch>
@@ -15,7 +15,7 @@
         <td width="45%">{{ i18n "username" }}</td>
         <td width="45%">{{ i18n "password" }}</td>
         <td>
-          <a-button icon="plus" size="small" @click="inbound.settings.addAccount(new Inbound.SocksSettings.SocksAccount())"></a-button>
+          <a-button icon="plus" size="small" @click="inbound.settings.addAccount(new Inbound.MixedSettings.SocksAccount())"></a-button>
         </td>
       </tr>
     </table>

+ 2 - 2
web/html/form/reality_settings.html

@@ -12,8 +12,8 @@
             <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
         </a-select>
     </a-form-item>
-    <a-form-item label='Dest (Target)'>
-        <a-input v-model.trim="inbound.stream.reality.dest"></a-input>
+    <a-form-item label='Target'>
+        <a-input v-model.trim="inbound.stream.reality.target"></a-input>
     </a-form-item>
     <a-form-item label='SNI'>
         <a-input v-model.trim="inbound.stream.reality.serverNames"></a-input>

+ 2 - 2
web/html/modals/inbound_info_modal.html

@@ -354,7 +354,7 @@
           <code>[[ link.link ]]</code>
         </tr-info-row>
       </template>
-      <table v-if="inbound.protocol == Protocols.DOKODEMO" class="tr-info-table">
+      <table v-if="inbound.protocol == Protocols.TUNNEL" class="tr-info-table">
         <tr>
           <th>{{ i18n "pages.inbounds.targetAddress" }}</th>
           <th>{{ i18n "pages.inbounds.destinationPort" }}</th>
@@ -376,7 +376,7 @@
           </td>
         </tr>
       </table>
-      <table v-if="dbInbound.isSocks" class="tr-info-table">
+      <table v-if="dbInbound.isMixed" class="tr-info-table">
         <tr>
           <th>{{ i18n "password" }} Auth</th>
           <th>{{ i18n "pages.inbounds.enable" }} udp</th>

+ 1 - 1
web/html/xray.html

@@ -572,7 +572,7 @@
             serverObj = o.settings.vnext;
             break;
           case Protocols.HTTP:
-          case Protocols.Socks:
+          case Protocols.Mixed:
           case Protocols.Shadowsocks:
           case Protocols.Trojan:
             serverObj = o.settings.servers;

+ 1 - 1
web/service/config.json

@@ -19,7 +19,7 @@
       "tag": "api",
       "listen": "127.0.0.1",
       "port": 62789,
-      "protocol": "dokodemo-door",
+      "protocol": "tunnel",
       "settings": {
         "address": "127.0.0.1"
       }

+ 2 - 2
web/service/tgbot.go

@@ -2129,8 +2129,8 @@ func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) {
 	}
 
 	excludedProtocols := map[model.Protocol]bool{
-		model.DOKODEMO:  true,
-		model.Socks:     true,
+		model.Tunnel:    true,
+		model.Mixed:     true,
 		model.WireGuard: true,
 		model.HTTP:      true,
 	}

BIN
windows_files/SSL/Win64OpenSSL_Light-3_5_2.exe


+ 13 - 0
windows_files/readme.txt

@@ -0,0 +1,13 @@
+you can't install fail2ban on windows
+we don't have bash menu for windows
+if you forgot your password you need to check your database with https://sqlitebrowser.org/
+the app need to be open all the time
+
+default setting:
+http://localhost:2053/
+user: admin
+pass: admin
+port: 2053
+
+
+openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt