├── .editorconfig ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── go.mod ├── heroku.yml ├── main.go ├── modules ├── config │ └── config.go ├── proxy │ ├── http.go │ └── ws.go └── rewrites │ └── rewrites.go ├── ssl ├── localhost.crt └── localhost.key └── static ├── index.html ├── js └── inject.js └── robots.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{go,js}] 2 | charset = utf-8 3 | indent_style = tab 4 | indent_size = 4 5 | trim_trailing_whitespace = true 6 | insert_final_newline = false 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | go.sum 2 | config.yaml -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15-alpine AS build 2 | WORKDIR /src 3 | COPY * /src 4 | RUN CGO_ENABLED=0 go build -o proxy 5 | 6 | FROM scratch 7 | COPY --from=build /src/proxy /src/proxy 8 | ENTRYPOINT ["/src/proxy"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Ryan Wilson 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aurora Proxy 2 | A fast and powerful proxy made in go. This project is currently in beta. Anything you see here is subject to change. 3 | 4 | # Contributing Information 5 | Please send your changes through a pull request. Make sure you run gofmt before you commit your changes if you modify or create a go file. -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/titaniumnetwork-dev/Aurora 2 | 3 | require ( 4 | github.com/gobwas/httphead v0.1.0 5 | github.com/gobwas/pool v0.2.1 6 | github.com/gobwas/ws v1.0.4 7 | github.com/tdewolff/parse/v2 v2.5.11 8 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777 9 | gopkg.in/yaml.v2 v2.4.0 // indirect 10 | ) 11 | 12 | go 1.15 13 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | web: Dockerfile -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "net/http" 7 | 8 | "github.com/titaniumnetwork-dev/Aurora/modules/config" 9 | "github.com/titaniumnetwork-dev/Aurora/modules/proxy" 10 | "gopkg.in/yaml.v2" 11 | ) 12 | 13 | var err error 14 | 15 | func main() { 16 | file, err := ioutil.ReadFile("config.yaml") 17 | if err != nil { 18 | log.Fatal("You need to add a config") 19 | } 20 | 21 | err = yaml.Unmarshal(file, &config.YAML) 22 | 23 | if config.YAML.HTTPPrefix == "" { 24 | log.Fatal("You need to specify an http prefix") 25 | } else if config.YAML.WSPrefix == "" { 26 | log.Fatal("You need to specify an ws prefix") 27 | } else { 28 | http.HandleFunc(config.YAML.HTTPPrefix, proxy.HTTPServer) 29 | http.HandleFunc(config.YAML.WSPrefix, proxy.WSServer) 30 | // TODO: Serve main.html and use templates 31 | http.Handle("/", http.FileServer(http.Dir("./static"))) 32 | } 33 | 34 | if config.YAML.Port == "" { 35 | log.Fatal("You need to specify a port") 36 | } 37 | 38 | if config.YAML.Cert != "" && config.YAML.Key != "" { 39 | err = http.ListenAndServeTLS(config.YAML.Port, config.YAML.Cert, config.YAML.Key, nil) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | } else { 44 | err = http.ListenAndServe(config.YAML.Port, nil) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /modules/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "net/url" 4 | 5 | type yaml struct { 6 | BlockedDomains []string `yaml:"BlockedDomains"` 7 | BlockedHeaders []string `yaml:"BlockedHeaders"` 8 | BlockedUserAgents []string `yaml:"BlockedUserAgents"` 9 | 10 | // TODO: Support subdomains too 11 | HTTPPrefix string `yaml:"HTTPPrefix"` 12 | WSPrefix string `yaml:"WSPrefix"` 13 | 14 | /* 15 | var WRTCPrefixExists bool 16 | var WRTCPrefix String 17 | */ 18 | 19 | Port string `yaml:"Port"` 20 | 21 | Cert string `yaml:"Cert"` 22 | Key string `yaml:"Key"` 23 | 24 | Cap int64 `yaml:"Cap"` 25 | } 26 | 27 | var ( 28 | Scheme string 29 | URL *url.URL 30 | ProxyURL *url.URL 31 | 32 | YAML = yaml{} 33 | ) 34 | -------------------------------------------------------------------------------- /modules/proxy/http.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "io" 7 | "net/http" 8 | "net/url" 9 | "strings" 10 | "time" 11 | 12 | "github.com/titaniumnetwork-dev/Aurora/modules/config" 13 | "github.com/titaniumnetwork-dev/Aurora/modules/rewrites" 14 | ) 15 | 16 | // Server used for http proxy 17 | func HTTPServer(w http.ResponseWriter, r *http.Request) { 18 | var err error 19 | 20 | for _, userAgent := range config.YAML.BlockedUserAgents { 21 | if userAgent == r.UserAgent() { 22 | w.WriteHeader(http.StatusUnauthorized) 23 | fmt.Fprintf(w, "401, not authorized") 24 | return 25 | } 26 | } 27 | 28 | if r.TLS == nil { 29 | config.Scheme = "http" 30 | } else if r.TLS != nil { 31 | config.Scheme = "https" 32 | } 33 | 34 | config.URL, err = url.Parse(fmt.Sprintf("%s://%s%s", config.Scheme, r.Host, r.RequestURI)) 35 | if err != nil || config.URL.Scheme == "" || config.URL.Host == "" { 36 | w.WriteHeader(http.StatusInternalServerError) 37 | fmt.Fprintf(w, "500, %s", fmt.Sprintf("Unable to parse url, %s", config.ProxyURL.String())) 38 | return 39 | } 40 | 41 | proxyURLB64 := config.URL.Path[len(config.YAML.HTTPPrefix):] 42 | proxyURLBytes, err := base64.URLEncoding.DecodeString(proxyURLB64) 43 | if err != nil { 44 | w.WriteHeader(http.StatusInternalServerError) 45 | fmt.Fprintf(w, "500, %s", err) 46 | return 47 | } 48 | 49 | config.ProxyURL, err = url.Parse(string(proxyURLBytes)) 50 | if err != nil || config.ProxyURL.Scheme == "" || config.ProxyURL.Host == "" { 51 | w.WriteHeader(http.StatusInternalServerError) 52 | fmt.Fprintf(w, fmt.Sprintf("500, %s", fmt.Sprintf("Unable to parse url, %s", string(proxyURLBytes)))) 53 | return 54 | } 55 | 56 | for _, domain := range config.YAML.BlockedDomains { 57 | if domain == config.ProxyURL.Hostname() { 58 | w.WriteHeader(http.StatusUnauthorized) 59 | fmt.Fprintf(w, fmt.Sprintf("401, %s has been blocked", config.ProxyURL.Hostname())) 60 | return 61 | } 62 | } 63 | 64 | tr := &http.Transport{ 65 | IdleConnTimeout: 10 * time.Second, 66 | } 67 | 68 | client := &http.Client{Transport: tr} 69 | 70 | req, err := http.NewRequest("GET", config.ProxyURL.String(), nil) 71 | if err != nil { 72 | w.WriteHeader(http.StatusNotFound) 73 | fmt.Fprintf(w, "404, %s", err) 74 | return 75 | } 76 | 77 | for _, header := range config.YAML.BlockedHeaders { 78 | delete(r.Header, header) 79 | } 80 | for key, val := range r.Header { 81 | val = rewrites.Header(key, val) 82 | r.Header.Set(key, strings.Join(val, ", ")) 83 | } 84 | 85 | resp, err := client.Do(req) 86 | if err != nil { 87 | w.WriteHeader(http.StatusNotFound) 88 | fmt.Fprintf(w, "404, %s", err) 89 | return 90 | } 91 | defer resp.Body.Close() 92 | 93 | if config.YAML.Cap != 0 { 94 | http.MaxBytesReader(w, resp.Body, config.YAML.Cap) 95 | } 96 | 97 | for _, header := range config.YAML.BlockedHeaders { 98 | delete(resp.Header, header) 99 | } 100 | for key, val := range resp.Header { 101 | val = rewrites.Header(key, val) 102 | w.Header().Set(key, strings.Join(val, ", ")) 103 | } 104 | w.WriteHeader(resp.StatusCode) 105 | 106 | contentType := resp.Header.Get("Content-Type") 107 | if strings.HasPrefix(contentType, "text/html") { 108 | resp.Body = rewrites.HTML(resp.Body) 109 | } 110 | if strings.HasPrefix(contentType, "text/css") { 111 | respBodyInterface := rewrites.CSS(resp.Body) 112 | resp.Body = respBodyInterface.(io.ReadCloser) 113 | } 114 | // Currently low priority 115 | /* 116 | if strings.HasPrefix(contentType, "image/svg") { 117 | resp.Body = rewrites.SVG(resp.Body) 118 | } 119 | if strings.HasPrefix(contentType, "application/xml") strings.HasPrefix(contentType, "text/xml") { 120 | resp.Body = rewrites.XML(resp.Body) 121 | } 122 | */ 123 | 124 | io.Copy(w, resp.Body) 125 | } 126 | -------------------------------------------------------------------------------- /modules/proxy/ws.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | //"context" 5 | "fmt" 6 | //"github.com/gobwas/ws" 7 | //"github.com/gobwas/ws/wsutil" 8 | //"github.com/titaniumnetwork-dev/Aurora/modules/config" 9 | "net/http" 10 | ) 11 | 12 | // Server used for ws proxy 13 | // Even after this is done there are a lot of improvements to be made 14 | // Do not use pre-forwarding blocking or get information at that time 15 | // TODO: Send websocket error however that works 16 | func WSServer(w http.ResponseWriter, r *http.Request) { 17 | w.WriteHeader(http.StatusInternalServerError) 18 | fmt.Fprintf(w, "Websocket support is not finished yet") 19 | return 20 | /* 21 | conn, _, _, err := ws.UpgradeHTTP(r, w) 22 | if err != nil { 23 | log.Println(err) 24 | return 25 | } 26 | go func() { 27 | defer conn.Close() 28 | 29 | for { 30 | msg, op, err := wsutil.ReadClientData(serverConn) 31 | if err != nil { 32 | log.Println(err) 33 | return 34 | } 35 | 36 | // TODO: STtore something in proxy proxyurl variable 37 | proxyConn, _, _, err := ws.DefaultDialer.Dial(ctx, config.ProxyURL.String()) 38 | if err != nil { 39 | log.Println(err) 40 | return 41 | } 42 | 43 | proxyMsg, proxyOp, err = wsutil.ReadServerData(clientConn) 44 | if err != nil { 45 | log.Println(err) 46 | return 47 | } 48 | } 49 | }() 50 | */ 51 | } 52 | -------------------------------------------------------------------------------- /modules/rewrites/rewrites.go: -------------------------------------------------------------------------------- 1 | package rewrites 2 | 3 | import ( 4 | "github.com/tdewolff/parse/v2" 5 | "github.com/tdewolff/parse/v2/css" 6 | "github.com/titaniumnetwork-dev/Aurora/modules/config" 7 | "golang.org/x/net/html" 8 | 9 | // "encoding/xml" 10 | 11 | "encoding/base64" 12 | "fmt" 13 | "io" 14 | "io/ioutil" 15 | "net/url" 16 | "strings" 17 | ) 18 | 19 | // TODO: Start switching to using fmt.Sprintf() 20 | 21 | var err error 22 | 23 | // TODO: Continue adding more header rewrites until it's done 24 | func Header(key string, vals []string) []string { 25 | for i, val1 := range vals { 26 | split1 := strings.Split(val1, "; ") 27 | for j, val2 := range split1 { 28 | switch key { 29 | // Request headers 30 | case "Host": 31 | split2 := strings.Split(val2, ":") 32 | split2[0] = config.ProxyURL.Host 33 | val2 = strings.Join(split2, ":") 34 | // Response headers 35 | case "Set-Cookie": 36 | split2 := strings.Split(val2, "=") 37 | switch split2[0] { 38 | case "domain": 39 | split2[1] = config.URL.Hostname() 40 | case "path": 41 | split2[1] = config.YAML.HTTPPrefix + base64.URLEncoding.EncodeToString([]byte(config.ProxyURL.String())) 42 | } 43 | val2 = strings.Join(split2, "=") 44 | } 45 | split1[j] = val2 46 | } 47 | val1 = strings.Join(split1, "; ") 48 | vals[i] = val1 49 | } 50 | 51 | return vals 52 | } 53 | 54 | func internalHTML(key string, val string) string { 55 | if key == "href" || key == "src" || key == "poster" || key == "action" || key == "srcset" { 56 | url, err := url.Parse(val) 57 | if err != nil || url.Scheme == "" || url.Host == "" { 58 | split := strings.Split(val, "../") 59 | if len(split) >= 2 { 60 | val = split[len(split)-1] 61 | 62 | pSplit := strings.Split(config.ProxyURL.Path, "/") 63 | for i := 1; i <= len(pSplit); i++ { 64 | pSplit[len(pSplit)-i] = "" 65 | } 66 | 67 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%s://%s%s/%s", config.ProxyURL.Scheme, config.ProxyURL.Host, config.ProxyURL.Path[:len(strings.Join(pSplit, ""))], val)))) 68 | } else if strings.HasPrefix(val, "/") { 69 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%s://%s%s", config.ProxyURL.Scheme, config.ProxyURL.Host, val)))) 70 | } else { 71 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(config.ProxyURL.String()+val))) 72 | } 73 | } else { 74 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(val))) 75 | } 76 | } 77 | if key == "style" { 78 | valInterface := CSS(val) 79 | val = valInterface.(string) 80 | } 81 | attr := fmt.Sprintf(" %s=\"%s\"", key, val) 82 | return attr 83 | } 84 | 85 | func internalCSS(val string) string { 86 | url, err := url.Parse(val) 87 | if err != nil || url.Scheme == "" || url.Host == "" { 88 | split := strings.Split(val, "../") 89 | if len(split) >= 2 { 90 | val = split[len(split)-1] 91 | 92 | pSplit := strings.Split(config.ProxyURL.Path, "/") 93 | for i := 1; i <= len(pSplit); i++ { 94 | pSplit[len(pSplit)-i] = "" 95 | } 96 | 97 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%s://%s%s/%s", config.ProxyURL.Scheme, config.ProxyURL.Host, config.ProxyURL.Path[:len(strings.Join(pSplit, ""))], val)))) 98 | } else if strings.HasPrefix(val, "/") { 99 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%s://%s%s", config.ProxyURL.Scheme, config.ProxyURL.Host, val)))) 100 | } else { 101 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(config.ProxyURL.String()+val))) 102 | } 103 | } else { 104 | val = fmt.Sprintf("%s://%s%s%s", config.Scheme, config.URL.Host, config.YAML.HTTPPrefix, base64.URLEncoding.EncodeToString([]byte(val))) 105 | } 106 | 107 | return val 108 | } 109 | 110 | func HTML(body io.ReadCloser) io.ReadCloser { 111 | tokenizer := html.NewTokenizer(body) 112 | out := "" 113 | 114 | for { 115 | tokenType := tokenizer.Next() 116 | token := tokenizer.Token() 117 | 118 | err := tokenizer.Err() 119 | if err == io.EOF { 120 | break 121 | } 122 | 123 | switch tokenType { 124 | case html.TextToken: 125 | if string(tokenizer.Text()) == "style" { 126 | valInterface := CSS(token.Data) 127 | val := valInterface.(string) 128 | token.Data = val 129 | } 130 | out += token.Data 131 | case html.StartTagToken: 132 | attr := "" 133 | for _, elm := range token.Attr { 134 | attrSel := internalHTML(elm.Key, elm.Val) 135 | attr += attrSel 136 | } 137 | 138 | out += fmt.Sprintf("<%s%s>", token.Data, attr) 139 | 140 | if token.Data == "head" { 141 | out += fmt.Sprintf("", base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("{\"url\":\"%s\",\"proxyurl\":\"%s\",\"httpprefix\":\"%s\",\"wsprefix\":\"%s\"}", config.URL.String(), config.ProxyURL.String(), config.YAML.HTTPPrefix, config.YAML.WSPrefix)))) 142 | } 143 | if token.Data == "html" { 144 | // Temporary solution 145 | // TODO: Doesn't work; fix 146 | // token.Attr = append("id", "domsel") 147 | } 148 | case html.SelfClosingTagToken: 149 | attr := "" 150 | for _, elm := range token.Attr { 151 | attrSel := internalHTML(elm.Key, elm.Val) 152 | attr += attrSel 153 | } 154 | 155 | out += fmt.Sprintf("<%s%s/>", token.Data, attr) 156 | default: 157 | out += token.String() 158 | } 159 | } 160 | 161 | body = ioutil.NopCloser(strings.NewReader(out)) 162 | body.Close() 163 | return body 164 | } 165 | 166 | func CSS(bodyInterface interface{}) interface{} { 167 | var tokenizer *css.Lexer 168 | switch bodyInterface.(type) { 169 | case string: 170 | body := bodyInterface.(string) 171 | tokenizer = css.NewLexer(parse.NewInput(strings.NewReader(body))) 172 | default: 173 | body := bodyInterface.(io.ReadCloser) 174 | tokenizer = css.NewLexer(parse.NewInput(body)) 175 | } 176 | 177 | out := "" 178 | 179 | for { 180 | tokenType, token := tokenizer.Next() 181 | 182 | err = tokenizer.Err() 183 | if err == io.EOF { 184 | break 185 | } 186 | 187 | tokenStr := string(token) 188 | switch tokenType { 189 | case css.URLToken: 190 | val := strings.Replace(tokenStr, "url(", "", 4) 191 | val = strings.Replace(val, ")", "", 1) 192 | val = internalCSS(val) 193 | 194 | out += fmt.Sprintf("url(%s)", val) 195 | default: 196 | out += tokenStr 197 | } 198 | } 199 | 200 | switch bodyInterface.(type) { 201 | case string: 202 | return out 203 | default: 204 | body := ioutil.NopCloser(strings.NewReader(out)) 205 | body.Close() 206 | return body 207 | } 208 | } 209 | 210 | // Low Priority 211 | 212 | // TODO: Add xml rewrites for external entities 213 | // Use https://golang.org/pkg/encoding/xml/ 214 | 215 | // TODO: Add svg rewrites 216 | // Use https://github.com/rustyoz/svg/ 217 | -------------------------------------------------------------------------------- /ssl/localhost.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5TCCAc2gAwIBAgIJAPOlcQn7UEJWMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV 3 | BAMMCWxvY2FsaG9zdDAeFw0yMTAzMDQwNzQ4NTVaFw0yMTA0MDMwNzQ4NTVaMBQx 4 | EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBALBRoIq2hue8MOj4javrOowui80W1jKMN9sRa8mgNOs8jx8ZR96crV51jrPj 6 | mF6k+9+txxJgKBf3P/AtyDqryWt8PeSRlGR6jaqskAsbAQ/yGLwhpPpSwUeCcjuD 7 | nigb5zhjAmC34SZ5Y0d+cmNGwqNPSIpIroTc7/cXlOUwL4Su0fEjyu96ww63rjzE 8 | YUrOXqRaaNwBJkTKy/zZZbqPeudmFOeZCFJGyxJZsyoeTNjmk4aRtOeZjTPtmJKo 9 | 9McKpoM+fP9FE+lWSdK6by9UQXrBNSLBOswk/myIWpa8yjZfqq8ICotYJInNhnaB 10 | ZW2hy9WK8sXV73lfxeqxjISxZ4MCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo 11 | b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B 12 | AQsFAAOCAQEAhedRoXgthlyiTDz0DmJLOtSqehuiiIm/ltNjC5+vY/DQHTELE7vi 13 | LI+hjpi4GyWoOajmKlddWxuPmaXxMQq4YTc8c/oWwtcMAUBNHQHXcbWmGl2/h+Jf 14 | O7nO2kiWMfQohMnVElBFaPFuI5Gm4lbQF2Ckww9UiWkFQqUjD0yTBF3yudIZP6vE 15 | ng5QUquvtf7BK1nwwuLJ/qC5YPFJqT3Ksifz7L49UKAU/xbzDWLQ5kGirfGZ0Ppd 16 | Cd9YyH5GvPw2xZlS8Ol40/ubQZS/vgBY/izVzIg7sy0I3dsrolqqrJV3HI5DX/QS 17 | g3bAKWeAX9f0DgK4eiEnhnJJYc1J5ryF6g== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /ssl/localhost.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwUaCKtobnvDDo 3 | +I2r6zqMLovNFtYyjDfbEWvJoDTrPI8fGUfenK1edY6z45hepPvfrccSYCgX9z/w 4 | Lcg6q8lrfD3kkZRkeo2qrJALGwEP8hi8IaT6UsFHgnI7g54oG+c4YwJgt+EmeWNH 5 | fnJjRsKjT0iKSK6E3O/3F5TlMC+ErtHxI8rvesMOt648xGFKzl6kWmjcASZEysv8 6 | 2WW6j3rnZhTnmQhSRssSWbMqHkzY5pOGkbTnmY0z7ZiSqPTHCqaDPnz/RRPpVknS 7 | um8vVEF6wTUiwTrMJP5siFqWvMo2X6qvCAqLWCSJzYZ2gWVtocvVivLF1e95X8Xq 8 | sYyEsWeDAgMBAAECggEAU7ofY19zxn1uOGM3W0kznzfHOVe71XsSVxv5tGA4YPB8 9 | AkeOAl8iULXAUxoj0+XCmaA65TX2NBM8MIB9Eadb2YfBGFYtQl2UAlU5fZyQL5NG 10 | Pag4YIqFr8B5IFvK8b72WKdjjKwk5ZFFHMEl7pC+grB2gPwsq3kDFrIDCaaNGhLk 11 | ZE4JgbAI0rEUV3lY+utaRVieVv3Sz1Sr6nJLMsSiogi1j/cLKi4THZudR3fuIKhe 12 | hgIS16KnbrCg4c0FI0ajc5CIL/HBScCTLza1jfBco8TkCOd7hHoWV5EX5Dcd600t 13 | ZZWD/j1VFvjZSwkq8xLh6bk9IVGBo+/6dN+ceGlIQQKBgQDWJcHF94jw0UuOdpPi 14 | mjUdnMDJPsE2CNkyaDppeNV/R66SC3d7hsfwAayGyWLwwerCozwLMt2Xrd8bIZXh 15 | QD5Db0aiYToXEYaqpgEMs3J4skbnQz7GZkuoHbHSooZbQAWt2AJEItAFIhCNXj0l 16 | pxeKMjk+JqeDBQIyxR12jXGgIQKBgQDSxzmqFyZB7Q45e+UoZ9Q/v7j7waPaPrIL 17 | Ta28yOWTwejJuJC0zdq6n+SAh1ncXEqegD1lx0eYGUBZ3n87TgqHNGlXYGPNKUP8 18 | lyTsrtFaMTkEMeNm/4NaSsuk9MWdBBimv8CGMLdHhU2CVm0mEUQbBTTwykN/t1HZ 19 | fPhwjMQjIwKBgQDAURg8mZk57DxWrNcS4jphZa0dDmamCDxGsKQEpKfXrqBwOCwN 20 | m3VjbZ1rTuC0JvKV6dK6m+u1lEiRLRBVQkSoev6MRZTNssel6X930JA1JKXYeuOd 21 | ebDoQgK4j4zp1g1DmoIufrUiZv1GeCOh9PWG/qO51S0K1SysO6nCFjS9AQKBgQDO 22 | mOInmusv4Vh49byG30aGebiqY4HkUGGZfLkXet6z9nPjDRohbki/diu143Ur7fZh 23 | 55bGpQ7CwbV2oQSar4LYRYIfV+Za2OC/u7JAn5WqTubw+qlHcplgLkHvXNA5eCNl 24 | hjwCC8wJuVpgr6/qiS/1QCRFBCwnChubDshBIWi6ewKBgDWHt6/Qgt9B0glkcraw 25 | RHZrYyOqnWRaCt18lDXk5NvMllWZC9MYs6YPpDe7QMWXtOdPOvVowMtGS2xKRV5t 26 | fdRDNdPhhEDfRyu8QPaREFIfZta6Gp6A3PbMowswKF02y9u02BLa9BkD1ovPmXtM 27 | hvQMuMndywxK+gewjVgdpuJx 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 |