fix(app): preserve passwords during Local startup
Local App startup saved passwords such as `好` or `a+b` correctly and started the service, but the launcher encoded its URL fragment twice. The browser then submitted a different password and stopped at the site-access screen. Both App launch URL paths now read the escaped fragment and serialize its query parameters once. Regression checks use the browser-visible fragment, which prevents an extra Go URL-decoding step from hiding the defect. ## Release notes ### 中文 - 修复 App 设置中文、空格或特殊字符作为本地站点密码后,启动时无法自动进入站点的问题。 ### English - Fixed automatic Local site entry when an App password contains Chinese text, spaces or special characters. ## Verification - Go App and Launcher checks passed, including password round trips, reopening a launch URL, empty passwords and retained language/theme parameters. - 105 relevant Web tests, type-checking and the Web build passed. - A development App built from the repaired source passed the actual fresh Launcher-to-Local flow with a one-character Chinese password: one automatic JSON login returned 200, Host UI opened without manual login, the consumed fragment was cleared, and Chinese/dark preferences were retained. Compatible App bug fix; signaling, Native control, capture and persistent room contracts are unchanged.
This commit is contained in:
2 files changed
+32
-22
No files matched your search
+6
-6
@@ -503,13 +503,13 @@ func launchURL(raw string) string {
|
||||
if err != nil {
|
||||
return raw
|
||||
}
|
||||
fragment, err := url.ParseQuery(parsed.Fragment)
|
||||
fragment, err := url.ParseQuery(parsed.EscapedFragment())
|
||||
if err != nil {
|
||||
return raw
|
||||
}
|
||||
fragment.Set("piik-client", "1")
|
||||
parsed.Fragment = fragment.Encode()
|
||||
return parsed.String()
|
||||
parsed.Fragment, parsed.RawFragment = "", ""
|
||||
return parsed.String() + "#" + fragment.Encode()
|
||||
}
|
||||
|
||||
func launchURLWithLocalAccess(raw, password string) string {
|
||||
@@ -517,7 +517,7 @@ func launchURLWithLocalAccess(raw, password string) string {
|
||||
if err != nil {
|
||||
return raw
|
||||
}
|
||||
fragment, err := url.ParseQuery(parsed.Fragment)
|
||||
fragment, err := url.ParseQuery(parsed.EscapedFragment())
|
||||
if err != nil {
|
||||
return launchURL(raw)
|
||||
}
|
||||
@@ -526,8 +526,8 @@ func launchURLWithLocalAccess(raw, password string) string {
|
||||
fragment.Set("client-access", password)
|
||||
}
|
||||
fragment.Set("piik-client", "1")
|
||||
parsed.Fragment = fragment.Encode()
|
||||
return parsed.String()
|
||||
parsed.Fragment, parsed.RawFragment = "", ""
|
||||
return parsed.String() + "#" + fragment.Encode()
|
||||
}
|
||||
|
||||
type nativeRuntime struct {
|
||||
|
||||
+26
-16
@@ -94,7 +94,7 @@ func TestAppLaunchURLMarksThePageWithoutChangingOrigin(t *testing.T) {
|
||||
parsed.RawQuery != "" {
|
||||
t.Fatalf("launch URL = %q, %v", value, err)
|
||||
}
|
||||
fragment, err := url.ParseQuery(parsed.Fragment)
|
||||
fragment, err := url.ParseQuery(parsed.EscapedFragment())
|
||||
if err != nil || fragment.Get("piik-client") != "1" {
|
||||
t.Fatalf("App launch fragment = %q, %v", parsed.Fragment, err)
|
||||
}
|
||||
@@ -192,7 +192,7 @@ func TestLaunchURLPreservesLocalAccessInsideThePrivateFragment(t *testing.T) {
|
||||
if err != nil || parsed.RawQuery != "" {
|
||||
t.Fatalf("local native launch URL = %q, %v", value, err)
|
||||
}
|
||||
fragment, err := url.ParseQuery(parsed.Fragment)
|
||||
fragment, err := url.ParseQuery(parsed.EscapedFragment())
|
||||
if err != nil || fragment.Get("client-access") != "secret" ||
|
||||
fragment.Get("piik-client") != "1" {
|
||||
t.Fatalf("local native launch fragment = %q, %v", parsed.Fragment, err)
|
||||
@@ -200,26 +200,36 @@ func TestLaunchURLPreservesLocalAccessInsideThePrivateFragment(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLaunchURLEncodesAndClearsOptionalLocalAccess(t *testing.T) {
|
||||
value := launchURLWithLocalAccess(
|
||||
"http://localhost:8787/#retained=yes&client-access=old",
|
||||
" 中文 a+b&c?d=e ",
|
||||
)
|
||||
parsed, err := url.Parse(value)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fragment, err := url.ParseQuery(parsed.Fragment)
|
||||
if err != nil || fragment.Get("client-access") != " 中文 a+b&c?d=e " ||
|
||||
fragment.Get("piik-client") != "1" || fragment.Get("retained") != "yes" {
|
||||
t.Fatalf("encoded local launch fragment = %q, %v", parsed.Fragment, err)
|
||||
for _, password := range []string{"x", "好", " ", "+", "%", "#&?=", " 中文 a+b&c?d=e% "} {
|
||||
t.Run(password, func(t *testing.T) {
|
||||
value := launchURLWithLocalAccess(
|
||||
"http://localhost:8787/?retained=query#retained=a%2Bb%25&client-access=old&piik-lang=zh&piik-mode=text&piik-theme=dark",
|
||||
password,
|
||||
)
|
||||
for _, target := range []string{value, launchURL(value)} {
|
||||
parsed, err := url.Parse(target)
|
||||
if err != nil || parsed.RawQuery != "retained=query" {
|
||||
t.Fatalf("local launch URL = %q, %v", target, err)
|
||||
}
|
||||
// location.hash stays escaped. Parsing Fragment instead would decode
|
||||
// twice and hide the browser's percent-encoded-password regression.
|
||||
fragment, err := url.ParseQuery(parsed.EscapedFragment())
|
||||
if err != nil || fragment.Get("client-access") != password ||
|
||||
fragment.Get("piik-client") != "1" || fragment.Get("retained") != "a+b%" ||
|
||||
fragment.Get("piik-lang") != "zh" || fragment.Get("piik-mode") != "text" ||
|
||||
fragment.Get("piik-theme") != "dark" {
|
||||
t.Fatalf("browser-visible launch fragment = %q, %v", parsed.EscapedFragment(), err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
open := launchURLWithLocalAccess("http://localhost:8787/#client-access=old", "")
|
||||
parsed, err = url.Parse(open)
|
||||
parsed, err := url.Parse(open)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fragment, err = url.ParseQuery(parsed.Fragment)
|
||||
fragment, err := url.ParseQuery(parsed.EscapedFragment())
|
||||
if err != nil || fragment.Get("client-access") != "" || fragment.Get("piik-client") != "1" {
|
||||
t.Fatalf("open local launch fragment = %q, %v", parsed.Fragment, err)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user