diff --git a/sub/sub.go b/sub/sub.go index 8a16120d..e2876a61 100644 --- a/sub/sub.go +++ b/sub/sub.go @@ -85,6 +85,12 @@ func (s *Server) initRouter() (*gin.Engine, error) { return nil, err } + // Determine if JSON subscription endpoint is enabled + subJsonEnable, err := s.settingService.GetSubJsonEnable() + if err != nil { + return nil, err + } + // Set base_path based on LinksPath for template rendering engine.Use(func(c *gin.Context) { c.Set("base_path", LinksPath) @@ -186,7 +192,7 @@ func (s *Server) initRouter() (*gin.Engine, error) { g := engine.Group("/") s.sub = NewSUBController( - g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates, + g, LinksPath, JsonPath, subJsonEnable, Encrypt, ShowInfo, RemarkModel, SubUpdates, SubJsonFragment, SubJsonNoises, SubJsonMux, SubJsonRules, SubTitle) return engine, nil diff --git a/sub/subController.go b/sub/subController.go index 170cfa74..b29d019e 100644 --- a/sub/subController.go +++ b/sub/subController.go @@ -13,6 +13,7 @@ type SUBController struct { subTitle string subPath string subJsonPath string + jsonEnabled bool subEncrypt bool updateInterval string @@ -24,6 +25,7 @@ func NewSUBController( g *gin.RouterGroup, subPath string, jsonPath string, + jsonEnabled bool, encrypt bool, showInfo bool, rModel string, @@ -39,6 +41,7 @@ func NewSUBController( subTitle: subTitle, subPath: subPath, subJsonPath: jsonPath, + jsonEnabled: jsonEnabled, subEncrypt: encrypt, updateInterval: update, @@ -51,10 +54,11 @@ func NewSUBController( func (a *SUBController) initRouter(g *gin.RouterGroup) { gLink := g.Group(a.subPath) - gJson := g.Group(a.subJsonPath) - gLink.GET(":subid", a.subs) - gJson.GET(":subid", a.subJsons) + if a.jsonEnabled { + gJson := g.Group(a.subJsonPath) + gJson.GET(":subid", a.subJsons) + } } func (a *SUBController) subs(c *gin.Context) { @@ -74,6 +78,9 @@ func (a *SUBController) subs(c *gin.Context) { if strings.Contains(strings.ToLower(accept), "text/html") || c.Query("html") == "1" || strings.EqualFold(c.Query("view"), "html") { // Build page data in service subURL, subJsonURL := a.subService.BuildURLs(scheme, hostWithPort, a.subPath, a.subJsonPath, subId) + if !a.jsonEnabled { + subJsonURL = "" + } page := a.subService.BuildPageData(subId, hostHeader, traffic, lastOnline, subs, subURL, subJsonURL) c.HTML(200, "subpage.html", gin.H{ "title": "subscription.title", diff --git a/web/assets/js/model/setting.js b/web/assets/js/model/setting.js index 55fbf635..d3f7f3e2 100644 --- a/web/assets/js/model/setting.js +++ b/web/assets/js/model/setting.js @@ -26,7 +26,8 @@ class AllSetting { this.twoFactorEnable = false; this.twoFactorToken = ""; this.xrayTemplateConfig = ""; - this.subEnable = false; + this.subEnable = true; + this.subJsonEnable = false; this.subTitle = ""; this.subListen = ""; this.subPort = 2096; diff --git a/web/assets/js/subscription.js b/web/assets/js/subscription.js index 2c731be3..0af95890 100644 --- a/web/assets/js/subscription.js +++ b/web/assets/js/subscription.js @@ -101,7 +101,10 @@ if (sj) this.app.subJsonUrl = sj; drawQR(this.app.subUrl); try { - new QRious({ element: document.getElementById('qrcode-subjson'), value: this.app.subJsonUrl || '', size: 220 }); + const elJson = document.getElementById('qrcode-subjson'); + if (elJson && this.app.subJsonUrl) { + new QRious({ element: elJson, value: this.app.subJsonUrl, size: 220 }); + } } catch (e) { /* ignore */ } this._onResize = () => { this.viewportWidth = window.innerWidth; }; window.addEventListener('resize', this._onResize); diff --git a/web/entity/entity.go b/web/entity/entity.go index 844a7ce0..dd6885f6 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -42,6 +42,7 @@ type AllSetting struct { TwoFactorEnable bool `json:"twoFactorEnable" form:"twoFactorEnable"` TwoFactorToken string `json:"twoFactorToken" form:"twoFactorToken"` SubEnable bool `json:"subEnable" form:"subEnable"` + SubJsonEnable bool `json:"subJsonEnable" form:"subJsonEnable"` SubTitle string `json:"subTitle" form:"subTitle"` SubListen string `json:"subListen" form:"subListen"` SubPort int `json:"subPort" form:"subPort"` diff --git a/web/html/inbounds.html b/web/html/inbounds.html index 1c48480d..5f17c98b 100644 --- a/web/html/inbounds.html +++ b/web/html/inbounds.html @@ -736,10 +736,11 @@ refreshing: false, refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000, subSettings: { - enable: false, + enable: true, subTitle: '', subURI: '', subJsonURI: '', + subJsonEnable: false, }, remarkModel: '-ieo', datepicker: 'gregorian', @@ -795,7 +796,8 @@ enable: subEnable, subTitle: subTitle, subURI: subURI, - subJsonURI: subJsonURI + subJsonURI: subJsonURI, + subJsonEnable: subJsonEnable, }; this.pageSize = pageSize; this.remarkModel = remarkModel; diff --git a/web/html/modals/inbound_info_modal.html b/web/html/modals/inbound_info_modal.html index 5112ec1c..55d9919c 100644 --- a/web/html/modals/inbound_info_modal.html +++ b/web/html/modals/inbound_info_modal.html @@ -308,7 +308,7 @@ [[ infoModal.subLink ]] - + Json Link @@ -548,7 +548,7 @@ if (this.clientSettings) { if (this.clientSettings.subId) { this.subLink = this.genSubLink(this.clientSettings.subId); - this.subJsonLink = this.genSubJsonLink(this.clientSettings.subId); + this.subJsonLink = app.subSettings.subJsonEnable ? this.genSubJsonLink(this.clientSettings.subId) : ''; } } this.visible = true; diff --git a/web/html/modals/qrcode_modal.html b/web/html/modals/qrcode_modal.html index ef438b74..cdbb585b 100644 --- a/web/html/modals/qrcode_modal.html +++ b/web/html/modals/qrcode_modal.html @@ -30,7 +30,7 @@ - + {{ i18n "pages.settings.subSettings"}} Json @@ -262,7 +262,9 @@ if (qrModal.client && qrModal.client.subId) { qrModal.subId = qrModal.client.subId; this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId)); - this.setQrCode("qrCode-subJson", this.genSubJsonLink(qrModal.subId)); + if (app.subSettings.subJsonEnable) { + this.setQrCode("qrCode-subJson", this.genSubJsonLink(qrModal.subId)); + } } qrModal.qrcodes.forEach((element, index) => { this.setQrCode("qrCode-" + index, element.link); diff --git a/web/html/settings.html b/web/html/settings.html index 0c88f518..22ad3907 100644 --- a/web/html/settings.html +++ b/web/html/settings.html @@ -79,7 +79,7 @@ {{ template "settings/panel/subscription/general" . }} - + + + + + + diff --git a/web/html/settings/panel/subscription/subpage.html b/web/html/settings/panel/subscription/subpage.html index c9cf241f..6d56496b 100644 --- a/web/html/settings/panel/subscription/subpage.html +++ b/web/html/settings/panel/subscription/subpage.html @@ -56,7 +56,7 @@ - - \r\n\r\n" + - "JSON URL:\r\n" + subJsonURL + "" + msg := "Subscription URL:\r\n" + subURL + "" + if subJsonURL != "" { + msg += "\r\n\r\nJSON URL:\r\n" + subJsonURL + "" + } inlineKeyboard := tu.InlineKeyboard( tu.InlineKeyboardRow( tu.InlineKeyboardButton(t.I18nBot("subscription.individualLinks")).WithCallbackData(t.encodeQuery("client_individual_links "+email)), @@ -2271,15 +2277,17 @@ func (t *Tgbot) sendClientQRLinks(chatId int64, email string) { t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error()) } - // Send JSON URL QR (filename: subjson.png) - if png, err := createQR(subJsonURL, 320); err == nil { - document := tu.Document( - tu.ID(chatId), - tu.FileFromBytes(png, "subjson.png"), - ) - _, _ = bot.SendDocument(context.Background(), document) - } else { - t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error()) + // Send JSON URL QR (filename: subjson.png) when available + if subJsonURL != "" { + if png, err := createQR(subJsonURL, 320); err == nil { + document := tu.Document( + tu.ID(chatId), + tu.FileFromBytes(png, "subjson.png"), + ) + _, _ = bot.SendDocument(context.Background(), document) + } else { + t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error()) + } } // Also generate a few individual links' QRs (first up to 5) diff --git a/web/translation/translate.ar_EG.toml b/web/translation/translate.ar_EG.toml index 4ddf9fd8..2287b52b 100644 --- a/web/translation/translate.ar_EG.toml +++ b/web/translation/translate.ar_EG.toml @@ -371,6 +371,7 @@ "subSettings" = "الاشتراك" "subEnable" = "تفعيل خدمة الاشتراك" "subEnableDesc" = "يفعل خدمة الاشتراك." +"subJsonEnable" = "تمكين/تعطيل نقطة نهاية اشتراك JSON بشكل مستقل." "subTitle" = "عنوان الاشتراك" "subTitleDesc" = "العنوان اللي هيظهر في عميل VPN" "subListen" = "IP الاستماع" diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index 5a3735dd..e56f5f89 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -369,8 +369,9 @@ "timeZone" = "Time Zone" "timeZoneDesc" = "Scheduled tasks will run based on this time zone." "subSettings" = "Subscription" -"subEnable" = "Enable Subscription Service" -"subEnableDesc" = "Enables the subscription service." +"subEnable" = "Subscription Service" +"subEnableDesc" = "Enable/Disable the subscription service." +"subJsonEnable" = "Enable/Disable the JSON subscription endpoint independently." "subTitle" = "Subscription Title" "subTitleDesc" = "Title shown in VPN client" "subListen" = "Listen IP" diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml index 83a6abbc..ea70494c 100644 --- a/web/translation/translate.es_ES.toml +++ b/web/translation/translate.es_ES.toml @@ -371,6 +371,7 @@ "subSettings" = "Suscripción" "subEnable" = "Habilitar Servicio" "subEnableDesc" = "Función de suscripción con configuración separada." +"subJsonEnable" = "Habilitar/Deshabilitar el endpoint de suscripción JSON de forma independiente." "subTitle" = "Título de la Suscripción" "subTitleDesc" = "Título mostrado en el cliente de VPN" "subListen" = "Listening IP" diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index 37efbc65..70603d08 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -371,6 +371,7 @@ "subSettings" = "سابسکریپشن" "subEnable" = "فعال‌سازی سرویس سابسکریپشن" "subEnableDesc" = "سرویس سابسکریپشن‌ را فعال‌می‌کند" +"subJsonEnable" = "فعال/غیرفعال‌سازی مستقل نقطه دسترسی سابسکریپشن JSON." "subTitle" = "عنوان اشتراک" "subTitleDesc" = "عنوان نمایش داده شده در کلاینت VPN" "subListen" = "آدرس آی‌پی" diff --git a/web/translation/translate.id_ID.toml b/web/translation/translate.id_ID.toml index e0ceaab5..5068aecb 100644 --- a/web/translation/translate.id_ID.toml +++ b/web/translation/translate.id_ID.toml @@ -371,6 +371,7 @@ "subSettings" = "Langganan" "subEnable" = "Aktifkan Layanan Langganan" "subEnableDesc" = "Mengaktifkan layanan langganan." +"subJsonEnable" = "Aktifkan/Nonaktifkan endpoint langganan JSON secara mandiri." "subTitle" = "Judul Langganan" "subTitleDesc" = "Judul yang ditampilkan di klien VPN" "subListen" = "IP Pendengar" diff --git a/web/translation/translate.ja_JP.toml b/web/translation/translate.ja_JP.toml index 7f74f1d4..ebec829a 100644 --- a/web/translation/translate.ja_JP.toml +++ b/web/translation/translate.ja_JP.toml @@ -371,6 +371,7 @@ "subSettings" = "サブスクリプション設定" "subEnable" = "サブスクリプションサービスを有効にする" "subEnableDesc" = "サブスクリプションサービス機能を有効にする" +"subJsonEnable" = "JSON サブスクリプションのエンドポイントを個別に有効/無効にする。" "subTitle" = "サブスクリプションタイトル" "subTitleDesc" = "VPNクライアントに表示されるタイトル" "subListen" = "監視IP" diff --git a/web/translation/translate.pt_BR.toml b/web/translation/translate.pt_BR.toml index ab21489d..f6f3b975 100644 --- a/web/translation/translate.pt_BR.toml +++ b/web/translation/translate.pt_BR.toml @@ -371,6 +371,7 @@ "subSettings" = "Assinatura" "subEnable" = "Ativar Serviço de Assinatura" "subEnableDesc" = "Ativa o serviço de assinatura." +"subJsonEnable" = "Ativar/Desativar o endpoint de assinatura JSON de forma independente." "subTitle" = "Título da Assinatura" "subTitleDesc" = "Título exibido no cliente VPN" "subListen" = "IP de Escuta" diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index 4e46a9f3..49ea872c 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -371,6 +371,7 @@ "subSettings" = "Подписка" "subEnable" = "Включить подписку" "subEnableDesc" = "Функция подписки с отдельной конфигурацией" +"subJsonEnable" = "Включить/отключить JSON-эндпоинт подписки независимо." "subTitle" = "Заголовок подписки" "subTitleDesc" = "Название подписки, которое видит клиент в VPN клиенте" "subListen" = "Прослушивание IP" diff --git a/web/translation/translate.tr_TR.toml b/web/translation/translate.tr_TR.toml index 90394154..d34f6fca 100644 --- a/web/translation/translate.tr_TR.toml +++ b/web/translation/translate.tr_TR.toml @@ -371,6 +371,7 @@ "subSettings" = "Abonelik" "subEnable" = "Abonelik Hizmetini Etkinleştir" "subEnableDesc" = "Abonelik hizmetini etkinleştirir." +"subJsonEnable" = "JSON abonelik uç noktasını bağımsız olarak Etkinleştir/Devre Dışı bırak." "subTitle" = "Abonelik Başlığı" "subTitleDesc" = "VPN istemcisinde gösterilen başlık" "subListen" = "Dinleme IP" diff --git a/web/translation/translate.uk_UA.toml b/web/translation/translate.uk_UA.toml index c59e789d..e8312fb4 100644 --- a/web/translation/translate.uk_UA.toml +++ b/web/translation/translate.uk_UA.toml @@ -371,6 +371,7 @@ "subSettings" = "Підписка" "subEnable" = "Увімкнути службу підписки" "subEnableDesc" = "Вмикає службу підписки." +"subJsonEnable" = "Увімкнути/вимкнути JSON-кінець підписки незалежно." "subTitle" = "Назва Підписки" "subTitleDesc" = "Назва, яка відображається у VPN-клієнті" "subListen" = "Слухати IP" diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml index c653a0cb..787451ae 100644 --- a/web/translation/translate.vi_VN.toml +++ b/web/translation/translate.vi_VN.toml @@ -371,6 +371,7 @@ "subSettings" = "Gói đăng ký" "subEnable" = "Bật dịch vụ" "subEnableDesc" = "Tính năng gói đăng ký với cấu hình riêng" +"subJsonEnable" = "Bật/Tắt điểm cuối đăng ký JSON độc lập." "subTitle" = "Tiêu đề Đăng ký" "subTitleDesc" = "Tiêu đề hiển thị trong ứng dụng VPN" "subListen" = "Listening IP" diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml index 333a61c7..b11f9073 100644 --- a/web/translation/translate.zh_CN.toml +++ b/web/translation/translate.zh_CN.toml @@ -371,6 +371,7 @@ "subSettings" = "订阅设置" "subEnable" = "启用订阅服务" "subEnableDesc" = "启用订阅服务功能" +"subJsonEnable" = "单独启用/禁用 JSON 订阅端点。" "subTitle" = "订阅标题" "subTitleDesc" = "在VPN客户端中显示的标题" "subListen" = "监听 IP" diff --git a/web/translation/translate.zh_TW.toml b/web/translation/translate.zh_TW.toml index f646b45c..ad1bdab9 100644 --- a/web/translation/translate.zh_TW.toml +++ b/web/translation/translate.zh_TW.toml @@ -371,6 +371,7 @@ "subSettings" = "訂閱設定" "subEnable" = "啟用訂閱服務" "subEnableDesc" = "啟用訂閱服務功能" +"subJsonEnable" = "獨立啟用/停用 JSON 訂閱端點。" "subTitle" = "訂閱標題" "subTitleDesc" = "在VPN客戶端中顯示的標題" "subListen" = "監聽 IP"