Fix manifest encoding (#14114)
The previous URL encoding would encode spaces to '+' for the app name which is incorrect. Use base64 encoding instead which does not have such issues.
This commit is contained in:
parent
e0c753e770
commit
cd5278a44c
3 changed files with 105 additions and 10 deletions
|
@ -7,8 +7,8 @@ package setting
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
|
@ -104,6 +104,7 @@ var (
|
|||
GracefulHammerTime time.Duration
|
||||
StartupTimeout time.Duration
|
||||
StaticURLPrefix string
|
||||
AbsoluteAssetURL string
|
||||
|
||||
SSH = struct {
|
||||
Disabled bool `ini:"DISABLE_SSH"`
|
||||
|
@ -294,7 +295,7 @@ var (
|
|||
CSRFCookieName = "_csrf"
|
||||
CSRFCookieHTTPOnly = true
|
||||
|
||||
ManifestData template.URL
|
||||
ManifestData string
|
||||
|
||||
// Mirror settings
|
||||
Mirror struct {
|
||||
|
@ -600,6 +601,11 @@ func NewContext() {
|
|||
Domain = urlHostname
|
||||
}
|
||||
|
||||
AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix)
|
||||
|
||||
manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL)
|
||||
ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes)
|
||||
|
||||
var defaultLocalURL string
|
||||
switch Protocol {
|
||||
case UnixSocket:
|
||||
|
@ -645,8 +651,6 @@ func NewContext() {
|
|||
LandingPageURL = LandingPageHome
|
||||
}
|
||||
|
||||
ManifestData = makeManifestData()
|
||||
|
||||
if len(SSH.Domain) == 0 {
|
||||
SSH.Domain = Domain
|
||||
}
|
||||
|
@ -1045,12 +1049,74 @@ func loadOrGenerateInternalToken(sec *ini.Section) string {
|
|||
return token
|
||||
}
|
||||
|
||||
func makeManifestData() template.URL {
|
||||
name := url.QueryEscape(AppName)
|
||||
prefix := url.QueryEscape(StaticURLPrefix)
|
||||
subURL := url.QueryEscape(AppSubURL) + "/"
|
||||
// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
|
||||
func MakeAbsoluteAssetURL(appURL string, staticURLPrefix string) string {
|
||||
parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/"))
|
||||
if err != nil {
|
||||
log.Fatal("Unable to parse STATIC_URL_PREFIX: %v", err)
|
||||
}
|
||||
|
||||
return template.URL(`data:application/json,{"short_name":"` + name + `","name":"` + name + `","icons":[{"src":"` + prefix + `/img/logo-lg.png","type":"image/png","sizes":"880x880"},{"src":"` + prefix + `/img/logo-sm.png","type":"image/png","sizes":"120x120"},{"src":"` + prefix + `/img/logo-512.png","type":"image/png","sizes":"512x512"},{"src":"` + prefix + `/img/logo-192.png","type":"image/png","sizes":"192x192"}],"start_url":"` + subURL + `","scope":"` + subURL + `","background_color":"%23FAFAFA","display":"standalone"}`)
|
||||
if err == nil && parsedPrefix.Hostname() == "" {
|
||||
if staticURLPrefix == "" {
|
||||
return strings.TrimSuffix(appURL, "/")
|
||||
}
|
||||
|
||||
// StaticURLPrefix is just a path
|
||||
return strings.TrimSuffix(appURL, "/") + strings.TrimSuffix(staticURLPrefix, "/")
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(staticURLPrefix, "/")
|
||||
}
|
||||
|
||||
// MakeManifestData generates web app manifest JSON
|
||||
func MakeManifestData(appName string, appURL string, absoluteAssetURL string) []byte {
|
||||
type manifestIcon struct {
|
||||
Src string `json:"src"`
|
||||
Type string `json:"type"`
|
||||
Sizes string `json:"sizes"`
|
||||
}
|
||||
|
||||
type manifestJSON struct {
|
||||
Name string `json:"name"`
|
||||
ShortName string `json:"short_name"`
|
||||
StartURL string `json:"start_url"`
|
||||
Icons []manifestIcon `json:"icons"`
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(&manifestJSON{
|
||||
Name: appName,
|
||||
ShortName: appName,
|
||||
StartURL: appURL,
|
||||
Icons: []manifestIcon{
|
||||
{
|
||||
Src: absoluteAssetURL + "/img/logo-lg.png",
|
||||
Type: "image/png",
|
||||
Sizes: "880x880",
|
||||
},
|
||||
{
|
||||
Src: absoluteAssetURL + "/img/logo-512.png",
|
||||
Type: "image/png",
|
||||
Sizes: "512x512",
|
||||
},
|
||||
{
|
||||
Src: absoluteAssetURL + "/img/logo-192.png",
|
||||
Type: "image/png",
|
||||
Sizes: "192x192",
|
||||
},
|
||||
{
|
||||
Src: absoluteAssetURL + "/img/logo-sm.png",
|
||||
Type: "image/png",
|
||||
Sizes: "120x120",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Error("unable to marshal manifest JSON. Error: %v", err)
|
||||
return make([]byte, 0)
|
||||
}
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
// NewServices initializes the services
|
||||
|
|
29
modules/setting/setting_test.go
Normal file
29
modules/setting/setting_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMakeAbsoluteAssetURL(t *testing.T) {
|
||||
assert.Equal(t, "https://localhost:2345", MakeAbsoluteAssetURL("https://localhost:1234", "https://localhost:2345"))
|
||||
assert.Equal(t, "https://localhost:2345", MakeAbsoluteAssetURL("https://localhost:1234/", "https://localhost:2345"))
|
||||
assert.Equal(t, "https://localhost:2345", MakeAbsoluteAssetURL("https://localhost:1234/", "https://localhost:2345/"))
|
||||
assert.Equal(t, "https://localhost:1234/foo", MakeAbsoluteAssetURL("https://localhost:1234", "/foo"))
|
||||
assert.Equal(t, "https://localhost:1234/foo", MakeAbsoluteAssetURL("https://localhost:1234/", "/foo"))
|
||||
assert.Equal(t, "https://localhost:1234/foo", MakeAbsoluteAssetURL("https://localhost:1234/", "/foo/"))
|
||||
assert.Equal(t, "https://localhost:1234/foo/bar", MakeAbsoluteAssetURL("https://localhost:1234/foo", "/bar"))
|
||||
assert.Equal(t, "https://localhost:1234/foo/bar", MakeAbsoluteAssetURL("https://localhost:1234/foo/", "/bar"))
|
||||
assert.Equal(t, "https://localhost:1234/foo/bar", MakeAbsoluteAssetURL("https://localhost:1234/foo/", "/bar/"))
|
||||
}
|
||||
|
||||
func TestMakeManifestData(t *testing.T) {
|
||||
jsonBytes := MakeManifestData(`Example App '\"`, "https://example.com", "https://example.com/foo/bar")
|
||||
assert.True(t, json.Valid(jsonBytes))
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}} </title>
|
||||
<link rel="manifest" href="{{.ManifestData}}"/>
|
||||
<link rel="manifest" href="data:{{.ManifestData}}"/>
|
||||
<meta name="theme-color" content="{{ThemeColorMetaTag}}">
|
||||
<meta name="default-theme" content="{{DefaultTheme}}" />
|
||||
<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}" />
|
||||
|
|
Reference in a new issue