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" . }}
-
+
{{ i18n "pages.settings.subSettings" }} (JSON)
@@ -523,6 +523,8 @@
if (this.allSetting.subEnable) {
subPath = this.allSetting.subURI.length > 0 ? new URL(this.allSetting.subURI).pathname : this.allSetting.subPath;
if (subPath == '/sub/') alerts.push('{{ i18n "secAlertSubURI" }}');
+ }
+ if (this.allSetting.subJsonEnable) {
subJsonPath = this.allSetting.subJsonURI.length > 0 ? new URL(this.allSetting.subJsonURI).pathname : this.allSetting.subJsonPath;
if (subJsonPath == '/json/') alerts.push('{{ i18n "secAlertSubJsonURI" }}');
}
diff --git a/web/html/settings/panel/subscription/general.html b/web/html/settings/panel/subscription/general.html
index b6e616dd..e3481df7 100644
--- a/web/html/settings/panel/subscription/general.html
+++ b/web/html/settings/panel/subscription/general.html
@@ -8,6 +8,13 @@
+
+ JSON Subscription
+ {{ i18n "pages.settings.subJsonEnable"}}
+
+
+
+
{{ i18n "pages.settings.subTitle"}}
{{ i18n "pages.settings.subTitleDesc"}}
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"