feat: sync host-based public app links

This commit is contained in:
A 2026-07-22 21:43:56 +08:00
parent 10de462191
commit 8cfb6f74c1
19 changed files with 375 additions and 26 deletions

View file

@ -82,6 +82,10 @@ type Config struct {
// PublicAppScheme 是公开落地页自动唤起自建客户端时使用的 URL scheme。
// 必须与 TDesktop/Android 客户端构建时注册的 scheme 一致,且不能占用 tg/http/https。
PublicAppScheme string
// PublicAppLinkBase 是可选的 host-based 自建客户端链接根,例如
// owpg://example.com。为空时继续生成 PublicAppScheme://<route>;非空时
// 生成 <base>/<route>,同时保留旧 scheme 作为服务端输入兼容。
PublicAppLinkBase string
// PublicWebBaseURL 是公开 username 页面“Open in Web”按钮指向的 Web 客户端根 URL。
PublicWebBaseURL string
// PublicAppName 是公开落地页展示的产品名,不参与协议路由。
@ -434,6 +438,10 @@ func Load() (Config, error) {
if err != nil {
return Config{}, fmt.Errorf("TELESRV_PUBLIC_APP_SCHEME: %w", err)
}
publicAppLinkBase, err := links.ValidateAppLinkBase(envAllowEmptyOr("TELESRV_PUBLIC_APP_LINK_BASE", ""))
if err != nil {
return Config{}, fmt.Errorf("TELESRV_PUBLIC_APP_LINK_BASE: %w", err)
}
publicWebBaseURL, err := links.ValidateBaseURL(envOr("TELESRV_PUBLIC_WEB_BASE_URL", links.DefaultWebBaseURL))
if err != nil {
return Config{}, fmt.Errorf("TELESRV_PUBLIC_WEB_BASE_URL: %w", err)
@ -487,6 +495,7 @@ func Load() (Config, error) {
AdminAPIToken: envOr("TELESRV_ADMIN_API_TOKEN", ""),
PublicBaseURL: publicBaseURL,
PublicAppScheme: publicAppScheme,
PublicAppLinkBase: publicAppLinkBase,
PublicWebBaseURL: publicWebBaseURL,
PublicAppName: publicAppName,
PublicLinkWebAddr: envAllowEmptyOr("TELESRV_PUBLIC_LINK_WEB_ADDR", ""),

View file

@ -25,6 +25,9 @@ func TestLoadDefaultsAdvertiseIPToLoopback(t *testing.T) {
if cfg.PublicAppScheme != "telesrv" {
t.Fatalf("PublicAppScheme = %q, want telesrv", cfg.PublicAppScheme)
}
if cfg.PublicAppLinkBase != "" {
t.Fatalf("PublicAppLinkBase = %q, want disabled", cfg.PublicAppLinkBase)
}
if cfg.PublicWebBaseURL != "https://web.telesrv.net" {
t.Fatalf("PublicWebBaseURL = %q, want https://web.telesrv.net", cfg.PublicWebBaseURL)
}
@ -379,6 +382,7 @@ TELESRV_WEBSOCKET_ALLOWED_ORIGINS=https://one.example, https://two.example
TELESRV_CALL_RING_TIMEOUT=2m
TELESRV_PUBLIC_BASE_URL=links.example.test/root
TELESRV_PUBLIC_APP_SCHEME=example-chat
TELESRV_PUBLIC_APP_LINK_BASE=OWPG://Tenant.Example.Test/
TELESRV_PUBLIC_WEB_BASE_URL=web.example.test/client
TELESRV_PUBLIC_APP_NAME=Example Chat
TELESRV_PUBLIC_LINK_WEB_ADDR=127.0.0.1:2401
@ -410,6 +414,9 @@ TELESRV_PUBLIC_LINK_WEB_ADDR=127.0.0.1:2401
if cfg.PublicAppScheme != "example-chat" {
t.Fatalf("PublicAppScheme = %q, want example-chat", cfg.PublicAppScheme)
}
if cfg.PublicAppLinkBase != "owpg://tenant.example.test" {
t.Fatalf("PublicAppLinkBase = %q, want owpg://tenant.example.test", cfg.PublicAppLinkBase)
}
if cfg.PublicWebBaseURL != "https://web.example.test/client" {
t.Fatalf("PublicWebBaseURL = %q, want https://web.example.test/client", cfg.PublicWebBaseURL)
}
@ -537,6 +544,10 @@ func TestLoadRejectsInvalidPublicLinkClientConfig(t *testing.T) {
}{
{name: "official scheme", key: "TELESRV_PUBLIC_APP_SCHEME", value: "tg"},
{name: "malformed scheme", key: "TELESRV_PUBLIC_APP_SCHEME", value: "bad scheme"},
{name: "app link base official scheme", key: "TELESRV_PUBLIC_APP_LINK_BASE", value: "tg://links.example.test"},
{name: "app link base missing host", key: "TELESRV_PUBLIC_APP_LINK_BASE", value: "owpg://"},
{name: "app link base path", key: "TELESRV_PUBLIC_APP_LINK_BASE", value: "owpg://links.example.test/root"},
{name: "app link base query", key: "TELESRV_PUBLIC_APP_LINK_BASE", value: "owpg://links.example.test?tenant=one"},
{name: "invalid web base", key: "TELESRV_PUBLIC_WEB_BASE_URL", value: "file:///tmp/client"},
{name: "empty app name after trim", key: "TELESRV_PUBLIC_APP_NAME", value: " "},
{name: "control in app name", key: "TELESRV_PUBLIC_APP_NAME", value: "bad\nname"},