oficina / home Public

Clone
git clone https://amadan.net/oficina/home

Plain git — no account needed to clone.

Download

Download this file

1package home
2
3import (
4 "errors"
5 "net"
6 "net/http"
7 "net/url"
8 "os"
9 "strings"
10)
11
12const (
13 suiteDomain = "oficina.works"
14 credentialHost = "id." + suiteDomain
15 directoryHost = suiteDomain
16 directoryOrigin = "https://" + directoryHost
17)
18
19var errOrigins = errors.New("home: invalid origin configuration")
20
21type Origins struct {
22 Credential string
23 Directory string
24}
25
26func LoadOrigins() (Origins, error) {
27 credential, haveCredential := os.LookupEnv("HOME_CREDENTIAL_ORIGIN")
28 directory, haveDirectory := os.LookupEnv("HOME_DIRECTORY_ORIGIN")
29 if !haveCredential && !haveDirectory {
30 return Origins{Origin, directoryOrigin}, nil
31 }
32 origins := Origins{credential, directory}
33 if !haveCredential || !haveDirectory {
34 return Origins{}, errOrigins
35 }
36 return origins, origins.validate()
37}
38
39func originHost(origin string) (string, error) {
40 u, err := url.Parse(origin)
41 if err != nil || u.Scheme != "https" || u.User != nil || u.Host == "" || origin != "https://"+u.Host || u.Host != strings.ToLower(u.Host) || net.ParseIP(u.Host) != nil {
42 return "", errOrigins
43 }
44 if len(u.Host) > 253 {
45 return "", errOrigins
46 }
47 labels := strings.Split(u.Host, ".")
48 if len(labels) < 2 {
49 return "", errOrigins
50 }
51 for _, label := range labels {
52 if len(label) == 0 || len(label) > 63 || label[0] == '-' || label[len(label)-1] == '-' {
53 return "", errOrigins
54 }
55 for _, c := range label {
56 if !(c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '-') {
57 return "", errOrigins
58 }
59 }
60 }
61 return u.Host, nil
62}
63
64func (o Origins) validate() error {
65 credential, err := originHost(o.Credential)
66 if err != nil {
67 return err
68 }
69 directory, err := originHost(o.Directory)
70 if err != nil {
71 return err
72 }
73 if directory == credential || strings.HasSuffix(directory, "."+credential) {
74 return errOrigins
75 }
76 if o.Credential == Origin && o.Directory == directoryOrigin {
77 return nil
78 }
79 for _, host := range []string{credential, directory} {
80 if host == directoryHost || host == credentialHost || strings.HasSuffix(host, "."+credentialHost) {
81 return errOrigins
82 }
83 }
84 return nil
85}
86
87func (a *App) serveKnownHost(next http.Handler) http.Handler {
88 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
89 host := strings.ToLower(r.Host)
90 if a.runtime != nil && ((a.runtime.role == "credential" && host != a.credentialHost) || (a.runtime.role == "directory" && host != a.directoryHost)) {
91 w.WriteHeader(http.StatusNotFound)
92 return
93 }
94 if host != a.credentialHost && host != a.directoryHost {
95 w.WriteHeader(http.StatusNotFound)
96 return
97 }
98 next.ServeHTTP(w, r)
99 })
100}
101
102func (a *App) credentialOnly(next http.Handler) http.Handler {
103 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
104 if strings.ToLower(r.Host) != a.credentialHost {
105 w.WriteHeader(http.StatusNotFound)
106 return
107 }
108 next.ServeHTTP(w, r)
109 })
110}
111