diff --git a/go.mod b/go.mod index 23bfb1aa..27c84202 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.25.0 // indirect gopkg.in/square/go-jose.v2 v2.5.0 // indirect + mvdan.cc/xurls/v2 v2.2.0 ) go 1.11 diff --git a/go.sum b/go.sum index 5121c96a..d39e76b1 100644 --- a/go.sum +++ b/go.sum @@ -331,6 +331,7 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -576,6 +577,9 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +mvdan.cc/xurls v1.1.0 h1:kj0j2lonKseISJCiq1Tfk+iTv65dDGCl0rTbanXJGGc= +mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= +mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/ui/static_manifest.go b/ui/static_manifest.go index 50e7e988..5c9183d7 100644 --- a/ui/static_manifest.go +++ b/ui/static_manifest.go @@ -14,6 +14,18 @@ import ( ) func (h *handler) showWebManifest(w http.ResponseWriter, r *http.Request) { + type webManifestShareTargetParams struct { + URL string `json:"url"` + Text string `json:"text"` + } + + type webManifestShareTarget struct { + Action string `json:"action"` + Method string `json:"method"` + Enctype string `json:"enctype"` + Params webManifestShareTargetParams `json:"params"` + } + type webManifestIcon struct { Source string `json:"src"` Sizes string `json:"sizes"` @@ -21,14 +33,15 @@ func (h *handler) showWebManifest(w http.ResponseWriter, r *http.Request) { } type webManifest struct { - Name string `json:"name"` - Description string `json:"description"` - ShortName string `json:"short_name"` - StartURL string `json:"start_url"` - Icons []webManifestIcon `json:"icons"` - Display string `json:"display"` - ThemeColor string `json:"theme_color"` - BackgroundColor string `json:"background_color"` + Name string `json:"name"` + Description string `json:"description"` + ShortName string `json:"short_name"` + StartURL string `json:"start_url"` + Icons []webManifestIcon `json:"icons"` + ShareTarget webManifestShareTarget `json:"share_target"` + Display string `json:"display"` + ThemeColor string `json:"theme_color"` + BackgroundColor string `json:"background_color"` } themeColor := model.ThemeColor(request.UserTheme(r)) @@ -45,6 +58,12 @@ func (h *handler) showWebManifest(w http.ResponseWriter, r *http.Request) { webManifestIcon{Source: route.Path(h.router, "appIcon", "filename", "icon-192.png"), Sizes: "192x192", Type: "image/png"}, webManifestIcon{Source: route.Path(h.router, "appIcon", "filename", "icon-512.png"), Sizes: "512x512", Type: "image/png"}, }, + ShareTarget: webManifestShareTarget{ + Action: route.Path(h.router, "bookmarklet"), + Method: http.MethodGet, + Enctype: "application/x-www-form-urlencoded", + Params: webManifestShareTargetParams{URL: "uri", Text: "text"}, + }, } json.OK(w, r, manifest) diff --git a/ui/subscription_bookmarklet.go b/ui/subscription_bookmarklet.go index 5ad6b2f2..01e4a8cc 100644 --- a/ui/subscription_bookmarklet.go +++ b/ui/subscription_bookmarklet.go @@ -13,6 +13,8 @@ import ( "miniflux.app/ui/form" "miniflux.app/ui/session" "miniflux.app/ui/view" + + "mvdan.cc/xurls/v2" ) func (h *handler) bookmarklet(w http.ResponseWriter, r *http.Request) { @@ -33,6 +35,17 @@ func (h *handler) bookmarklet(w http.ResponseWriter, r *http.Request) { bookmarkletURL := request.QueryStringParam(r, "uri", "") + // Extract URL from text supplied by Web Share Target API. + // + // This is because Android intents have no concept of URL, so apps + // just shove a URL directly into the EXTRA_TEXT intent field. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=789379. + text := request.QueryStringParam(r, "text", "") + if text != "" && bookmarkletURL == "" { + bookmarkletURL = xurls.Relaxed().FindString(text) + } + view.Set("form", form.SubscriptionForm{URL: bookmarkletURL}) view.Set("categories", categories) view.Set("menu", "feeds")