internal/httpd/aasa.go

69 lines · 2686 bytes

3 symbols in this file
 1package httpd
 2
 3import (
 4	"encoding/json"
 5	"net/http"
 6)
 7
 8// aasaComponent is one applinks path pattern. iOS takes the first
 9// component that matches; * matches any run of characters, slashes
10// included, and ? matches one.
11type aasaComponent struct {
12	Path    string `json:"/"`
13	Exclude bool   `json:"exclude,omitempty"`
14}
15
16// aasaComponents lists the pages the iOS app opens. Web-only pages come
17// first as exclusions, then the repository sections the app has screens
18// for; anything else of three or more segments stays in the browser,
19// and what is left is an owner or a repository.
20var aasaComponents = func() []aasaComponent {
21	var c []aasaComponent
22	for _, p := range []string{
23		"/.well-known/*", "/static/*", "/api/*", "/admin", "/admin/*",
24		"/settings", "/settings/*", "/login", "/logout", "/register",
25		"/new", "/explore", "/search", "/healthz", "/privacy", "/favicon.svg",
26		"/*/activity.atom", "/*/*/releases.atom", "/*/*/log.atom", "/*/*/log.atom/*",
27		"/*/-/queries", "/*/-/queries/*", "/*/-/snippets/new", "/*/-/snippets/*/raw/*",
28		"/*/*/settings", "/*/*/fork", "/*/*/search", "/*/*/symbols",
29		"/*/*/issues/new", "/*/*/mrs/new", "/*/*/mrs/*/range-diff",
30		"/*/*/edit/*", "/*/*/raw/*", "/*/*/archive/*", "/*/*/releases/download/*",
31		"/*/*/badge/*", "/*/*/wiki/_raw/*", "/*/*/compare/*", "/*/*/info/*",
32	} {
33		c = append(c, aasaComponent{Path: p, Exclude: true})
34	}
35	for _, p := range []string{
36		"/bookmarks", "/notifications",
37		"/*/-/repositories", "/*/-/bookmarks", "/*/-/people", "/*/-/labels",
38		"/*/-/milestones", "/*/-/snippets", "/*/-/snippets/*",
39		"/*/*/issues", "/*/*/issues/*", "/*/*/mrs", "/*/*/mrs/*",
40		"/*/*/builds", "/*/*/builds/*", "/*/*/tree/*", "/*/*/blob/*",
41		"/*/*/blame/*", "/*/*/commit/*", "/*/*/log", "/*/*/log/*",
42		"/*/*/refs", "/*/*/compare", "/*/*/releases", "/*/*/milestones",
43		"/*/*/labels", "/*/*/wiki", "/*/*/wiki/*",
44	} {
45		c = append(c, aasaComponent{Path: p})
46	}
47	return append(c,
48		aasaComponent{Path: "/*/*/?*", Exclude: true},
49		aasaComponent{Path: "/?*"},
50	)
51}()
52
53// appleAppSiteAssociation serves the file iOS fetches to decide which
54// links open the app ([web] apple_app_ids). Apple requires JSON at this
55// exact path with no redirect.
56func (s *Server) appleAppSiteAssociation(w http.ResponseWriter, r *http.Request) {
57	type detail struct {
58		AppIDs     []string        `json:"appIDs"`
59		Components []aasaComponent `json:"components"`
60	}
61	var doc struct {
62		Applinks struct {
63			Details []detail `json:"details"`
64		} `json:"applinks"`
65	}
66	doc.Applinks.Details = []detail{{AppIDs: s.cfg.Web.AppleAppIDs, Components: aasaComponents}}
67	w.Header().Set("Content-Type", "application/json")
68	json.NewEncoder(w).Encode(doc)
69}