fix for owpg
This commit is contained in:
parent
d5c51f620c
commit
ddd26e51b5
2 changed files with 55 additions and 21 deletions
|
|
@ -157,6 +157,14 @@ func newHandler(cfg Config, logger *zap.Logger) (http.Handler, error) {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
logger = zap.NewNop()
|
logger = zap.NewNop()
|
||||||
}
|
}
|
||||||
|
// links.ValidateBaseURL above guarantees cfg.PublicBaseURL parses with a
|
||||||
|
// non-empty host; publicHost is the bare "host[:port]" used to build
|
||||||
|
// owpg://<host>/<path> deep links (the client reinterprets those as
|
||||||
|
// https://<host>/<path>, see LaunchActivity's "owpg" scheme case).
|
||||||
|
publicHost := cfg.PublicBaseURL
|
||||||
|
if u, err := url.Parse(cfg.PublicBaseURL); err == nil {
|
||||||
|
publicHost = u.Host
|
||||||
|
}
|
||||||
h := &handler{
|
h := &handler{
|
||||||
stickerSets: cfg.StickerSets,
|
stickerSets: cfg.StickerSets,
|
||||||
users: cfg.Users,
|
users: cfg.Users,
|
||||||
|
|
@ -166,6 +174,7 @@ func newHandler(cfg Config, logger *zap.Logger) (http.Handler, error) {
|
||||||
uniqueGifts: cfg.UniqueGifts,
|
uniqueGifts: cfg.UniqueGifts,
|
||||||
giftWithdrawals: cfg.GiftWithdrawals,
|
giftWithdrawals: cfg.GiftWithdrawals,
|
||||||
publicBaseURL: cfg.PublicBaseURL,
|
publicBaseURL: cfg.PublicBaseURL,
|
||||||
|
publicHost: publicHost,
|
||||||
appScheme: cfg.AppScheme,
|
appScheme: cfg.AppScheme,
|
||||||
webBaseURL: cfg.WebBaseURL,
|
webBaseURL: cfg.WebBaseURL,
|
||||||
appName: cfg.AppName,
|
appName: cfg.AppName,
|
||||||
|
|
@ -199,6 +208,7 @@ type handler struct {
|
||||||
uniqueGifts UniqueStarGiftResolver
|
uniqueGifts UniqueStarGiftResolver
|
||||||
giftWithdrawals StarGiftWithdrawalResolver
|
giftWithdrawals StarGiftWithdrawalResolver
|
||||||
publicBaseURL string
|
publicBaseURL string
|
||||||
|
publicHost string
|
||||||
appScheme string
|
appScheme string
|
||||||
webBaseURL string
|
webBaseURL string
|
||||||
appName string
|
appName string
|
||||||
|
|
@ -284,7 +294,7 @@ func (h *handler) addList(w http.ResponseWriter, r *http.Request) {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app := h.appURL("addlist", "slug", slug)
|
app := h.appURL("addlist", slug)
|
||||||
data := pageData{
|
data := pageData{
|
||||||
AppName: h.appName,
|
AppName: h.appName,
|
||||||
Title: "Shared Folder",
|
Title: "Shared Folder",
|
||||||
|
|
@ -340,7 +350,7 @@ func (h *handler) uniqueGift(w http.ResponseWriter, r *http.Request) {
|
||||||
if unique.AvailabilityIssued > 0 && unique.AvailabilityTotal >= unique.AvailabilityIssued {
|
if unique.AvailabilityIssued > 0 && unique.AvailabilityTotal >= unique.AvailabilityIssued {
|
||||||
subtitle += fmt.Sprintf(" · %s/%s issued", groupedDecimal(unique.AvailabilityIssued), groupedDecimal(unique.AvailabilityTotal))
|
subtitle += fmt.Sprintf(" · %s/%s issued", groupedDecimal(unique.AvailabilityIssued), groupedDecimal(unique.AvailabilityTotal))
|
||||||
}
|
}
|
||||||
app := h.appURL("nft", "slug", canonicalSlug)
|
app := h.appURL("nft", canonicalSlug)
|
||||||
data := pageData{
|
data := pageData{
|
||||||
AppName: h.appName,
|
AppName: h.appName,
|
||||||
Title: title,
|
Title: title,
|
||||||
|
|
@ -385,8 +395,10 @@ func (h *handler) usernameLink(w http.ResponseWriter, r *http.Request) {
|
||||||
h.serveUsernameNotFound(w, username)
|
h.serveUsernameNotFound(w, username)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// owpg://<host>/<username> — built from params BEFORE "domain" is added
|
||||||
|
// below, since owpg encodes the username in the path, not as a query key.
|
||||||
|
app := h.appUsernameURL(peer.username, params)
|
||||||
params.Set("domain", peer.username)
|
params.Set("domain", peer.username)
|
||||||
app := schemeURLValues(h.appScheme, "resolve", params)
|
|
||||||
description := peer.about
|
description := peer.about
|
||||||
if description == "" {
|
if description == "" {
|
||||||
description = peer.fallbackDescription(h.appName)
|
description = peer.fallbackDescription(h.appName)
|
||||||
|
|
@ -455,7 +467,7 @@ func (h *handler) inviteLink(w http.ResponseWriter, r *http.Request, hash string
|
||||||
if title == "" {
|
if title == "" {
|
||||||
title = strings.TrimSpace(invite.Title)
|
title = strings.TrimSpace(invite.Title)
|
||||||
}
|
}
|
||||||
app := h.appURL("join", "invite", hash)
|
app := h.appInviteURL(hash)
|
||||||
description := peer.about
|
description := peer.about
|
||||||
if description == "" {
|
if description == "" {
|
||||||
description = peer.fallbackDescription(h.appName)
|
description = peer.fallbackDescription(h.appName)
|
||||||
|
|
@ -618,7 +630,7 @@ func (h *handler) serveSet(w http.ResponseWriter, r *http.Request, pathKind stri
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
count = len(docs)
|
count = len(docs)
|
||||||
}
|
}
|
||||||
app := h.appURL(canonicalKind, "set", set.ShortName)
|
app := h.appURL(canonicalKind, set.ShortName)
|
||||||
data := pageData{
|
data := pageData{
|
||||||
AppName: h.appName,
|
AppName: h.appName,
|
||||||
Title: fallbackTitle(set),
|
Title: fallbackTitle(set),
|
||||||
|
|
@ -1169,10 +1181,32 @@ func itemNoun(set domain.StickerSet, count int) string {
|
||||||
return "stickers"
|
return "stickers"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) appURL(kind, key, value string) string {
|
// appURL/appInviteURL/appUsernameURL build owpg://<host>/<path> deep links —
|
||||||
return schemeURL(h.appScheme, kind, key, value)
|
// mirrors publicURL/publicInviteURL/publicUsernameURL (https://<host>/<path>)
|
||||||
|
// but with the app scheme instead. The client's "owpg" URI handler reinterprets
|
||||||
|
// owpg://<host>/<path>?<query> as https://<host>/<path>?<query> and falls
|
||||||
|
// through to the normal t.me-style path router (LaunchActivity.java), which
|
||||||
|
// expects a path, not a tg://-style "resolve?domain=" query. Do NOT use
|
||||||
|
// schemeURL here — that format is only valid for the real tg:// scheme.
|
||||||
|
func (h *handler) appURL(kind, value string) string {
|
||||||
|
return h.appScheme + "://" + h.publicHost + "/" + kind + "/" + url.PathEscape(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handler) appInviteURL(hash string) string {
|
||||||
|
return h.appScheme + "://" + h.publicHost + "/+" + url.PathEscape(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) appUsernameURL(username string, extraQuery url.Values) string {
|
||||||
|
u := h.appScheme + "://" + h.publicHost + "/" + url.PathEscape(username)
|
||||||
|
if len(extraQuery) > 0 {
|
||||||
|
u += "?" + extraQuery.Encode()
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// schemeURL/schemeURLValues build the real tg:// deep-link format
|
||||||
|
// (tg://resolve?domain=X) — used only for the legacy-client fallback link
|
||||||
|
// (LegacyTgURL), never for the app's own owpg:// scheme.
|
||||||
func schemeURL(scheme, kind, key, value string) string {
|
func schemeURL(scheme, kind, key, value string) string {
|
||||||
return scheme + "://" + kind + "?" + key + "=" + url.QueryEscape(value)
|
return scheme + "://" + kind + "?" + key + "=" + url.QueryEscape(value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ func TestHandlerServesUniqueGiftLandingPage(t *testing.T) {
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"Official Gift", "Collectible #7", "7/1 000 issued",
|
"Official Gift", "Collectible #7", "7/1 000 issued",
|
||||||
"http://127.0.0.1:2401/nft/" + slug,
|
"http://127.0.0.1:2401/nft/" + slug,
|
||||||
"telesrv://nft?slug=" + slug,
|
"telesrv://127.0.0.1:2401/nft/" + slug,
|
||||||
"tg://nft?slug=" + slug,
|
"tg://nft?slug=" + slug,
|
||||||
"Open it in the app to view its current details.",
|
"Open it in the app to view its current details.",
|
||||||
} {
|
} {
|
||||||
|
|
@ -219,7 +219,7 @@ func TestHandlerServesStickerSetLandingPage(t *testing.T) {
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"Fresh Pack",
|
"Fresh Pack",
|
||||||
"https://telesrv.net/addstickers/fresh_pack",
|
"https://telesrv.net/addstickers/fresh_pack",
|
||||||
"telesrv://addstickers?set=fresh_pack",
|
"telesrv://telesrv.net/addstickers/fresh_pack",
|
||||||
"Files are still fetched by the app through MTProto.",
|
"Files are still fetched by the app through MTProto.",
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(body, want) {
|
if !strings.Contains(body, want) {
|
||||||
|
|
@ -257,7 +257,7 @@ func TestHandlerServesEmojiLandingPage(t *testing.T) {
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"custom emoji set",
|
"custom emoji set",
|
||||||
"https://example.test/base/addemoji/emoji_pack",
|
"https://example.test/base/addemoji/emoji_pack",
|
||||||
"telesrv://addemoji?set=emoji_pack",
|
"telesrv://example.test/addemoji/emoji_pack",
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(body, want) {
|
if !strings.Contains(body, want) {
|
||||||
t.Fatalf("body missing %q:\n%s", want, body)
|
t.Fatalf("body missing %q:\n%s", want, body)
|
||||||
|
|
@ -278,7 +278,7 @@ func TestHandlerServesChatlistLandingPage(t *testing.T) {
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"Shared Folder",
|
"Shared Folder",
|
||||||
"http://127.0.0.1:2401/addlist/zNhytIbwRwjaC2GH",
|
"http://127.0.0.1:2401/addlist/zNhytIbwRwjaC2GH",
|
||||||
"telesrv://addlist?slug=zNhytIbwRwjaC2GH",
|
"telesrv://127.0.0.1:2401/addlist/zNhytIbwRwjaC2GH",
|
||||||
"preview and add this shared folder",
|
"preview and add this shared folder",
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(body, want) {
|
if !strings.Contains(body, want) {
|
||||||
|
|
@ -313,11 +313,11 @@ func TestHandlerServesBotUsernameLandingPage(t *testing.T) {
|
||||||
"bot",
|
"bot",
|
||||||
"@TetrisBot",
|
"@TetrisBot",
|
||||||
"http://127.0.0.1:2401/TetrisBot",
|
"http://127.0.0.1:2401/TetrisBot",
|
||||||
"telesrv://resolve?domain=TetrisBot",
|
"telesrv://127.0.0.1:2401/TetrisBot",
|
||||||
"Start Bot",
|
"Start Bot",
|
||||||
"Open telesrv to start a chat with this bot.",
|
"Open telesrv to start a chat with this bot.",
|
||||||
`property="og:title" content="Tetris Bot"`,
|
`property="og:title" content="Tetris Bot"`,
|
||||||
`property="al:android:url" content="telesrv://resolve?domain=TetrisBot"`,
|
`property="al:android:url" content="telesrv://127.0.0.1:2401/TetrisBot"`,
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(body, want) {
|
if !strings.Contains(body, want) {
|
||||||
t.Fatalf("body missing %q:\n%s", want, body)
|
t.Fatalf("body missing %q:\n%s", want, body)
|
||||||
|
|
@ -353,7 +353,7 @@ func TestHandlerUsesConfiguredClientLinksAndBrand(t *testing.T) {
|
||||||
}
|
}
|
||||||
body := rr.Body.String()
|
body := rr.Body.String()
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"example-chat://resolve?domain=Alice&start=hello",
|
"example-chat://links.example.test/Alice?start=hello",
|
||||||
"https://web.example.test/client/#?tgaddr=",
|
"https://web.example.test/client/#?tgaddr=",
|
||||||
"Example Chat",
|
"Example Chat",
|
||||||
"Open Example Chat to send a message to @Alice.",
|
"Open Example Chat to send a message to @Alice.",
|
||||||
|
|
@ -369,10 +369,10 @@ func TestHandlerUsesConfiguredClientLinksAndBrand(t *testing.T) {
|
||||||
path string
|
path string
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{path: "/addstickers/stickers_pack", want: "example-chat://addstickers?set=stickers_pack"},
|
{path: "/addstickers/stickers_pack", want: "example-chat://links.example.test/addstickers/stickers_pack"},
|
||||||
{path: "/addemoji/emoji_pack", want: "example-chat://addemoji?set=emoji_pack"},
|
{path: "/addemoji/emoji_pack", want: "example-chat://links.example.test/addemoji/emoji_pack"},
|
||||||
{path: "/addlist/shared-folder", want: "example-chat://addlist?slug=shared-folder"},
|
{path: "/addlist/shared-folder", want: "example-chat://links.example.test/addlist/shared-folder"},
|
||||||
{path: "/nft/gift-1", want: "example-chat://nft?slug=gift-1"},
|
{path: "/nft/gift-1", want: "example-chat://links.example.test/nft/gift-1"},
|
||||||
} {
|
} {
|
||||||
rr := httptest.NewRecorder()
|
rr := httptest.NewRecorder()
|
||||||
h.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, tc.path, nil))
|
h.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, tc.path, nil))
|
||||||
|
|
@ -447,14 +447,14 @@ func TestHandlerServesUserChannelAndSupergroupLandingPages(t *testing.T) {
|
||||||
path: "/aLiCe/",
|
path: "/aLiCe/",
|
||||||
wants: []string{
|
wants: []string{
|
||||||
"Alice Example", "Public bio", "@Alice", "Send Message", "Verified",
|
"Alice Example", "Public bio", "@Alice", "Send Message", "Verified",
|
||||||
"https://telesrv.net/Alice", "telesrv://resolve?domain=Alice",
|
"https://telesrv.net/Alice", "telesrv://telesrv.net/Alice",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/NewsRoom",
|
path: "/NewsRoom",
|
||||||
wants: []string{
|
wants: []string{
|
||||||
"News Room", "Public channel description", "12 001 subscribers", "View Channel",
|
"News Room", "Public channel description", "12 001 subscribers", "View Channel",
|
||||||
"https://telesrv.net/NewsRoom", "telesrv://resolve?domain=NewsRoom",
|
"https://telesrv.net/NewsRoom", "telesrv://telesrv.net/NewsRoom",
|
||||||
"/_public/avatar/NewsRoom/301",
|
"/_public/avatar/NewsRoom/301",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -497,7 +497,7 @@ func TestHandlerPreservesBoundedResolveQueryAndOverridesDomain(t *testing.T) {
|
||||||
}
|
}
|
||||||
body := rr.Body.String()
|
body := rr.Body.String()
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"telesrv://resolve?domain=TetrisBot&ref=campaign&start=hello",
|
"telesrv://telesrv.net/TetrisBot?ref=campaign&start=hello",
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(body, want) {
|
if !strings.Contains(body, want) {
|
||||||
t.Fatalf("body missing sanitized query %q:\n%s", want, body)
|
t.Fatalf("body missing sanitized query %q:\n%s", want, body)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue