33 Commits

Author SHA1 Message Date
bel
f083763f1d there we go 2024-03-10 11:17:48 -06:00
bel
abf628d2bb proxy2 does auth inline 2024-03-10 11:08:51 -06:00
bel
fb6d7af6d3 from gogs to gitea 2024-03-10 09:54:05 -06:00
bel
9941706b73 trivial 2024-03-10 09:51:29 -06:00
Bel LaPointe
fb30cc8436 to gogs.inhome 2023-04-10 11:18:10 -06:00
bel
c8330aab26 NOW go mod 2022-10-25 22:42:05 -06:00
bel
32891c518c go mod 2022-10-25 22:40:00 -06:00
bel
00591f5dde meta access log to stdout 2022-05-26 20:04:00 -06:00
bel
56a74a2767 add access log 2022-05-26 20:03:35 -06:00
bel
0eea3e787c ifnot proxied, then call WriteHeader to ensure CORS 2022-05-26 19:34:12 -06:00
bel
38f19408c2 cors ensures only ONE access control allow origin header set 2022-05-26 19:04:28 -06:00
Bel LaPointe
f28211e722 impl trim 2022-01-11 15:58:27 -05:00
Bel LaPointe
ef3abbbf07 authelia attempt failed 2021-04-18 12:20:19 -05:00
Bel LaPointe
af240639cb backend gets cookie identifying user 2021-03-21 13:12:11 -05:00
Bel LaPointe
c623792c2f NOW authelia supported 2021-03-21 13:03:04 -05:00
Bel LaPointe
cebb518e05 impl authelia I think 2021-03-21 12:44:21 -05:00
Bel LaPointe
177e0d88da dont rewrite 2020-07-31 23:15:58 -06:00
Bel LaPointe
9b0bccd9ca CORS for DELETE 2020-07-25 19:32:59 -06:00
Bel LaPointe
1af274dc1d Add redirect things for dumb js apps 2020-07-25 02:28:57 -06:00
Bel LaPointe
ec1e0cdf2e Add nopath for vue things 2020-07-25 02:23:04 -06:00
Bel LaPointe
61811e8e61 Listen on second port and redirect to main 2020-02-14 14:57:26 -07:00
bel
c4c37068f3 New oauth2client 2019-12-31 11:21:15 -07:00
bel
d71b00e067 Fix 2019-11-06 19:00:56 -07:00
Bel LaPointe
d98703610d remove unused and rename 2019-11-03 07:56:43 -07:00
Bel LaPointe
01b7b06971 Optional oauth via + flag 2019-11-03 07:55:38 -07:00
Bel LaPointe
7d3d6d88f6 Re-enable config files 2019-11-03 07:45:23 -07:00
Bel LaPointe
8c415f2a39 Update to scoped oauth 2019-11-02 08:03:35 -06:00
Bel LaPointe
df0232e24c Create dockerfile from dockerize.do and test WS 2019-11-02 07:26:58 -06:00
bel
bc11dd7f82 change conf to argsset and flag for oauth 2019-10-22 05:03:53 +00:00
bel
e20ba5361d about to replace config and storage with shared package 2019-10-22 02:36:59 +00:00
Bel LaPointe
8a90a3adda Implement tcp proxy with single forward 2019-10-02 09:07:59 -06:00
Bel LaPointe
698edf7e45 insecure skip verify 2019-09-24 12:47:06 -06:00
Bel LaPointe
48e0048216 no more logger 2019-05-02 09:35:53 -06:00
33 changed files with 767 additions and 409 deletions

4
.gitignore vendored Normal file → Executable file
View File

@@ -1,6 +1,10 @@
lz4
rclone
rcloner
exec
exec-*
**/exec
**/exec-*
Go
cloudly
dockfile

16
Dockerfile Executable file
View File

@@ -0,0 +1,16 @@
FROM golang:1.13-alpine as certs
RUN apk update && apk add --no-cache ca-certificates
FROM busybox:glibc
RUN mkdir -p /var/log
WORKDIR /main
COPY --from=certs /etc/ssl/certs /etc/ssl/certs
COPY . .
ENV GOPATH=""
ENV MNT="/mnt/"
ENTRYPOINT ["/main/exec-rproxy3"]
CMD []

View File

@@ -1,11 +0,0 @@
p: 54243
r:
- echo:http://localhost:49982
- echo2:http://192.168.0.86:38090
#crt: ./testdata/rproxy3server.crt
#key: ./testdata/rproxy3server.key
#user: bel
#pass: bel
rate: 1
burst: 2
timeout: 10

183
config/config.go Normal file → Executable file
View File

@@ -1,118 +1,127 @@
package config
import (
"local/rproxy3/storage/packable"
"encoding/json"
"fmt"
"log"
"strconv"
"regexp"
"strings"
"time"
"gopkg.in/yaml.v2"
)
func GetPort() string {
v := packable.NewString()
conf.Get(nsConf, flagPort, v)
return ":" + strings.TrimPrefix(v.String(), ":")
type Proxy struct {
Auth string
To string
}
func GetRoutes() map[string]string {
v := packable.NewString()
conf.Get(nsConf, flagRoutes, v)
m := make(map[string]string)
for _, v := range strings.Split(v.String(), ",") {
if len(v) == 0 {
return m
}
from := v[:strings.Index(v, ":")]
to := v[strings.Index(v, ":")+1:]
m[from] = to
func parseOneProxyCSV(s string) (string, Proxy) {
p := Proxy{}
key := ""
l := strings.Split(s, ",")
if len(l) > 0 {
key = l[0]
}
return m
}
func GetSSL() (string, string, bool) {
v := packable.NewString()
conf.Get(nsConf, flagCert, v)
certPath := v.String()
conf.Get(nsConf, flagKey, v)
keyPath := v.String()
return certPath, keyPath, notEmpty(certPath, keyPath)
if len(l) > 1 {
p.To = l[1]
}
return key, p
}
func GetAuth() (string, string, bool) {
v := packable.NewString()
conf.Get(nsConf, flagUser, v)
user := v.String()
conf.Get(nsConf, flagPass, v)
pass := v.String()
return user, pass, notEmpty(user, pass)
user := conf.Get("user").GetString()
pass := conf.Get("pass").GetString()
return user, pass, user != "" && pass != ""
}
func notEmpty(s ...string) bool {
for i := range s {
if s[i] == "" || s[i] == "/dev/null" {
return false
}
}
return true
func GetTrim() string {
return conf.Get("trim").GetString()
}
func GetPort() string {
port := conf.Get("p").GetInt()
return ":" + fmt.Sprint(port)
}
func GetAltPort() string {
port := conf.Get("ap").GetInt()
return ":" + fmt.Sprint(port)
}
func GetRate() (int, int) {
r := packable.NewString()
conf.Get(nsConf, flagRate, r)
b := packable.NewString()
conf.Get(nsConf, flagBurst, b)
rate, err := strconv.Atoi(r.String())
if err != nil {
log.Printf("illegal rate: %v", err)
rate = 5
}
burst, _ := strconv.Atoi(b.String())
if err != nil {
log.Printf("illegal burst: %v", err)
burst = 5
}
rate := conf.Get("r").GetInt()
burst := conf.Get("b").GetInt()
log.Println("rate/burst:", rate, burst)
return rate, burst
}
func GetTimeout() int {
t := packable.NewString()
conf.Get(nsConf, flagTimeout, t)
timeout, err := strconv.Atoi(t.String())
if err != nil || timeout == 5 {
return 5
func GetRoutes() map[string]Proxy {
s := conf.Get("proxy2").GetString()
var dict map[string]string
if err := yaml.Unmarshal([]byte(s), &dict); err == nil && len(s) > 0 {
pattern := regexp.MustCompile(`(([^:]*):)?([a-z0-9]*:.*)`)
result := map[string]Proxy{}
for k, v := range dict {
submatches := pattern.FindAllStringSubmatch(v, -1)
log.Printf("%+v", submatches)
result[k] = Proxy{
Auth: submatches[0][2],
To: submatches[0][3],
}
}
return result
}
return getRoutesCSV()
}
func getRoutesCSV() map[string]Proxy {
list := conf.Get("proxy2").GetString()
definitions := strings.Split(list, ",,")
routes := make(map[string]Proxy)
for _, definition := range definitions {
k, v := parseOneProxyCSV(definition)
routes[k] = v
}
return routes
}
func GetSSL() (string, string, bool) {
crt := conf.Get("crt").GetString()
key := conf.Get("key").GetString()
return crt, key, crt != "" && key != ""
}
func GetTCP() (string, bool) {
tcp := conf.Get("tcp").GetString()
return tcp, tcp != ""
}
func GetTimeout() time.Duration {
timeout := conf.Get("timeout").GetDuration()
return timeout
}
func GetRewrites(hostMatch string) map[string]string {
v := packable.NewString()
conf.Get(nsConf, flagRewrites, v)
m := make(map[string]string)
for _, v := range strings.Split(v.String(), ",") {
vs := strings.Split(v, ":")
if len(v) < 3 {
continue
}
host := vs[0]
if host != hostMatch {
continue
}
from := vs[1]
to := strings.Join(vs[2:], ":")
m[from] = to
func GetCORS(key string) bool {
cors := conf.GetString("cors")
var m map[string]bool
if err := json.Unmarshal([]byte(cors), &m); err != nil {
return false
}
return m
_, ok := m[key]
return ok
}
func GetProxyMode() string {
v := packable.NewString()
conf.Get(nsConf, flagMode, v)
s := v.String()
if s == "" {
return "domain"
func GetNoPath(key string) bool {
nopath := conf.GetString("nopath")
var m map[string]bool
if err := json.Unmarshal([]byte(nopath), &m); err != nil {
return false
}
return s
_, ok := m[key]
return ok
}
func GetCompression() bool {
return conf.GetBool("compression")
}

180
config/new.go Normal file → Executable file
View File

@@ -1,161 +1,61 @@
package config
import (
"flag"
"io/ioutil"
"local/rproxy3/storage"
"local/rproxy3/storage/packable"
"fmt"
"log"
"os"
"strings"
"time"
yaml "gopkg.in/yaml.v2"
"gitea.inhome.blapointe.com/local/args"
"gitea.inhome.blapointe.com/local/logb"
)
const nsConf = "configuration"
const flagPort = "p"
const flagMode = "mode"
const flagRoutes = "r"
const flagConf = "c"
const flagCert = "crt"
const flagKey = "key"
const flagUser = "user"
const flagPass = "pass"
const flagRate = "rate"
const flagBurst = "burst"
const flagTimeout = "timeout"
const flagRewrites = "rw"
var conf *args.ArgSet
var conf = storage.NewMap()
type toBind struct {
flag string
value *string
func init() {
if err := Refresh(); err != nil {
panic(err)
}
}
type fileConf struct {
Port string `yaml:"p"`
Mode string `yaml:"mode"`
Routes []string `yaml:"r"`
CertPath string `yaml:"crt"`
KeyPath string `yaml:"key"`
Username string `yaml:"user"`
Password string `yaml:"pass"`
Rate string `yaml:"rate"`
Burst string `yaml:"burst"`
Timeout string `yaml:"timeout"`
Rewrites []string `yaml:"rw"`
}
func Init() error {
func Refresh() error {
log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
log.SetFlags(log.Ltime | log.Lshortfile)
if err := fromFile(); err != nil {
return err
}
if err := fromFlags(); err != nil {
as, err := parseArgs()
if err != nil && !strings.Contains(fmt.Sprint(os.Args), "-test") {
return err
}
conf = as
logb.Set(logb.LevelFromString(as.GetString("level")))
return nil
}
func fromFile() error {
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
defer func() {
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
}()
flag.String(flagConf, "/dev/null", "yaml config file path")
flag.Parse()
confFlag := flag.Lookup(flagConf)
if confFlag == nil || confFlag.Value.String() == "" {
return nil
func parseArgs() (*args.ArgSet, error) {
configFiles := []string{}
if v, ok := os.LookupEnv("CONFIG"); ok {
configFiles = strings.Split(v, ",")
}
confBytes, err := ioutil.ReadFile(confFlag.Value.String())
if err != nil {
return err
}
var c fileConf
if err := yaml.Unmarshal(confBytes, &c); err != nil {
return err
}
if err := conf.Set(nsConf, flagPort, packable.NewString(c.Port)); err != nil {
return err
}
if err := conf.Set(nsConf, flagMode, packable.NewString(c.Mode)); err != nil {
return err
}
if err := conf.Set(nsConf, flagRoutes, packable.NewString(strings.Join(c.Routes, ","))); err != nil {
return err
}
if err := conf.Set(nsConf, flagCert, packable.NewString(c.CertPath)); err != nil {
return err
}
if err := conf.Set(nsConf, flagKey, packable.NewString(c.KeyPath)); err != nil {
return err
}
if err := conf.Set(nsConf, flagUser, packable.NewString(c.Username)); err != nil {
return err
}
if err := conf.Set(nsConf, flagPass, packable.NewString(c.Password)); err != nil {
return err
}
if err := conf.Set(nsConf, flagRate, packable.NewString(c.Rate)); err != nil {
return err
}
if err := conf.Set(nsConf, flagBurst, packable.NewString(c.Burst)); err != nil {
return err
}
if err := conf.Set(nsConf, flagTimeout, packable.NewString(c.Timeout)); err != nil {
return err
}
if err := conf.Set(nsConf, flagRewrites, packable.NewString(strings.Join(c.Rewrites, ","))); err != nil {
return err
}
return nil
}
func fromFlags() error {
binds := make([]toBind, 0)
binds = append(binds, addFlag(flagPort, "51555", "port to bind to"))
binds = append(binds, addFlag(flagMode, "domain", "[domain] or [path] to match"))
binds = append(binds, addFlag(flagConf, "", "configuration file path"))
binds = append(binds, addFlag(flagRoutes, "", "comma-separated routes to map, each as from:scheme://to.tld:port"))
binds = append(binds, addFlag(flagCert, "", "path to .crt"))
binds = append(binds, addFlag(flagKey, "", "path to .key"))
binds = append(binds, addFlag(flagUser, "", "basic auth username"))
binds = append(binds, addFlag(flagPass, "", "basic auth password"))
binds = append(binds, addFlag(flagRate, "100", "rate limit per second"))
binds = append(binds, addFlag(flagBurst, "100", "rate limit burst"))
binds = append(binds, addFlag(flagTimeout, "30", "seconds to wait for limiter"))
binds = append(binds, addFlag(flagRewrites, "", "comma-separated from:replace:replacement to rewrite in response bodies"))
flag.Parse()
for _, bind := range binds {
confFlag := flag.Lookup(bind.flag)
if confFlag == nil || confFlag.Value.String() == "" {
continue
}
if err := conf.Set(nsConf, bind.flag, packable.NewString(*bind.value)); err != nil {
return err
}
}
return nil
}
func addFlag(key, def, help string) toBind {
def = getFlagOrDefault(key, def)
v := flag.String(key, def, help)
return toBind{
flag: key,
value: v,
}
}
func getFlagOrDefault(key, def string) string {
v := packable.NewString()
if err := conf.Get(nsConf, key, v); err != nil {
return def
}
return v.String()
as := args.NewArgSet(configFiles...)
as.Append(args.STRING, "user", "username for basic auth", "")
as.Append(args.STRING, "pass", "password for basic auth", "")
as.Append(args.INT, "p", "port for service", 51555)
as.Append(args.INT, "ap", "alt port for always http service", 51556)
as.Append(args.INT, "r", "rate per second for requests", 100)
as.Append(args.INT, "b", "burst requests", 100)
as.Append(args.BOOL, "compress", "enable compression", true)
as.Append(args.STRING, "crt", "path to crt for ssl", "")
as.Append(args.STRING, "key", "path to key for ssl", "")
as.Append(args.STRING, "trim", "path prefix to trim, like '/abc' to change '/abc/def' to '/def'", "")
as.Append(args.STRING, "tcp", "address for tcp only tunnel", "")
as.Append(args.DURATION, "timeout", "timeout for tunnel", time.Minute)
as.Append(args.STRING, "proxy2", "double-comma separated 'from,scheme://to.tld:port,,' OR a yaml dictionary of 'from: (password:)scheme://to.tld:port'", "")
as.Append(args.STRING, "cors", "json dict key:true for keys to set CORS permissive headers, like {\"from\":true}", "{}")
as.Append(args.STRING, "nopath", "json dict key:true for keys to remove all path info from forwarded request, like -cors", "{}")
as.Append(args.STRING, "level", "log level", "info")
err := as.Parse()
return as, err
}

View File

@@ -1,46 +0,0 @@
package config
import (
"flag"
"os"
"testing"
)
func TestInit(t *testing.T) {
was := os.Args[:]
os.Args = []string{"program"}
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
defer func() {
os.Args = was[:]
}()
if err := Init(); err != nil {
t.Errorf("failed to init: %v", err)
}
}
func TestFromFile(t *testing.T) {
was := os.Args[:]
os.Args = []string{"program"}
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
defer func() {
os.Args = was[:]
}()
if err := fromFile(); err != nil {
t.Errorf("failed from file: %v", err)
}
}
func TestFromFlags(t *testing.T) {
was := os.Args[:]
os.Args = []string{"program"}
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
defer func() {
os.Args = was[:]
}()
if err := fromFlags(); err != nil {
t.Errorf("failed from flags: %v", err)
}
}

13
example_config.yaml Executable file
View File

@@ -0,0 +1,13 @@
user: ""
pass: ""
port: 51555
r: 100
b: 100
crt: ""
key: ""
tcp: ""
timeout: 1m
proxy2: |
a: http://localhost:41912
b: password:http://localhost:41912
oauth: http://localhost:23456

13
go.mod Normal file
View File

@@ -0,0 +1,13 @@
module gitea.inhome.blapointe.com/local/rproxy3
go 1.18
require (
gitea.inhome.blapointe.com/local/args v0.0.0-20240109214601-658deda479a4
gitea.inhome.blapointe.com/local/logb v0.0.0-20231109150430-1221d87a6dbc
gitea.inhome.blapointe.com/local/oauth2 v0.0.0-20240109220403-8897142866f1
github.com/google/uuid v1.3.0
golang.org/x/time v0.1.0
)
require gopkg.in/yaml.v2 v2.4.0 // indirect

207
go.sum Normal file
View File

@@ -0,0 +1,207 @@
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
gitea.inhome.blapointe.com/local/args v0.0.0-20240109214601-658deda479a4 h1:4qBHjKAiEwRV1A1tN1JK6PsLV1+UwESXKrjGqfCCdNk=
gitea.inhome.blapointe.com/local/args v0.0.0-20240109214601-658deda479a4/go.mod h1:SqCOE3bE3wvrztVIQGHuyxHKfDjRKU9EWhBdkmkiwyc=
gitea.inhome.blapointe.com/local/logb v0.0.0-20231109150430-1221d87a6dbc h1:u3akQkq12V8xWXlcDgjZxIK6hqo6f1eHd9KOxAKMoKc=
gitea.inhome.blapointe.com/local/logb v0.0.0-20231109150430-1221d87a6dbc/go.mod h1:KwilawX4UgD4HxSJAVFEzkuckrnHeQrd49KwUX6GpYU=
gitea.inhome.blapointe.com/local/oauth2 v0.0.0-20240109220403-8897142866f1 h1:GO2/M+5a5i4FqiOnG6hq73nITDv2Rf8oTF973RsYQgo=
gitea.inhome.blapointe.com/local/oauth2 v0.0.0-20240109220403-8897142866f1/go.mod h1:XvS1/YJqCL+HoLo76dSLTjRYR+4Hfg4srhEVhMK3L8E=
gitea.inhome.blapointe.com/local/router v0.0.0-20231109150317-e6b81bf7c23c/go.mod h1:xYz/cn236KTBSWNQ9bqCyBmy8aQ7VL95pDDJmeupmN4=
gitea.inhome.blapointe.com/local/storage v0.0.0-20231109151605-736d446d407d/go.mod h1:TRK5z/XTT6jws++Q21Y8DQot+5vZGTNeHf+RjuY8aQk=
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
github.com/a8m/tree v0.0.0-20180321023834-3cf936ce15d6/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=
github.com/anacrolix/dms v0.0.0-20180117034613-8af4925bffb5/go.mod h1:DGqLjaZ3ziKKNRt+U5Q9PLWJ52Q/4rxfaaH/b3QYKaE=
github.com/aws/aws-sdk-go v1.15.81/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/billziss-gh/cgofuse v1.1.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/coreos/bbolt v0.0.0-20180318001526-af9db2027c98/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/djherbis/times v1.1.0/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8=
github.com/dropbox/dropbox-sdk-go-unofficial v5.4.0+incompatible/go.mod h1:lr+LhMM3F6Y3lW1T9j2U5l7QeuWm87N9+PPXo3yH4qY=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss=
github.com/goftp/server v0.0.0-20190111142836-88de73f463af/go.mod h1:k/SS6VWkxY7dHPhoMQ8IdRu8L4lQtmGbhyXGg+vCnXE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jlaffaye/ftp v0.0.0-20181101112434-47f21d10f0ee/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2/go.mod h1:MLIrzg7gp/kzVBxRE1olT7CWYMCklcUWU+ekoxOD9x0=
github.com/ncw/rclone v1.46.0/go.mod h1:+uFY4HNpat/yXXIEin5ETWXxIwEplC+eDe/vT8vlk1w=
github.com/ncw/swift v1.0.44/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nsf/termbox-go v0.0.0-20181027232701-60ab7e3d12ed/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd/go.mod h1:4soZNh0zW0LtYGdQ416i0jO0EIqMGcbtaspRS4BDvRQ=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pengsrc/go-shared v0.2.0/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sevlyar/go-daemon v0.1.4/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/t3rm1n4l/go-mega v0.0.0-20190205172012-55a226cf41da/go.mod h1:XWL4vDyd3JKmJx+hZWUVgCNmmhZ2dTBcaNDcxH465s0=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yunify/qingstor-sdk-go v2.2.15+incompatible/go.mod h1:w6wqLDQ5bBTzxGJ55581UrSwLrsTAsdo9N6yX/8d9RY=
go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

6
main.go Normal file → Executable file
View File

@@ -1,12 +1,12 @@
package main
import (
"local/rproxy3/config"
"local/rproxy3/server"
"gitea.inhome.blapointe.com/local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/server"
)
func main() {
if err := config.Init(); err != nil {
if err := config.Refresh(); err != nil {
panic(err)
}

14
main_test.go Normal file → Executable file
View File

@@ -34,8 +34,8 @@ func TestHTTPSMain(t *testing.T) {
"username",
"-pass",
"password",
"-r",
"hello:" + addr,
"-proxy",
"hello," + addr,
"-crt",
"./testdata/rproxy3server.crt",
"-key",
@@ -51,7 +51,7 @@ func TestHTTPSMain(t *testing.T) {
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
r, _ := http.NewRequest("GET", "https://hello.localhost"+port, nil)
r, _ := http.NewRequest("GET", "https://hello.localhost:"+port, nil)
if resp, err := client.Do(r); err != nil {
t.Fatalf("client failed: %v", err)
@@ -89,8 +89,8 @@ func TestHTTPMain(t *testing.T) {
"username",
"-pass",
"password",
"-r",
"hello:" + addr,
"-proxy",
"hello," + addr,
}
main()
}()
@@ -98,7 +98,7 @@ func TestHTTPMain(t *testing.T) {
time.Sleep(time.Millisecond * 100)
client := &http.Client{}
r, _ := http.NewRequest("GET", "http://hello.localhost"+port, nil)
r, _ := http.NewRequest("GET", "http://hello.localhost:"+port, nil)
if resp, err := client.Do(r); err != nil {
t.Fatalf("client failed: %v", err)
@@ -127,5 +127,5 @@ func echoServer() (string, func()) {
func getPort() string {
s := httptest.NewServer(nil)
s.Close()
return s.URL[strings.LastIndex(s.URL, ":"):]
return s.URL[strings.LastIndex(s.URL, ":")+1:]
}

9
server/new.go Normal file → Executable file
View File

@@ -1,18 +1,21 @@
package server
import (
"local/rproxy3/config"
"local/rproxy3/storage"
"gitea.inhome.blapointe.com/local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/storage"
"golang.org/x/time/rate"
)
func New() *Server {
port := config.GetPort()
altport := config.GetAltPort()
r, b := config.GetRate()
return &Server{
server := &Server{
db: storage.NewMap(),
addr: port,
altaddr: altport,
limiter: rate.NewLimiter(rate.Limit(r), b),
}
return server
}

0
server/new_test.go Normal file → Executable file
View File

42
server/proxy.go Normal file → Executable file
View File

@@ -2,14 +2,16 @@ package server
import (
"bytes"
"crypto/tls"
"io"
"local/rproxy3/config"
"local/rproxy3/storage/packable"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"gitea.inhome.blapointe.com/local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/storage/packable"
)
type redirPurge struct {
@@ -24,23 +26,21 @@ type rewrite struct {
}
func (s *Server) Proxy(w http.ResponseWriter, r *http.Request) {
newURL, err := s.lookup(mapKey(r, config.GetProxyMode()))
newURL, err := s.lookup(mapKey(r.Host))
r.URL.Path = strings.TrimPrefix(r.URL.Path, config.GetTrim())
var transport http.RoundTripper
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
transport = &redirPurge{
proxyHost: r.Host,
targetHost: newURL.Host,
baseTransport: http.DefaultTransport,
}
transport = &rewrite{
rewrites: config.GetRewrites(mapKey(r, config.GetProxyMode())),
baseTransport: transport,
}
if err != nil {
http.NotFound(w, r)
log.Printf("unknown host lookup %q", r.Host)
return
}
r.Host = newURL.Host
//r.Host = newURL.Host
proxy := httputil.NewSingleHostReverseProxy(newURL)
proxy.Transport = transport
proxy.ServeHTTP(w, r)
@@ -52,20 +52,16 @@ func (s *Server) lookup(host string) (*url.URL, error) {
return v.URL(), err
}
func mapKey(r *http.Request, proxyMode string) string {
switch proxyMode {
case "domain":
host := strings.Split(r.Host, ".")[0]
host = strings.Split(host, ":")[0]
return host
case "path":
paths := strings.Split(r.URL.Path, "/")
if len(paths) < 2 {
return ""
}
return paths[1]
}
return ""
func (s *Server) lookupAuth(host string) (string, error) {
v := packable.NewString()
err := s.db.Get(nsRouting, host+"//auth", v)
return v.String(), err
}
func mapKey(host string) string {
host = strings.Split(host, ".")[0]
host = strings.Split(host, ":")[0]
return host
}
func (rp *redirPurge) RoundTrip(r *http.Request) (*http.Response, error) {
@@ -76,6 +72,8 @@ func (rp *redirPurge) RoundTrip(r *http.Request) (*http.Response, error) {
if loc := resp.Header.Get("Location"); loc != "" {
resp.Header.Set("Location", strings.Replace(loc, rp.targetHost, rp.proxyHost, 1))
}
// google floc https://paramdeo.com/blog/opting-your-website-out-of-googles-floc-network
resp.Header.Set("Permissions-Policy", "interest-cohort=()")
return resp, err
}

33
server/proxy_test.go Normal file → Executable file
View File

@@ -3,7 +3,6 @@ package server
import (
"io/ioutil"
"net/http"
"net/url"
"strings"
"testing"
)
@@ -41,35 +40,3 @@ func TestRewrite(t *testing.T) {
t.Errorf("failed to replace: got %q, want \"b\"", b)
}
}
func TestMapKey(t *testing.T) {
r := &http.Request{
Host: "a.b.c:123",
URL: &url.URL{
Path: "/c/d/e",
},
}
if v := mapKey(r, "domain"); v != "a" {
t.Errorf("failed to get domain: got %v", v)
}
if v := mapKey(r, "path"); v != "c" {
t.Errorf("failed to get domain: got %v", v)
}
r.Host = "a:123"
if v := mapKey(r, "domain"); v != "a" {
t.Errorf("failed to get domain: got %v", v)
}
r.URL.Path = ""
if v := mapKey(r, "path"); v != "" {
t.Errorf("failed to get domain: got %v", v)
}
r.URL.Path = "/"
if v := mapKey(r, "path"); v != "" {
t.Errorf("failed to get domain: got %v", v)
}
}

2
server/routes.go Normal file → Executable file
View File

@@ -1,7 +1,7 @@
package server
import (
"local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/config"
)
func (s *Server) Routes() error {

0
server/routes_test.go Normal file → Executable file
View File

202
server/server.go Normal file → Executable file
View File

@@ -4,16 +4,23 @@ import (
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"local/rproxy3/config"
"local/rproxy3/storage"
"local/rproxy3/storage/packable"
"fmt"
"io"
"log"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"gitea.inhome.blapointe.com/local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/storage"
"gitea.inhome.blapointe.com/local/rproxy3/storage/packable"
"github.com/google/uuid"
"golang.org/x/time/rate"
)
@@ -24,6 +31,7 @@ type listenerScheme int
const (
schemeHTTP listenerScheme = iota
schemeHTTPS listenerScheme = iota
schemeTCP listenerScheme = iota
)
func (ls listenerScheme) String() string {
@@ -32,6 +40,8 @@ func (ls listenerScheme) String() string {
return "http"
case schemeHTTPS:
return "https"
case schemeTCP:
return "tcp"
}
return ""
}
@@ -39,32 +49,33 @@ func (ls listenerScheme) String() string {
type Server struct {
db storage.DB
addr string
altaddr string
username string
password string
limiter *rate.Limiter
}
func (s *Server) Route(src, dst string) error {
log.Printf("Adding route %q -> %q...\n", src, dst)
u, err := url.Parse(dst)
func (s *Server) Route(src string, dst config.Proxy) error {
src = strings.TrimPrefix(src, "+")
log.Printf("Adding route %q -> %v...\n", src, dst)
u, err := url.Parse(dst.To)
if err != nil {
return err
}
if err := s.db.Set(nsRouting, src+"//auth", packable.NewString(dst.Auth)); err != nil {
return err
}
return s.db.Set(nsRouting, src, packable.NewURL(u))
}
func (s *Server) Run() error {
scheme := schemeHTTP
if _, _, ok := config.GetSSL(); ok {
scheme = schemeHTTPS
}
go s.alt()
scheme := getScheme()
log.Printf("Listening for %v on %v...\n", scheme, s.addr)
switch scheme {
case schemeHTTP:
log.Printf("Serve http")
return http.ListenAndServe(s.addr, s)
case schemeHTTPS:
log.Printf("Serve https")
c, k, _ := config.GetSSL()
httpsServer := &http.Server{
Addr: s.addr,
@@ -83,42 +94,147 @@ func (s *Server) Run() error {
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
}
return httpsServer.ListenAndServeTLS(c, k)
case schemeTCP:
addr, _ := config.GetTCP()
return s.ServeTCP(addr)
}
return errors.New("did not load server")
}
func (s *Server) doAuth(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
rusr, rpwd, ok := config.GetAuth()
if ok {
//usr, pwd := getProxyAuth(r)
usr, pwd, ok := r.BasicAuth()
if !ok || rusr != usr || rpwd != pwd {
w.WriteHeader(http.StatusUnauthorized)
log.Printf("denying proxy basic auth")
func (s *Server) ServeTCP(addr string) error {
listen, err := net.Listen("tcp", s.addr)
if err != nil {
return err
}
for {
c, err := listen.Accept()
if err != nil {
return err
}
go func(c net.Conn) {
d, err := net.Dial("tcp", addr)
if err != nil {
log.Println(err)
return
}
}
foo(w, r)
go pipe(c, d)
go pipe(d, c)
}(c)
}
}
func pipe(a, b net.Conn) {
log.Println("open pipe")
defer log.Println("close pipe")
defer a.Close()
defer b.Close()
io.Copy(a, b)
}
func (s *Server) Pre(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx, can := context.WithTimeout(r.Context(), time.Second*time.Duration(config.GetTimeout()))
r, flush := withMeta(w, r)
defer flush()
ctx, can := context.WithTimeout(r.Context(), time.Duration(config.GetTimeout()))
defer can()
if err := s.limiter.Wait(ctx); err != nil {
pushMeta(r, "explain", "limiter exceeded")
w.WriteHeader(http.StatusTooManyRequests)
return
}
s.doAuth(foo)(w, r)
w, did := doCORS(w, r)
if did {
pushMeta(r, "explain", "did cors")
return
}
if auth, err := s.lookupAuth(mapKey(r.Host)); err != nil {
log.Printf("failed to lookup auth for %s (%s): %v", r.Host, mapKey(r.Host), err)
w.Header().Set("WWW-Authenticate", "Basic")
http.Error(w, err.Error(), http.StatusUnauthorized)
} else if _, p, _ := r.BasicAuth(); auth != p {
log.Printf("failed to auth: expected %q but got %q", auth, p)
w.Header().Set("WWW-Authenticate", "Basic")
http.Error(w, "unexpected basic auth", http.StatusUnauthorized)
} else {
foo(w, r)
}
}
}
func withMeta(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
meta := map[string]string{
"ts": strconv.FormatInt(time.Now().Unix(), 10),
"method": r.Method,
"url": r.URL.String(),
"id": uuid.New().String(),
}
w.Header().Set("meta-id", meta["id"])
ctx := r.Context()
ctx = context.WithValue(ctx, "meta", meta)
r = r.WithContext(ctx)
return r, func() {
b, err := json.Marshal(meta)
if err != nil {
panic(err)
}
fmt.Printf("[access] %s\n", b)
}
}
func pushMeta(r *http.Request, k, v string) {
got := r.Context().Value("meta")
if got == nil {
return
}
meta, ok := got.(map[string]string)
if !ok || meta == nil {
return
}
meta[k] = v
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.Pre(s.Proxy)(w, r)
}
type corsResponseWriter struct {
r *http.Request
http.ResponseWriter
}
func (cb corsResponseWriter) WriteHeader(code int) {
cb.Header().Set("Access-Control-Allow-Origin", "*")
cb.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token, content-type, Content-Type")
cb.ResponseWriter.WriteHeader(code)
pushMeta(cb.r, "cors", "wrote headers")
}
func doCORS(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, bool) {
key := mapKey(r.Host)
if !config.GetCORS(key) {
return w, false
}
pushMeta(r, "do-cors", "enabled for key")
return _doCORS(w, r)
}
func _doCORS(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, bool) {
w2 := corsResponseWriter{r: r, ResponseWriter: w}
if r.Method != http.MethodOptions {
pushMeta(r, "-do-cors", "not options")
return w2, false
}
pushMeta(r, "-do-cors", "options")
w2.Header().Set("Content-Length", "0")
w2.Header().Set("Content-Type", "text/plain")
w2.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE")
w2.WriteHeader(http.StatusOK)
return w2, true
}
func getProxyAuth(r *http.Request) (string, string) {
proxyAuthHeader := r.Header.Get("Proxy-Authorization")
proxyAuthB64 := strings.TrimPrefix(proxyAuthHeader, "Basic ")
@@ -130,3 +246,39 @@ func getProxyAuth(r *http.Request) (string, string) {
proxyAuthSplit := strings.Split(proxyAuth, ":")
return proxyAuthSplit[0], proxyAuthSplit[1]
}
func (s *Server) alt() {
switch getScheme() {
case schemeHTTP:
case schemeHTTPS:
default:
return
}
foo := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.URL.Scheme = getScheme().String()
if hostname := r.URL.Hostname(); hostname != "" {
r.URL.Host = r.URL.Hostname() + s.addr
} else if hostname := r.URL.Host; hostname != "" {
r.URL.Host = r.URL.Host + s.addr
} else {
u := url.URL{Host: r.Host}
r.URL.Host = u.Hostname() + s.addr
}
http.Redirect(w, r, r.URL.String(), http.StatusSeeOther)
})
log.Println("redirecting from", s.altaddr)
if err := http.ListenAndServe(s.altaddr, foo); err != nil {
panic(err)
}
}
func getScheme() listenerScheme {
scheme := schemeHTTP
if _, _, ok := config.GetSSL(); ok {
scheme = schemeHTTPS
}
if _, ok := config.GetTCP(); ok {
scheme = schemeTCP
}
return scheme
}

52
server/server_test.go Normal file → Executable file
View File

@@ -3,19 +3,25 @@ package server
import (
"context"
"fmt"
"local/rproxy3/storage"
"net/http"
"net/http/httptest"
"strings"
"testing"
"gitea.inhome.blapointe.com/local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/storage"
"golang.org/x/time/rate"
)
func TestServerStart(t *testing.T) {
return // depends on etc hosts
server := mockServer()
if err := server.Route("world", "http://hello.localhost"+server.addr); err != nil {
p := config.Proxy{
To: "http://hello.localhost" + server.addr,
}
if err := server.Route("world", p); err != nil {
t.Fatalf("cannot add route: %v", err)
}
@@ -48,7 +54,10 @@ func mockServer() *Server {
func TestServerRoute(t *testing.T) {
server := mockServer()
if err := server.Route("world", "http://hello.localhost"+server.addr); err != nil {
p := config.Proxy{
To: "http://hello.localhost" + server.addr,
}
if err := server.Route("world", p); err != nil {
t.Fatalf("cannot add route: %v", err)
}
w := httptest.NewRecorder()
@@ -59,3 +68,40 @@ func TestServerRoute(t *testing.T) {
t.Fatalf("cannot proxy from 'world' to 'hello', status %v", w.Code)
}
}
func TestCORS(t *testing.T) {
t.Run(http.MethodOptions, func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodOptions, "/", nil)
w2, did := _doCORS(w, r)
w2.WriteHeader(300)
if !did {
t.Error("didnt do on options")
}
if w.Header().Get("Access-Control-Allow-Origin") != "*" {
t.Error("didnt set origina")
}
if w.Header().Get("Access-Control-Allow-Methods") != "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE" {
t.Error("didnt set allow methods")
}
})
t.Run(http.MethodGet, func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/", nil)
w2, did := _doCORS(w, r)
w2.Header().Set("a", "b")
w2.Header().Set("Access-Control-Allow-Origin", "NO")
w2.WriteHeader(300)
if did {
t.Error("did cors on options")
}
if w.Header().Get("Access-Control-Allow-Origin") != "*" {
t.Error("didnt set origina")
} else if len(w.Header()["Access-Control-Allow-Origin"]) != 1 {
t.Error(w.Header())
}
if w.Header().Get("Access-Control-Allow-Methods") != "" {
t.Error("did set allow methods")
}
})
}

2
storage/db.go Normal file → Executable file
View File

@@ -2,7 +2,7 @@ package storage
import (
"errors"
"local/rproxy3/storage/packable"
"gitea.inhome.blapointe.com/local/rproxy3/storage/packable"
)
var ErrNotFound = errors.New("not found")

2
storage/db_test.go Normal file → Executable file
View File

@@ -1,7 +1,7 @@
package storage
import (
"local/rproxy3/storage/packable"
"gitea.inhome.blapointe.com/local/rproxy3/storage/packable"
"os"
"testing"
)

2
storage/map.go Normal file → Executable file
View File

@@ -2,7 +2,7 @@ package storage
import (
"fmt"
"local/rproxy3/storage/packable"
"gitea.inhome.blapointe.com/local/rproxy3/storage/packable"
)
type Map map[string]map[string][]byte

0
storage/packable/packable.go Normal file → Executable file
View File

0
storage/packable/packable_test.go Normal file → Executable file
View File

0
testdata/Bserver.crt vendored Normal file → Executable file
View File

0
testdata/Bserver.key vendored Normal file → Executable file
View File

0
testdata/Bserver.pkcs12 vendored Normal file → Executable file
View File

36
testdata/index.html vendored Executable file
View File

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Go WebSocket Tutorial</title>
</head>
<body>
<h2>Hello World</h2>
<script>
let socket = new WebSocket("ws://a.bel.test:51555/ws");
document.getElementsByTagName("body")[0].innerHTML += "<br>connecting";
socket.onopen = () => {
document.getElementsByTagName("body")[0].innerHTML += "<br>connected";
socket.send("Hi From the Client!")
};
socket.onclose = event => {
document.getElementsByTagName("body")[0].innerHTML += "<br>disconnected";
socket.send("Client Closed!")
};
socket.onerror = error => {
document.getElementsByTagName("body")[0].innerHTML += "<br>error:" + error;
console.log("Socket Error: ", error);
};
socket.onmessage = function(msgevent) {
document.getElementsByTagName("body")[0].innerHTML += "<br>got:" + msgevent.data;
};
</script>
</body>
</html>

0
testdata/rproxy3server.crt vendored Normal file → Executable file
View File

0
testdata/rproxy3server.key vendored Normal file → Executable file
View File

0
testdata/rproxy3server.pkcs12 vendored Normal file → Executable file
View File

76
testdata/ws.go vendored Executable file
View File

@@ -0,0 +1,76 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
func homePage(w http.ResponseWriter, r *http.Request) {
b, _ := ioutil.ReadFile("./index.html")
fmt.Fprintf(w, "%s", b)
}
func setupRoutes() {
http.HandleFunc("/", homePage)
http.HandleFunc("/ws", wsEndpoint)
}
func main() {
fmt.Println("Hello World")
setupRoutes()
log.Fatal(http.ListenAndServe(":8080", nil))
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func reader(conn *websocket.Conn) {
for {
// read in a message
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
}
// print out that message for clarity
fmt.Println(string(p))
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println(err)
return
}
}
}
func wsEndpoint(w http.ResponseWriter, r *http.Request) {
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
// upgrade this connection to a WebSocket
// connection
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
}
log.Println("Client Connected")
// listen indefinitely for new messages coming
// through on our WebSocket connection
go reader(ws)
for {
log.Println("writing...")
err = ws.WriteMessage(1, []byte("Hi Client!"))
log.Println("written")
if err != nil {
log.Println(err)
return
}
time.Sleep(time.Second)
}
}

25
vendor/vendor.json vendored
View File

@@ -1,25 +0,0 @@
{
"comment": "",
"ignore": "test",
"package": [
{
"checksumSHA1": "GtamqiJoL7PGHsN454AoffBFMa8=",
"path": "golang.org/x/net/context",
"revision": "65e2d4e15006aab9813ff8769e768bbf4bb667a0",
"revisionTime": "2019-02-01T23:59:58Z"
},
{
"checksumSHA1": "HoCvrd3hEhsFeBOdEw7cbcfyk50=",
"path": "golang.org/x/time/rate",
"revision": "fbb02b2291d28baffd63558aa44b4b56f178d650",
"revisionTime": "2018-04-12T16:56:04Z"
},
{
"checksumSHA1": "QqDq2x8XOU7IoOR98Cx1eiV5QY8=",
"path": "gopkg.in/yaml.v2",
"revision": "51d6538a90f86fe93ac480b35f37b2be17fef232",
"revisionTime": "2018-11-15T11:05:04Z"
}
],
"rootPath": "local/rproxy3"
}