Browse Source

[feature] fallback link calculation

Co-Authored-By: Alireza Ahmadi <[email protected]>
MHSanaei 1 year ago
parent
commit
47ccc7b501
4 changed files with 57 additions and 10 deletions
  1. 28 0
      sub/subService.go
  2. 1 0
      web/html/common/qrcode_modal.html
  3. 26 3
      web/html/xui/inbounds.html
  4. 2 7
      x-ui.sh

+ 28 - 0
sub/subService.go

@@ -38,6 +38,21 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, []string, err
 		if clients == nil {
 			continue
 		}
+		if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
+			fallbackMaster, err := s.getFallbackMaster(inbound.Listen)
+			if err == nil {
+				inbound.Listen = fallbackMaster.Listen
+				inbound.Port = fallbackMaster.Port
+				var stream map[string]interface{}
+				json.Unmarshal([]byte(inbound.StreamSettings), &stream)
+				var masterStream map[string]interface{}
+				json.Unmarshal([]byte(fallbackMaster.StreamSettings), &masterStream)
+				stream["security"] = masterStream["security"]
+				stream["tlsSettings"] = masterStream["tlsSettings"]
+				modifiedStream, _ := json.MarshalIndent(stream, "", "  ")
+				inbound.StreamSettings = string(modifiedStream)
+			}
+		}
 		for _, client := range clients {
 			if client.Enable && client.SubID == subId {
 				link := s.getLink(inbound, client.Email)
@@ -93,6 +108,19 @@ func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email stri
 	return xray.ClientTraffic{}
 }
 
+func (s *SubService) getFallbackMaster(dest string) (*model.Inbound, error) {
+	db := database.GetDB()
+	var inbound *model.Inbound
+	err := db.Model(model.Inbound{}).
+		Where("JSON_TYPE(settings, '$.fallbacks') = 'array'").
+		Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest).
+		Find(&inbound).Error
+	if err != nil {
+		return nil, err
+	}
+	return inbound, nil
+}
+
 func (s *SubService) getLink(inbound *model.Inbound, email string) string {
 	switch inbound.Protocol {
 	case "vmess":

+ 1 - 0
web/html/common/qrcode_modal.html

@@ -39,6 +39,7 @@
             this.client = settings.clients[clientIndex];
             remark = this.dbInbound.remark + "-" + this.client.email;
             address = this.dbInbound.address;
+            this.subId = '';
             this.qrcodes = [];
             if (this.inbound.tls && !ObjectUtil.isArrEmpty(this.inbound.stream.tls.settings.domains)) {
                 this.inbound.stream.tls.settings.domains.forEach((domain) => {

+ 26 - 3
web/html/xui/inbounds.html

@@ -361,6 +361,7 @@
                 this.refreshing = true;
                 const msg = await HttpUtil.post('/panel/inbound/list');
                 if (!msg.success) {
+                    this.refreshing = false;
                     return;
                 }
                 this.setInbounds(msg.obj);
@@ -763,11 +764,32 @@
                     default: return client.id;
                 }
             },
+            checkFallback(dbInbound) {
+                newDbInbound = new DBInbound(dbInbound);
+                if (dbInbound.listen.startsWith("@")){
+                    rootInbound = this.inbounds.find((i) => 
+                        i.tls && 
+                        ['trojan','vless'].includes(i.protocol) &&
+                        i.settings.fallbacks.find(f => f.dest === dbInbound.listen)
+                    );
+                    if (rootInbound) {
+                        newDbInbound.listen = rootInbound.listen;
+                        newDbInbound.port = rootInbound.port;
+                        newInbound = newDbInbound.toInbound();
+                        newInbound.stream.security = 'tls';
+                        newInbound.stream.tls = rootInbound.stream.tls;
+                        newDbInbound.streamSettings = newInbound.stream.toString();
+                    }
+                }
+                return newDbInbound;
+            },
             showQrcode(dbInbound, clientIndex) {
-                qrModal.show('{{ i18n "qrCode"}}', dbInbound, clientIndex);
+                newDbInbound = this.checkFallback(dbInbound);
+                qrModal.show('{{ i18n "qrCode"}}', newDbInbound, clientIndex);
             },
             showInfo(dbInbound, index) {
-                infoModal.show(dbInbound, index);
+                newDbInbound = this.checkFallback(dbInbound);
+                infoModal.show(newDbInbound, index);
             },
             switchEnable(dbInboundId) {
                 dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
@@ -868,7 +890,8 @@
             },
             inboundLinks(dbInboundId) {
                 dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
-                txtModal.show('{{ i18n "pages.inbounds.export"}}', dbInbound.genInboundLinks, dbInbound.remark);
+                newDbInbound = this.checkFallback(dbInbound);
+                txtModal.show('{{ i18n "pages.inbounds.export"}}', newDbInbound.genInboundLinks, newDbInbound.remark);
             },
             exportAllLinks() {
                 let copyText = '';

+ 2 - 7
x-ui.sh

@@ -528,6 +528,7 @@ ssl_cert_issue_main() {
             local domain=""
             read -p "Please enter your domain name to revoke the certificate: " domain
             ~/.acme.sh/acme.sh --revoke -d ${domain}
+            LOGI "Certificate revoked"
             ;;
         3)
             local domain=""
@@ -571,13 +572,7 @@ ssl_cert_issue() {
         local certInfo=$(~/.acme.sh/acme.sh --list)
         LOGE "system already has certs here,can not issue again,current certs details:"
         LOGI "$certInfo"
-        read -p "Do you want to revoke the existing certificate? (yes/no): " choice
-        if [ "$choice" == "yes" ]; then
-            ~/.acme.sh/acme.sh --revoke -d ${domain}
-            LOGI "Certificate revoked"
-        else
-            exit 1
-        fi
+        exit 1
     else
         LOGI "your domain is ready for issuing cert now..."
     fi